diff options
Diffstat (limited to 'sys/net80211/ieee80211_input.c')
-rw-r--r-- | sys/net80211/ieee80211_input.c | 105 |
1 files changed, 104 insertions, 1 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 5ddfa6ed618..0d2ff372cdb 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -1,5 +1,5 @@ /* $NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung Exp $ */ -/* $OpenBSD: ieee80211_input.c,v 1.1 2004/06/22 22:53:52 millert Exp $ */ +/* $OpenBSD: ieee80211_input.c,v 1.2 2004/11/02 02:15:49 reyk Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe @@ -60,6 +60,7 @@ __KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung #endif #include <sys/proc.h> #include <sys/sysctl.h> +#include <sys/endian.h> #ifdef __FreeBSD__ #include <machine/atomic.h> @@ -96,8 +97,14 @@ __KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung #include <dev/rndvar.h> #endif +const struct timeval ieee80211_merge_print_intvl = { + .tv_sec = 1, + .tv_usec = 0 +}; + static void ieee80211_recv_pspoll(struct ieee80211com *, struct mbuf *, int, u_int32_t); +static int ieee80211_do_slow_print(struct ieee80211com *, int *); /* * Process a received frame. The node associated with the sender @@ -1603,5 +1610,101 @@ ieee80211_recv_pspoll(struct ieee80211com *ic, struct mbuf *m0, int rssi, IF_ENQUEUE(&ic->ic_pwrsaveq, m); (*ifp->if_start)(ifp); } + +static int +ieee80211_do_slow_print(struct ieee80211com *ic, int *did_print) +{ + if ((ic->ic_if.if_flags & IFF_LINK0) == 0) + return 0; + if (!*did_print && (ic->ic_if.if_flags & IFF_DEBUG) == 0 && + !ratecheck(&ic->ic_last_merge_print, &ieee80211_merge_print_intvl)) + return 0; + + *did_print = 1; + return 1; +} + +/* ieee80211_ibss_merge helps merge 802.11 ad hoc networks. The + * convention, set by the Wireless Ethernet Compatibility Alliance + * (WECA), is that an 802.11 station will change its BSSID to match + * the "oldest" 802.11 ad hoc network, on the same channel, that + * has the station's desired SSID. The "oldest" 802.11 network + * sends beacons with the greatest TSF timestamp. + * + * Return ENETRESET if the BSSID changed, 0 otherwise. + * + * XXX Perhaps we should compensate for the time that elapses + * between the MAC receiving the beacon and the host processing it + * in ieee80211_ibss_merge. + */ +int +ieee80211_ibss_merge(struct ieee80211com *ic, struct ieee80211_node *ni, + uint64_t local_tsft) +{ + uint64_t beacon_tsft; + int did_print = 0, sign; + union { + uint64_t word; + uint8_t tstamp[8]; + } u; + + /* ensure alignment */ + (void)memcpy(&u, &ni->ni_tstamp[0], sizeof(u)); + beacon_tsft = letoh64(u.word); + + /* we are faster, let the other guy catch up */ + if (beacon_tsft < local_tsft) + sign = -1; + else + sign = 1; + + if (memcmp(ni->ni_bssid, ic->ic_bss->ni_bssid, + IEEE80211_ADDR_LEN) == 0) { + if (!ieee80211_do_slow_print(ic, &did_print)) + return 0; + printf("%s: tsft offset %s%ull\n", ic->ic_if.if_xname, + (sign < 0) ? "-" : "", + (sign < 0) + ? (local_tsft - beacon_tsft) + : (beacon_tsft - local_tsft)); + return 0; + } + + if (sign < 0) + return 0; + + if (ieee80211_match_bss(ic, ni) != 0) + return 0; + + if (ieee80211_do_slow_print(ic, &did_print)) { + printf("%s: ieee80211_ibss_merge: bssid mismatch %s\n", + ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid)); + } + + ic->ic_flags &= ~IEEE80211_F_SIBSS; + + /* negotiate rates with new IBSS */ + ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE | + IEEE80211_F_DONEGO | IEEE80211_F_DODEL); + if (ni->ni_rates.rs_nrates == 0) { + if (ieee80211_do_slow_print(ic, &did_print)) { + printf("%s: rates mismatch, BSSID %s\n", + ic->ic_if.if_xname, ether_sprintf(ni->ni_bssid)); + } + return 0; + } + + if (ieee80211_do_slow_print(ic, &did_print)) { + printf("%s: sync BSSID %s -> ", + ic->ic_if.if_xname, ether_sprintf(ic->ic_bss->ni_bssid)); + printf("%s ", ether_sprintf(ni->ni_bssid)); + printf("(from %s)\n", ether_sprintf(ni->ni_macaddr)); + } + + ieee80211_node_newstate(ni, IEEE80211_STA_BSS); + (*ic->ic_node_copy)(ic, ic->ic_bss, ni); + + return ENETRESET; +} #undef IEEE80211_VERIFY_LENGTH #undef IEEE80211_VERIFY_ELEMENT |