Mercurial > hg > dhcpcd
comparison src/dhcpcd.c @ 5557:e65d193a1960 draft
Linux: Support wireless IP roaming
This is achieved by checking that the interface is wireless,
IFF_UP and IFF_LOWER_UP are present, but IFF_RUNNING is missing.
This gives exactly the same support as modern NetBSD when carrier
loss is detected, but without the address verifications when the
carrier comes back as that needs to be handled in the kernel.
While IP setup is maintained, other configuration data is discarded.
Note that this should be improved in the future.
Thanks to Boris Krasnovskiy <borkra@gmail.com> for helping with this.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Sat, 12 Dec 2020 13:12:26 +0000 |
| parents | 66dc60bf133d |
| children | e27177daaf0a |
comparison
equal
deleted
inserted
replaced
| 5556:99bfd2eb77ab | 5557:e65d193a1960 |
|---|---|
| 693 } | 693 } |
| 694 | 694 |
| 695 loginfox("%s: connected to Access Point: %s", ifp->name, pssid); | 695 loginfox("%s: connected to Access Point: %s", ifp->name, pssid); |
| 696 } | 696 } |
| 697 | 697 |
| 698 static void | |
| 699 dhcpcd_nocarrier_roaming(struct interface *ifp) | |
| 700 { | |
| 701 | |
| 702 loginfox("%s: carrier lost - roaming", ifp->name); | |
| 703 | |
| 704 /* | |
| 705 * XXX We should pass something like NOCARRIER_ROAMING | |
| 706 * and set if_up=true; ifdown=false; so that the hook scripts | |
| 707 * can make a decision to keep or discard the interface information. | |
| 708 * | |
| 709 * Currently they discard it (no carrier after all) which is | |
| 710 * generally fine as new connections won't work and current | |
| 711 * connections try to chug along as best as. | |
| 712 * dhcpcd has been doing this since NetBSD-7 at least. | |
| 713 * | |
| 714 * However, for slow roaming this is poor for say web browsing | |
| 715 * as new lookups will fail quickly giving a poor user experience. | |
| 716 * We should improve this, but the hooks will require some work first | |
| 717 * as we need to introduce a mechanism to sort interfaces by | |
| 718 * carrier > roaming > nocarrier. Then the hooks know in which | |
| 719 * order to apply their data, if at all. | |
| 720 * This probably should be a user toggle. | |
| 721 */ | |
| 722 script_runreason(ifp, "NOCARRIER"); | |
| 723 | |
| 724 #ifdef ARP | |
| 725 arp_drop(ifp); | |
| 726 #endif | |
| 727 #ifdef INET | |
| 728 dhcp_abort(ifp); | |
| 729 #endif | |
| 730 #ifdef DHCP6 | |
| 731 dhcp6_abort(ifp); | |
| 732 #endif | |
| 733 } | |
| 734 | |
| 698 void | 735 void |
| 699 dhcpcd_handlecarrier(struct interface *ifp, int carrier, unsigned int flags) | 736 dhcpcd_handlecarrier(struct interface *ifp, int carrier, unsigned int flags) |
| 700 { | 737 { |
| 701 bool was_link_up = if_is_link_up(ifp); | 738 bool was_link_up = if_is_link_up(ifp); |
| 739 bool was_roaming = if_roaming(ifp); | |
| 702 | 740 |
| 703 ifp->carrier = carrier; | 741 ifp->carrier = carrier; |
| 704 ifp->flags = flags; | 742 ifp->flags = flags; |
| 705 | 743 |
| 706 if (!if_is_link_up(ifp)) { | 744 if (!if_is_link_up(ifp)) { |
| 707 if (!was_link_up || !ifp->active) | 745 if (!ifp->active || (!was_link_up && !was_roaming)) |
| 708 return; | 746 return; |
| 709 loginfox("%s: carrier lost", ifp->name); | 747 |
| 710 script_runreason(ifp, "NOCARRIER"); | 748 /* |
| 749 * If the interface is roaming (generally on wireless) | |
| 750 * then while we are not up, we are not down either. | |
| 751 * Preserve the network state until we either disconnect | |
| 752 * or re-connect. | |
| 753 */ | |
| 754 if (if_roaming(ifp)) { | |
| 755 dhcpcd_nocarrier_roaming(ifp); | |
| 756 return; | |
| 757 } | |
| 758 | |
| 711 #ifdef NOCARRIER_PRESERVE_IP | 759 #ifdef NOCARRIER_PRESERVE_IP |
| 712 if (ifp->flags & IFF_UP && | 760 if (ifp->flags & IFF_UP && |
| 713 !(ifp->options->options & DHCPCD_ANONYMOUS)) | 761 !(ifp->options->options & DHCPCD_ANONYMOUS)) |
| 714 { | 762 { |
| 715 #ifdef ARP | 763 /* This OS supports the roaming concept on any |
| 716 arp_drop(ifp); | 764 * interface. */ |
| 717 #endif | 765 dhcpcd_nocarrier_roaming(ifp); |
| 718 #ifdef INET | 766 return; |
| 719 dhcp_abort(ifp); | 767 } |
| 720 #endif | 768 #endif |
| 721 #ifdef DHCP6 | 769 |
| 722 dhcp6_abort(ifp); | 770 loginfox("%s: carrier lost", ifp->name); |
| 723 #endif | 771 script_runreason(ifp, "NOCARRIER"); |
| 724 } else | 772 dhcpcd_drop(ifp, 0); |
| 725 #endif | 773 |
| 726 dhcpcd_drop(ifp, 0); | |
| 727 if (ifp->options->options & DHCPCD_ANONYMOUS) { | 774 if (ifp->options->options & DHCPCD_ANONYMOUS) { |
| 728 bool is_up = ifp->flags & IFF_UP; | 775 bool is_up = ifp->flags & IFF_UP; |
| 729 | 776 |
| 730 if (is_up) | 777 if (is_up) |
| 731 if_down(ifp); | 778 if_down(ifp); |
| 732 if (if_randomisemac(ifp) == -1 && errno != ENXIO) | 779 if (if_randomisemac(ifp) == -1 && errno != ENXIO) |
| 733 logerr(__func__); | 780 logerr(__func__); |
| 734 if (is_up) | 781 if (is_up) |
| 735 if_up(ifp); | 782 if_up(ifp); |
| 736 } | 783 } |
| 784 | |
| 737 return; | 785 return; |
| 738 } | 786 } |
| 739 | 787 |
| 740 /* | 788 /* |
| 741 * At this point carrier is NOT DOWN and we have IFF_UP. | 789 * At this point carrier is NOT DOWN and we have IFF_UP. |
| 772 /* If we changed SSID network, drop leases */ | 820 /* If we changed SSID network, drop leases */ |
| 773 if ((ifp->ssid_len != olen || | 821 if ((ifp->ssid_len != olen || |
| 774 memcmp(ifp->ssid, ossid, ifp->ssid_len)) && ifp->active) | 822 memcmp(ifp->ssid, ossid, ifp->ssid_len)) && ifp->active) |
| 775 { | 823 { |
| 776 dhcpcd_reportssid(ifp); | 824 dhcpcd_reportssid(ifp); |
| 777 #ifdef NOCARRIER_PRESERVE_IP | |
| 778 dhcpcd_drop(ifp, 0); | 825 dhcpcd_drop(ifp, 0); |
| 779 #endif | |
| 780 #ifdef IPV4LL | 826 #ifdef IPV4LL |
| 781 ipv4ll_reset(ifp); | 827 ipv4ll_reset(ifp); |
| 782 #endif | 828 #endif |
| 783 } | 829 } |
| 784 } | 830 } |
| 786 if (!ifp->active) | 832 if (!ifp->active) |
| 787 return; | 833 return; |
| 788 | 834 |
| 789 dhcpcd_initstate(ifp, 0); | 835 dhcpcd_initstate(ifp, 0); |
| 790 script_runreason(ifp, "CARRIER"); | 836 script_runreason(ifp, "CARRIER"); |
| 837 | |
| 791 #ifdef INET6 | 838 #ifdef INET6 |
| 792 #ifdef NOCARRIER_PRESERVE_IP | |
| 793 /* Set any IPv6 Routers we remembered to expire faster than they | 839 /* Set any IPv6 Routers we remembered to expire faster than they |
| 794 * would normally as we maybe on a new network. */ | 840 * would normally as we maybe on a new network. */ |
| 795 ipv6nd_startexpire(ifp); | 841 ipv6nd_startexpire(ifp); |
| 796 #endif | |
| 797 #ifdef IPV6_MANAGETEMPADDR | 842 #ifdef IPV6_MANAGETEMPADDR |
| 798 /* RFC4941 Section 3.5 */ | 843 /* RFC4941 Section 3.5 */ |
| 799 ipv6_regentempaddrs(ifp); | 844 ipv6_regentempaddrs(ifp); |
| 800 #endif | 845 #endif |
| 801 #endif | 846 #endif |
| 847 | |
| 802 dhcpcd_startinterface(ifp); | 848 dhcpcd_startinterface(ifp); |
| 803 } | 849 } |
| 804 | 850 |
| 805 static void | 851 static void |
| 806 warn_iaid_conflict(struct interface *ifp, uint16_t ia_type, uint8_t *iaid) | 852 warn_iaid_conflict(struct interface *ifp, uint16_t ia_type, uint8_t *iaid) |
