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)