📄 if_wlp_wavelan_roam.c
字号:
/* * Copyright (c) 1997 Carnegie Mellon University. All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted (including for commercial or for-profit * use), provided that both the copyright notice and this permission notice * appear in all copies of the software, derivative works, or modified * versions, and any portions thereof, and that both notices appear in * supporting documentation, and that credit is given to Carnegie Mellon * University in all publications reporting on direct or indirect use of this * code or its derivatives. * * THIS IMPLEMENTATION IS EXPERIMENTAL AND MAY HAVE BUGS, SOME OF WHICH MAY HAVE * SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS SOFTWARE IN ITS "AS * IS" CONDITION, AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON * UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Carnegie Mellon encourages (but does not require) users of this software to * return any improvements or extensions that they make, and to grant * Carnegie Mellon the rights to redistribute these changes without * encumbrance. * * */#ifdef WAVELAN_ROAMING#include "card.h"#if NCARD > 0#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/conf.h>#include <sys/errno.h>#include <sys/ioctl.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/syslog.h>#include <sys/time.h>#include <net/if.h>#include <net/if_dl.h>#include <net/if_types.h>#ifdef INET#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#include <netinet/if_ether.h>#endif#include <i386/isa/ic/i82593.h>#include <i386/isa/if_wlp_wavelan.h>#include <i386/isa/if_wlp.h>#include <i386/isa/if_wlp_wavelan_roam.h>/* * ====================================================================== * Local WaveLAN Routines * ====================================================================== */static voidRoamReset(struct wlp_softc *);static voidSetDOMID(struct wlp_softc*, int val); static voidroam_timer(void *);static voidPurgeAccessPointList(struct wlp_softc *);static struct accesspoint *BestAccessPoint1(struct wlp_softc *);static struct accesspoint *BestAccessPoint2(struct accesspoint *, struct accesspoint *);static voidProcessBeacon(struct ether_header *, struct mbuf *, int);static voidProcessSORsp(struct ether_header *, struct mbuf *);static voidSendSOReq(struct wlp_softc *, struct accesspoint *);static voidSendRECReq(struct wlp_softc *);#ifdef WLP_DEBUGstatic void dump_aplist(struct wlp_softc *);static void dump_ap(struct accesspoint *);#endif /* WLP_DEBUG *//* * ====================================================================== * External (non-static) WaveLAN Routines * ====================================================================== */intwavelan_roaming_ioctl(ifp, cmd, data) struct ifnet *ifp; int cmd; caddr_t data;{ struct wlp_softc *sc = (struct wlp_softc *) ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; int error = 0; switch (cmd) { case SIOCSIFNWID: if (sc->sc_rs.rs_roam_enable == ROAM_OFF) SetNWID(sc, (int) ifr->ifr_data ^ sc->sc_rs.rs_beaconkey, 0); else error = EPERM; break; case SIOCGIFNWID: (int) ifr->ifr_data = (sc->sc_nwid[0] << 8 | sc->sc_nwid[1]) ^ sc->sc_rs.rs_beaconkey; break; case SIOCSIFROAM: if (sc->sc_rs.rs_roam_enable == (int) ifr->ifr_data) { error = EALREADY; break; } if ((int) ifr->ifr_data != ROAM_ON && (int) ifr->ifr_data != ROAM_OFF) { error = EINVAL; break; } RoamOnOff(sc, (int) ifr->ifr_data); wlpinit(sc); break; case SIOCGIFROAM: (int) ifr->ifr_data = sc->sc_rs.rs_roam_enable; break; case SIOCSIFDOMID: if (sc->sc_rs.rs_roam_enable == ROAM_ON) SetDOMID(sc, (int) ifr->ifr_data); else error = EPERM; break; case SIOCGIFDOMID: (int) ifr->ifr_data = sc->sc_rs.rs_domid; break; case SIOCGIFSIGNAL: if (sc->sc_rs.rs_roam_enable == ROAM_ON && sc->sc_rs.rs_ap) { (int) ifr->ifr_data = (sc->sc_rs.rs_ap->ap_siglevel << SIGL_SHIFT) + (sc->sc_rs.rs_ap->ap_sillevel << SILL_SHIFT) + (sc->sc_rs.rs_ap->ap_sigqual << SIGQ_SHIFT); } else error = EPERM; break; case SIOCSIFBEACONKEY: sc->sc_rs.rs_beaconkey = htons((int) ifr->ifr_data); break; case SIOCGIFBEACONKEY: (int) ifr->ifr_data = ntohs(sc->sc_rs.rs_beaconkey); break; case SIOCGIFTHRESH: if (sc->sc_rs.rs_roam_enable == ROAM_ON && sc->sc_rs.rs_ap) (int) ifr->ifr_data = (STOP_CELL(sc->sc_rs.rs_ap) << STOPC_SHIFT) + (REG_CELL(sc->sc_rs.rs_ap) << REGC_SHIFT) + (FAST_CELL(sc->sc_rs.rs_ap) << FASTC_SHIFT); else error = EPERM; break; default: error = EINVAL; } return error;}voidwavelan_input(eh, m, sigstat) struct ether_header *eh; struct mbuf *m; int sigstat;{ caddr_t p = mtod(m, caddr_t); switch (*p) { case PDUTYPE_BEACON: if (m->m_len >= BEACON_MIN_LEN) ProcessBeacon(eh, m, sigstat); break; case PDUTYPE_SOREQ: /* we will never get these */ break; case PDUTYPE_SORSP: if (m->m_len >= SORSP_MIN_LEN) ProcessSORsp(eh, m); break; }}voidRoamOnOff(sc, status) struct wlp_softc *sc; int status;{ struct ifreq ifr; struct sockaddr *sa = &ifr.ifr_addr; RoamReset(sc); if (status == ROAM_OFF) { untimeout(roam_timer, (void *) sc); } bzero(&ifr, sizeof(ifr)); bcopy(sc->sc_ac.ac_if.if_name, ifr.ifr_name, sizeof(ifr.ifr_name)); sa->sa_family = AF_UNSPEC; sa->sa_len = sizeof(*sa); bcopy(ether_beacon_multiaddr, sa->sa_data, sizeof(ether_beacon_multiaddr)); if (status == ROAM_OFF) ether_delmulti(&ifr, &sc->sc_ac); else ether_addmulti(&ifr, &sc->sc_ac); wlpsetrcr(sc); if (status == ROAM_ON) { timeout(roam_timer, (void *) sc, hz * 2); } sc->sc_rs.rs_roam_enable = status;#ifdef WLP_DEBUG printf("%s(): roaming status is %s\n", __FUNCTION__, status == ROAM_ON ? "ON" : "OFF");#endif}/* * ====================================================================== * Management Functions * ====================================================================== */static voidRoamReset(sc) struct wlp_softc *sc;{ struct accesspoint *a; if (sc->sc_rs.rs_roam_enable == ROAM_ON) { /* Clean up the AP list */ for (a = sc->sc_rs.rs_aplist.lh_first; a; ) { struct accesspoint *an = a->ap_link.le_next; LIST_REMOVE(a, ap_link); free(a, M_TEMP); a = an; } } LIST_INIT(&sc->sc_rs.rs_aplist); sc->sc_rs.rs_ap = 0; sc->sc_rs.rs_apreg = 0; sc->sc_rs.rs_SOReqCnt = 0; sc->sc_rs.rs_SOReqRetrans = 0; sc->sc_rs.rs_roam_mode = MODE_FAST_CELL; sc->sc_rs.rs_SOReqFailed = 0; sc->sc_rs.rs_BeaconCount = 0; sc->sc_rs.rs_BeaconKept = 0;}static voidSetDOMID(sc, val) struct wlp_softc *sc; int val;{ sc->sc_rs.rs_domid = (val & 0xFFFF); if (sc->sc_rs.rs_domid && sc->sc_rs.rs_ap && sc->sc_rs.rs_ap->ap_beacon.domid != sc->sc_rs.rs_domid) { RoamReset(sc); }}/* * ====================================================================== * Functions that implement Roaming... * ====================================================================== */static voidroam_timer(arg) void *arg;{ struct wlp_softc *sc = arg; struct ifnet *ifp = &sc->sc_ac.ac_if; struct accesspoint *a = 0; int s; s = splimp();#ifdef WLP_DEBUG printf("----------\nbeacons... COUNT: %d, KEPT: %d, DISCARD: %d\n", sc->sc_rs.rs_BeaconCount, sc->sc_rs.rs_BeaconKept, sc->sc_rs.rs_BeaconCount - sc->sc_rs.rs_BeaconKept); printf("%s: sc_ap %p sc_apreg %p\n\tmode %s time %ld.%ld\n", __FUNCTION__, sc->sc_rs.rs_ap, sc->sc_rs.rs_apreg, RoamModeString[sc->sc_rs.rs_roam_mode], time.tv_sec, time.tv_usec); dump_ap(sc->sc_rs.rs_ap);#endif /* WLP_DEBUG */ if (sc->sc_rs.rs_roam_enable != ROAM_ON) { goto quit; } if (sc->sc_gone) { RoamOnOff(sc, ROAM_OFF); goto quit; } if ((ifp->if_flags & IFF_RUNNING) == 0) { goto done; }start: PurgeAccessPointList(sc); switch (sc->sc_rs.rs_roam_mode) { case MODE_FAST_CELL: case MODE_REG_CELL: /* * =========================================================== * Necessary to avoid thrashing... * =========================================================== */ if (sc->sc_rs.rs_ap && SNR(sc->sc_rs.rs_ap) > STOP_CELL(sc->sc_rs.rs_ap)) { /* ~NWID Promisc Mode */ SetNWID(sc, sc->sc_rs.rs_ap->ap_beacon.snwid, 0); if (sc->sc_rs.rs_roam_mode == MODE_FAST_CELL) EnableTX(ifp); if (sc->sc_rs.rs_apreg) {#ifdef WLP_DEBUG printf("Aborting Registration!\n");#endif EnableTX(ifp); /* Transmission Enabled */ SendRECReq(sc); /* XXX - Send a Recover REQ */ sc->sc_rs.rs_apreg = 0; /* Not Registering */ } sc->sc_rs.rs_roam_mode = MODE_STOP_CELL; goto done; } /* * =========================================================== * Try to find a better Access Point... * =========================================================== */ a = BestAccessPoint1(sc); if ((a == 0) || SNR(a) < FAST_CELL(a)) { SetNWID(sc, 0, 1); /* NWID Promisc Mode */ DisableTX(ifp); sc->sc_rs.rs_roam_mode = MODE_FAST_CELL; goto done; } /* * =========================================================== * Current Access Point * =========================================================== */ if (a == sc->sc_rs.rs_ap || (BestAccessPoint2(sc->sc_rs.rs_ap, a) == sc->sc_rs.rs_ap)) { /* NWID Promisc Mode */ SetNWID(sc, a->ap_beacon.snwid, 1); if (sc->sc_rs.rs_roam_mode == MODE_FAST_CELL) EnableTX(ifp); if (sc->sc_rs.rs_apreg) {#ifdef WLP_DEBUG printf("Aborting Registration!\n");#endif EnableTX(ifp); SendRECReq(a->ap_softc); /* XXX */ sc->sc_rs.rs_apreg = 0; /* Not Registering */ } sc->sc_rs.rs_roam_mode = MODE_REG_CELL; goto done; } /* * =========================================================== * Registering Access Point * =========================================================== */ if (a == sc->sc_rs.rs_apreg) { if (sc->sc_rs.rs_SOReqRetrans < MAX_SOREQ_RETRANS) {#ifdef WLP_DEBUG printf("*** No Sign-on Response Received\n"); printf("\tNWID: %x, SOReqRetrans = %d\n", sc->sc_rs.rs_apreg->ap_beacon.snwid, sc->sc_rs.rs_SOReqRetrans);#endif } else { /* * Must fall back to an initial Sign-ON ==> * forget about the previous base station. */ if (sc->sc_rs.rs_ap) { LIST_REMOVE(sc->sc_rs.rs_ap, ap_link); free(sc->sc_rs.rs_ap, M_TEMP); sc->sc_rs.rs_ap = 0; } else {#ifdef WLP_DEBUG panic("Can't Register at all...");#endif }#ifdef WLP_DEBUG printf("*** No Sign-on Response Received\n"); printf("\tNWID: %x, SOReqRetrans = %d\n", sc->sc_rs.rs_apreg->ap_beacon.snwid, sc->sc_rs.rs_SOReqRetrans);#endif sc->sc_rs.rs_SOReqRetrans = 0; sc->sc_rs.rs_SOReqFailed = 1; } SendSOReq(sc, a); /* Send a Sign-on Request */ sc->sc_rs.rs_roam_mode = MODE_REG_CELL; } /* * =========================================================== * New Access Point * =========================================================== */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -