The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/if_wi_hostap.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: if_wi_hostap.c,v 1.52 2018/02/19 08:59:52 mpi Exp $   */
    2 
    3 /*
    4  * Copyright (c) 2002
    5  *      Thomas Skibo <skibo@pacbell.net>.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Thomas Skibo.
   18  * 4. Neither the name of the author nor the names of any co-contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY Thomas Skibo AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL Thomas Skibo OR HIS DRINKING PALS
   26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   32  * THE POSSIBILITY OF SUCH DAMAGE.
   33  *
   34  */
   35 
   36 /* This is experimental Host AP software for Prism 2 802.11b interfaces.
   37  *
   38  * Much of this is based upon the "Linux Host AP driver Host AP driver
   39  * for Intersil Prism2" by Jouni Malinen <jkm@ssh.com> or <jkmaline@cc.hut.fi>.
   40  */
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/sockio.h>
   45 #include <sys/mbuf.h>
   46 #include <sys/malloc.h>
   47 #include <sys/kernel.h>
   48 #include <sys/timeout.h>
   49 #include <sys/ucred.h>
   50 #include <sys/socket.h>
   51 #include <sys/queue.h>
   52 #include <sys/syslog.h>
   53 #include <sys/sysctl.h>
   54 #include <sys/device.h>
   55 
   56 #include <machine/bus.h>
   57 
   58 #include <net/if.h>
   59 #include <net/if_media.h>
   60 
   61 #include <netinet/in.h>
   62 #include <netinet/if_ether.h>
   63 
   64 #include <net80211/ieee80211_var.h>
   65 #include <net80211/ieee80211_ioctl.h>
   66 
   67 #include <dev/ic/if_wireg.h>
   68 #include <dev/ic/if_wi_ieee.h>
   69 #include <dev/ic/if_wivar.h>
   70 
   71 void wihap_timeout(void *v);
   72 void wihap_sta_timeout(void *v);
   73 struct wihap_sta_info *wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr);
   74 void wihap_sta_delete(struct wihap_sta_info *sta);
   75 struct wihap_sta_info *wihap_sta_find(struct wihap_info *whi, u_int8_t *addr);
   76 int wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[]);
   77 void wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
   78     caddr_t pkt, int len);
   79 void wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[],
   80     u_int16_t reason);
   81 void wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
   82     caddr_t pkt, int len);
   83 void wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
   84     caddr_t pkt, int len);
   85 void wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[],
   86     u_int16_t reason);
   87 void wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
   88     caddr_t pkt, int len);
   89 
   90 #ifndef SMALL_KERNEL
   91 /*
   92  * take_hword()
   93  *
   94  *      Used for parsing management frames.  The pkt pointer and length
   95  *      variables are updated after the value is removed.
   96  */
   97 static __inline u_int16_t
   98 take_hword(caddr_t *ppkt, int *plen)
   99 {
  100         u_int16_t s = letoh16(* (u_int16_t *) *ppkt);
  101         *ppkt += sizeof(u_int16_t);
  102         *plen -= sizeof(u_int16_t);
  103         return s;
  104 }
  105 
  106 /* take_tlv()
  107  *
  108  *      Parse out TLV element from a packet, check for underflow of packet
  109  *      or overflow of buffer, update pkt/len.
  110  */
  111 static int
  112 take_tlv(caddr_t *ppkt, int *plen, int id_expect, void *dst, int maxlen)
  113 {
  114         u_int8_t id, len;
  115 
  116         if (*plen < 2)
  117                 return -1;
  118 
  119         id = ((u_int8_t *)*ppkt)[0];
  120         len = ((u_int8_t *)*ppkt)[1];
  121 
  122         if (id != id_expect || *plen < len+2 || maxlen < len)
  123                 return -1;
  124 
  125         bcopy(*ppkt + 2, dst, len);
  126         *plen -= 2 + len;
  127         *ppkt += 2 + len;
  128 
  129         return (len);
  130 }
  131 
  132 /* put_hword()
  133  *      Put half-word element into management frames.
  134  */
  135 static __inline void
  136 put_hword(caddr_t *ppkt, u_int16_t s)
  137 {
  138         * (u_int16_t *) *ppkt = htole16(s);
  139         *ppkt += sizeof(u_int16_t);
  140 }
  141 
  142 /* put_tlv()
  143  *      Put TLV elements into management frames.
  144  */
  145 static void
  146 put_tlv(caddr_t *ppkt, u_int8_t id, void *src, u_int8_t len)
  147 {
  148         (*ppkt)[0] = id;
  149         (*ppkt)[1] = len;
  150         bcopy(src, (*ppkt) + 2, len);
  151         *ppkt += 2 + len;
  152 }
  153 
  154 static int
  155 put_rates(caddr_t *ppkt, u_int16_t rates)
  156 {
  157         u_int8_t ratebuf[8];
  158         int len = 0;
  159 
  160         if (rates & WI_SUPPRATES_1M)
  161                 ratebuf[len++] = 0x82;
  162         if (rates & WI_SUPPRATES_2M)
  163                 ratebuf[len++] = 0x84;
  164         if (rates & WI_SUPPRATES_5M)
  165                 ratebuf[len++] = 0x8b;
  166         if (rates & WI_SUPPRATES_11M)
  167                 ratebuf[len++] = 0x96;
  168 
  169         put_tlv(ppkt, IEEE80211_ELEMID_RATES, ratebuf, len);
  170         return len;
  171 }
  172 
  173 /* wihap_init()
  174  *
  175  *      Initialize host AP data structures.  Called even if port type is
  176  *      not AP.  Caller MUST raise to splnet().
  177  */
  178 void
  179 wihap_init(struct wi_softc *sc)
  180 {
  181         int i;
  182         struct wihap_info *whi = &sc->wi_hostap_info;
  183 
  184         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  185                 printf("wihap_init: sc=%p whi=%p\n", sc, whi);
  186 
  187         bzero(whi, sizeof(struct wihap_info));
  188 
  189         if (sc->wi_ptype != WI_PORTTYPE_HOSTAP)
  190                 return;
  191 
  192         whi->apflags = WIHAPFL_ACTIVE;
  193 
  194         TAILQ_INIT(&whi->sta_list);
  195         for (i = 0; i < WI_STA_HASH_SIZE; i++)
  196                 LIST_INIT(&whi->sta_hash[i]);
  197 
  198         whi->inactivity_time = WIHAP_DFLT_INACTIVITY_TIME;
  199         timeout_set(&whi->tmo, wihap_timeout, sc);
  200 }
  201 
  202 /* wihap_sta_disassoc()
  203  *
  204  *      Send a disassociation frame to a specified station.
  205  */
  206 void
  207 wihap_sta_disassoc(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
  208 {
  209         struct wi_80211_hdr     *resp_hdr;
  210         caddr_t                 pkt;
  211 
  212         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  213                 printf("Sending disassoc to sta %s\n", ether_sprintf(sta_addr));
  214 
  215         /* Send disassoc packet. */
  216         resp_hdr = (struct wi_80211_hdr *)sc->wi_txbuf;
  217         bzero(resp_hdr, sizeof(struct wi_80211_hdr));
  218         resp_hdr->frame_ctl = WI_FTYPE_MGMT | WI_STYPE_MGMT_DISAS;
  219         pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
  220 
  221         bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN);
  222         bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
  223         bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
  224 
  225         put_hword(&pkt, reason);
  226 
  227         wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
  228             2 + sizeof(struct wi_80211_hdr));
  229 }
  230 
  231 /* wihap_sta_deauth()
  232  *
  233  *      Send a deauthentication message to a specified station.
  234  */
  235 void
  236 wihap_sta_deauth(struct wi_softc *sc, u_int8_t sta_addr[], u_int16_t reason)
  237 {
  238         struct wi_80211_hdr     *resp_hdr;
  239         caddr_t                 pkt;
  240 
  241         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  242                 printf("Sending deauth to sta %s\n", ether_sprintf(sta_addr));
  243 
  244         /* Send deauth packet. */
  245         resp_hdr = (struct wi_80211_hdr *)sc->wi_txbuf;
  246         bzero(resp_hdr, sizeof(struct wi_80211_hdr));
  247         resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_DEAUTH);
  248         pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
  249 
  250         bcopy(sta_addr, resp_hdr->addr1, ETHER_ADDR_LEN);
  251         bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
  252         bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
  253 
  254         put_hword(&pkt, reason);
  255 
  256         wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
  257             2 + sizeof(struct wi_80211_hdr));
  258 }
  259 
  260 /* wihap_shutdown()
  261  *
  262  *      Disassociate all stations and free up data structures.
  263  */
  264 void
  265 wihap_shutdown(struct wi_softc *sc)
  266 {
  267         struct wihap_info       *whi = &sc->wi_hostap_info;
  268         struct wihap_sta_info   *sta, *next;
  269         int i, s;
  270 
  271         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  272                 printf("wihap_shutdown: sc=%p whi=%p\n", sc, whi);
  273 
  274         if (!(whi->apflags & WIHAPFL_ACTIVE))
  275                 return;
  276         whi->apflags = 0;
  277 
  278         s = splnet();
  279 
  280         /* Disable wihap inactivity timer. */
  281         timeout_del(&whi->tmo);
  282 
  283         /* Delete all stations from the list. */
  284         for (sta = TAILQ_FIRST(&whi->sta_list); sta != NULL; sta = next) {
  285                 timeout_del(&sta->tmo);
  286                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  287                         printf("wihap_shutdown: free(sta=%p)\n", sta);
  288                 next = TAILQ_NEXT(sta, list);
  289                 if (sta->challenge)
  290                         free(sta->challenge, M_TEMP, 0);
  291                 free(sta, M_DEVBUF, 0);
  292         }
  293         TAILQ_INIT(&whi->sta_list);
  294 
  295         /* Broadcast disassoc and deauth to all the stations. */
  296         if (sc->wi_flags & WI_FLAGS_ATTACHED) {
  297                 for (i = 0; i < 5; i++) {
  298                         wihap_sta_disassoc(sc, etherbroadcastaddr,
  299                             IEEE80211_REASON_ASSOC_LEAVE);
  300                         wihap_sta_deauth(sc, etherbroadcastaddr,
  301                             IEEE80211_REASON_AUTH_LEAVE);
  302                         DELAY(50);
  303                 }
  304         }
  305 
  306         splx(s);
  307 }
  308 
  309 /* sta_hash_func()
  310  * Hash function for finding stations from ethernet address.
  311  */
  312 static __inline int
  313 sta_hash_func(u_int8_t addr[])
  314 {
  315         return ((addr[3] + addr[4] + addr[5]) % WI_STA_HASH_SIZE);
  316 }
  317 
  318 /* addr_cmp():  Maybe this is a faster way to compare addresses? */
  319 static __inline int
  320 addr_cmp(u_int8_t a[], u_int8_t b[])
  321 {
  322         return (*(u_int16_t *)(a + 4) == *(u_int16_t *)(b + 4) &&
  323                 *(u_int16_t *)(a + 2) == *(u_int16_t *)(b + 2) &&
  324                 *(u_int16_t *)(a    ) == *(u_int16_t *)(b));
  325 }
  326 
  327 /* wihap_sta_movetail(): move sta to the tail of the station list in whi */
  328 static __inline void
  329 wihap_sta_movetail(struct wihap_info *whi, struct wihap_sta_info *sta)
  330 {
  331         TAILQ_REMOVE(&whi->sta_list, sta, list);
  332         sta->flags &= ~WI_SIFLAGS_DEAD;
  333         TAILQ_INSERT_TAIL(&whi->sta_list, sta, list);
  334 }
  335 
  336 void
  337 wihap_timeout(void *v)
  338 {
  339         struct wi_softc         *sc = v;
  340         struct wihap_info       *whi = &sc->wi_hostap_info;
  341         struct wihap_sta_info   *sta, *next;
  342         int     i, s;
  343 
  344         s = splnet();
  345 
  346         for (i = 10, sta = TAILQ_FIRST(&whi->sta_list);
  347             i != 0 && sta != NULL && (sta->flags & WI_SIFLAGS_DEAD);
  348             i--, sta = next) {
  349                 next = TAILQ_NEXT(sta, list);
  350                 if (timeout_pending(&sta->tmo)) {
  351                         /* Became alive again, move to end of list. */
  352                         wihap_sta_movetail(whi, sta);
  353                 } else if (sta->flags & WI_SIFLAGS_ASSOC) {
  354                         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  355                                 printf("wihap_timeout: disassoc due to inactivity: %s\n",
  356                                     ether_sprintf(sta->addr));
  357 
  358                         /* Disassoc station. */
  359                         wihap_sta_disassoc(sc, sta->addr,
  360                             IEEE80211_REASON_ASSOC_EXPIRE);
  361                         sta->flags &= ~WI_SIFLAGS_ASSOC;
  362 
  363                         /*
  364                          * Move to end of the list and reset station timeout.
  365                          * We do this to make sure we don't get deauthed
  366                          * until inactivity_time seconds have passed.
  367                          */
  368                         wihap_sta_movetail(whi, sta);
  369                         timeout_add_sec(&sta->tmo, whi->inactivity_time);
  370                 } else if (sta->flags & WI_SIFLAGS_AUTHEN) {
  371                         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  372                                 printf("wihap_timeout: deauth due to inactivity: %s\n",
  373                                     ether_sprintf(sta->addr));
  374 
  375                         /* Deauthenticate station. */
  376                         wihap_sta_deauth(sc, sta->addr,
  377                             IEEE80211_REASON_AUTH_EXPIRE);
  378                         sta->flags &= ~WI_SIFLAGS_AUTHEN;
  379 
  380                         /* Delete the station if it's not permanent. */
  381                         if (sta->flags & WI_SIFLAGS_PERM)
  382                                 wihap_sta_movetail(whi, sta);
  383                         else
  384                                 wihap_sta_delete(sta);
  385                 }
  386         }
  387 
  388         /* Restart the timeout if there are still dead stations left. */
  389         sta = TAILQ_FIRST(&whi->sta_list);
  390         if (sta != NULL && (sta->flags & WI_SIFLAGS_DEAD))
  391                 timeout_add(&whi->tmo, 1);      /* still work left, requeue */
  392 
  393         splx(s);
  394 }
  395 
  396 void
  397 wihap_sta_timeout(void *v)
  398 {
  399         struct wihap_sta_info   *sta = v;
  400         struct wi_softc         *sc = sta->sc;
  401         struct wihap_info       *whi = &sc->wi_hostap_info;
  402         int     s;
  403 
  404         s = splnet();
  405 
  406         /* Mark sta as dead and move it to the head of the list. */
  407         TAILQ_REMOVE(&whi->sta_list, sta, list);
  408         sta->flags |= WI_SIFLAGS_DEAD;
  409         TAILQ_INSERT_HEAD(&whi->sta_list, sta, list);
  410 
  411         /* Add wihap timeout if we have not already done so. */
  412         if (!timeout_pending(&whi->tmo))
  413                 timeout_add(&whi->tmo, hz / 10);
  414 
  415         splx(s);
  416 }
  417 
  418 /* wihap_sta_delete()
  419  * Delete a single station and free up its data structure.
  420  * Caller must raise to splnet().
  421  */
  422 void
  423 wihap_sta_delete(struct wihap_sta_info *sta)
  424 {
  425         struct wi_softc         *sc = sta->sc;
  426         struct wihap_info       *whi = &sc->wi_hostap_info;
  427         int i = sta->asid - 0xc001;
  428 
  429         timeout_del(&sta->tmo);
  430 
  431         whi->asid_inuse_mask[i >> 4] &= ~(1UL << (i & 0xf));
  432 
  433         TAILQ_REMOVE(&whi->sta_list, sta, list);
  434         LIST_REMOVE(sta, hash);
  435         if (sta->challenge)
  436                 free(sta->challenge, M_TEMP, 0);
  437         free(sta, M_DEVBUF, 0);
  438         whi->n_stations--;
  439 }
  440 
  441 /* wihap_sta_alloc()
  442  *
  443  *      Create a new station data structure and put it in the list
  444  *      and hash table.
  445  */
  446 struct wihap_sta_info *
  447 wihap_sta_alloc(struct wi_softc *sc, u_int8_t *addr)
  448 {
  449         struct wihap_info       *whi = &sc->wi_hostap_info;
  450         struct wihap_sta_info   *sta;
  451         int i, hash = sta_hash_func(addr);
  452 
  453         /* Allocate structure. */
  454         sta = malloc(sizeof(*sta), M_DEVBUF, M_NOWAIT | M_ZERO);
  455         if (sta == NULL)
  456                 return (NULL);
  457 
  458         /* Allocate an ASID. */
  459         i=hash<<4;
  460         while (whi->asid_inuse_mask[i >> 4] & (1UL << (i & 0xf)))
  461                 i = (i == (WI_STA_HASH_SIZE << 4) - 1) ? 0 : (i + 1);
  462         whi->asid_inuse_mask[i >> 4] |= (1UL << (i & 0xf));
  463         sta->asid = 0xc001 + i;
  464 
  465         /* Insert in list and hash list. */
  466         TAILQ_INSERT_TAIL(&whi->sta_list, sta, list);
  467         LIST_INSERT_HEAD(&whi->sta_hash[hash], sta, hash);
  468 
  469         sta->sc = sc;
  470         whi->n_stations++;
  471         bcopy(addr, &sta->addr, ETHER_ADDR_LEN);
  472         timeout_set(&sta->tmo, wihap_sta_timeout, sta);
  473         timeout_add_sec(&sta->tmo, whi->inactivity_time);
  474 
  475         return (sta);
  476 }
  477 
  478 /* wihap_sta_find()
  479  *
  480  *      Find station structure given address.
  481  */
  482 struct wihap_sta_info *
  483 wihap_sta_find(struct wihap_info *whi, u_int8_t *addr)
  484 {
  485         int i;
  486         struct wihap_sta_info *sta;
  487 
  488         i = sta_hash_func(addr);
  489         LIST_FOREACH(sta, &whi->sta_hash[i], hash)
  490                 if (addr_cmp(addr, sta->addr))
  491                         return sta;
  492 
  493         return (NULL);
  494 }
  495 
  496 static __inline int
  497 wihap_check_rates(struct wihap_sta_info *sta, u_int8_t rates[], int rates_len)
  498 {
  499         struct wi_softc *sc = sta->sc;
  500         int     i;
  501 
  502         sta->rates = 0;
  503         sta->tx_max_rate = 0;
  504         for (i = 0; i < rates_len; i++)
  505                 switch (rates[i] & 0x7f) {
  506                 case 0x02:
  507                         sta->rates |= WI_SUPPRATES_1M;
  508                         break;
  509                 case 0x04:
  510                         sta->rates |= WI_SUPPRATES_2M;
  511                         if (sta->tx_max_rate < 1)
  512                                 sta->tx_max_rate = 1;
  513                         break;
  514                 case 0x0b:
  515                         sta->rates |= WI_SUPPRATES_5M;
  516                         if (sta->tx_max_rate < 2)
  517                                 sta->tx_max_rate = 2;
  518                         break;
  519                 case 0x16:
  520                         sta->rates |= WI_SUPPRATES_11M;
  521                         sta->tx_max_rate = 3;
  522                         break;
  523                 }
  524 
  525         sta->rates &= sc->wi_supprates;
  526         sta->tx_curr_rate = sta->tx_max_rate;
  527 
  528         return (sta->rates == 0 ? -1 : 0);
  529 }
  530 
  531 
  532 /* wihap_auth_req()
  533  *
  534  *      Handle incoming authentication request.
  535  */
  536 void
  537 wihap_auth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
  538     caddr_t pkt, int len)
  539 {
  540         struct wihap_info       *whi = &sc->wi_hostap_info;
  541         struct wihap_sta_info   *sta;
  542         int                     i, s;
  543 
  544         u_int16_t               algo;
  545         u_int16_t               seq;
  546         u_int16_t               status;
  547         int                     challenge_len;
  548         u_int32_t               challenge[32];
  549 
  550         struct wi_80211_hdr     *resp_hdr;
  551 
  552         if (len < 6) {
  553                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  554                         printf("wihap_auth_req: station %s short request\n",
  555                             ether_sprintf(rxfrm->wi_addr2));
  556                 return;
  557         }
  558 
  559         /* Break open packet. */
  560         algo = take_hword(&pkt, &len);
  561         seq = take_hword(&pkt, &len);
  562         status = take_hword(&pkt, &len);
  563         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  564                 printf("wihap_auth_req: station %s algo=0x%x seq=0x%x\n",
  565                     ether_sprintf(rxfrm->wi_addr2), algo, seq);
  566 
  567         /* Ignore vendor private tlv (if any). */
  568         (void)take_tlv(&pkt, &len, IEEE80211_ELEMID_VENDOR, challenge,
  569             sizeof(challenge));
  570 
  571         challenge_len = 0;
  572         if (len > 0 && (challenge_len = take_tlv(&pkt, &len,
  573             IEEE80211_ELEMID_CHALLENGE, challenge, sizeof(challenge))) < 0) {
  574                 status = IEEE80211_STATUS_CHALLENGE;
  575                 goto fail;
  576         }
  577 
  578         /* Find or create station info. */
  579         sta = wihap_sta_find(whi, rxfrm->wi_addr2);
  580         if (sta == NULL) {
  581 
  582                 /* Are we allowing new stations?
  583                  */
  584                 if (whi->apflags & WIHAPFL_MAC_FILT) {
  585                         status = IEEE80211_STATUS_OTHER; /* XXX */
  586                         goto fail;
  587                 }
  588 
  589                 /* Check for too many stations.
  590                  */
  591                 if (whi->n_stations >= WIHAP_MAX_STATIONS) {
  592                         status = IEEE80211_STATUS_TOOMANY;
  593                         goto fail;
  594                 }
  595 
  596                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  597                         printf("wihap_auth_req: new station\n");
  598 
  599                 /* Create new station. */
  600                 s = splnet();
  601                 sta = wihap_sta_alloc(sc, rxfrm->wi_addr2);
  602                 splx(s);
  603                 if (sta == NULL) {
  604                         /* Out of memory! */
  605                         status = IEEE80211_STATUS_TOOMANY;
  606                         goto fail;
  607                 }
  608         }
  609         timeout_add_sec(&sta->tmo, whi->inactivity_time);
  610 
  611         /* Note: it's okay to leave the station info structure around
  612          * if the authen fails.  It'll be timed out eventually.
  613          */
  614         switch (algo) {
  615         case IEEE80211_AUTH_ALG_OPEN:
  616                 if (sc->wi_authtype != IEEE80211_AUTH_OPEN) {
  617                         status = IEEE80211_STATUS_ALG;
  618                         goto fail;
  619                 }
  620                 if (seq != 1) {
  621                         status = IEEE80211_STATUS_SEQUENCE;
  622                         goto fail;
  623                 }
  624                 challenge_len = 0;
  625                 sta->flags |= WI_SIFLAGS_AUTHEN;
  626                 break;
  627         case IEEE80211_AUTH_ALG_SHARED:
  628                 if (sc->wi_authtype != IEEE80211_AUTH_SHARED) {
  629                         status = IEEE80211_STATUS_ALG;
  630                         goto fail;
  631                 }
  632                 switch (seq) {
  633                 case 1:
  634                         /* Create a challenge frame. */
  635                         if (!sta->challenge) {
  636                                 sta->challenge = malloc(128, M_TEMP, M_NOWAIT);
  637                                 if (!sta->challenge)
  638                                         return;
  639                         }
  640                         for (i = 0; i < 32; i++)
  641                                 challenge[i] = sta->challenge[i] =
  642                                         arc4random();
  643                         
  644                         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  645                                 printf("\tchallenge: 0x%x 0x%x ...\n",
  646                                    challenge[0], challenge[1]);
  647                         challenge_len = 128;
  648                         break;
  649                 case 3:
  650                         if (challenge_len != 128 || !sta->challenge ||
  651                             !(letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_WEP)) {
  652                                 status = IEEE80211_STATUS_CHALLENGE;
  653                                 goto fail;
  654                         }
  655 
  656                         for (i=0; i<32; i++)
  657                                 if (sta->challenge[i] != challenge[i]) {
  658                                         status = IEEE80211_STATUS_CHALLENGE;
  659                                         goto fail;
  660                                 }
  661 
  662                         sta->flags |= WI_SIFLAGS_AUTHEN;
  663                         free(sta->challenge, M_TEMP, 0);
  664                         sta->challenge = NULL;
  665                         challenge_len = 0;
  666                         break;
  667                 default:
  668                         status = IEEE80211_STATUS_SEQUENCE;
  669                         goto fail;
  670                 } /* switch (seq) */
  671                 break;
  672         default:
  673                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  674                         printf("wihap_auth_req: algorithm unsupported: 0x%x\n",
  675                            algo);
  676                 status = IEEE80211_STATUS_ALG;
  677                 goto fail;
  678         } /* switch (algo) */
  679 
  680         status = IEEE80211_STATUS_SUCCESS;
  681 
  682 fail:
  683         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  684                 printf("wihap_auth_req: returns status=0x%x\n", status);
  685 
  686         /* Send response. */
  687         resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf;
  688         bzero(resp_hdr, sizeof(struct wi_80211_hdr));
  689         resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_AUTH);
  690         bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);
  691         bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
  692         bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
  693 
  694         pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
  695         put_hword(&pkt, algo);
  696         put_hword(&pkt, seq + 1);
  697         put_hword(&pkt, status);
  698         if (challenge_len > 0)
  699                 put_tlv(&pkt, IEEE80211_ELEMID_CHALLENGE,
  700                         challenge, challenge_len);
  701 
  702         wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
  703             6 + sizeof(struct wi_80211_hdr) +
  704             (challenge_len > 0 ? challenge_len + 2 : 0));
  705 }
  706 
  707 
  708 /* wihap_assoc_req()
  709  *
  710  *      Handle incoming association and reassociation requests.
  711  */
  712 void
  713 wihap_assoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
  714                 caddr_t pkt, int len)
  715 {
  716         struct wihap_info       *whi = &sc->wi_hostap_info;
  717         struct wihap_sta_info   *sta;
  718         struct wi_80211_hdr     *resp_hdr;
  719         u_int16_t               capinfo;
  720         u_int16_t               lstintvl;
  721         u_int8_t                rates[12];
  722         int                     ssid_len, rates_len;
  723         struct ieee80211_nwid   ssid;
  724         u_int16_t               status;
  725         u_int16_t               asid = 0;
  726 
  727         if (len < 8)
  728                 return;
  729 
  730         /* Pull out request parameters. */
  731         capinfo = take_hword(&pkt, &len);
  732         lstintvl = take_hword(&pkt, &len);
  733 
  734         if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_STYPE)) ==
  735             htole16(WI_STYPE_MGMT_REASREQ)) {
  736                 if (len < 6)
  737                         return;
  738                 /* Eat the MAC address of the current AP */
  739                 take_hword(&pkt, &len);
  740                 take_hword(&pkt, &len);
  741                 take_hword(&pkt, &len);
  742         }
  743 
  744         if ((ssid_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_SSID,
  745             ssid.i_nwid, sizeof(ssid))) < 0)
  746                 return;
  747         ssid.i_len = ssid_len;
  748         if ((rates_len = take_tlv(&pkt, &len, IEEE80211_ELEMID_RATES,
  749             rates, sizeof(rates))) < 0)
  750                 return;
  751 
  752         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  753                 printf("wihap_assoc_req: from station %s\n",
  754                     ether_sprintf(rxfrm->wi_addr2));
  755 
  756         /* If SSID doesn't match, simply drop. */
  757         if (sc->wi_net_name.i_len != ssid.i_len ||
  758             memcmp(sc->wi_net_name.i_nwid, ssid.i_nwid, ssid.i_len)) {
  759 
  760                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  761                         printf("wihap_assoc_req: bad ssid: '%.*s' != '%.*s'\n",
  762                             ssid.i_len, ssid.i_nwid, sc->wi_net_name.i_len,
  763                             sc->wi_net_name.i_nwid);
  764                 return;
  765         }
  766 
  767         /* Is this station authenticated yet? */
  768         sta = wihap_sta_find(whi, rxfrm->wi_addr2);
  769         if (sta == NULL || !(sta->flags & WI_SIFLAGS_AUTHEN)) {
  770                 wihap_sta_deauth(sc, rxfrm->wi_addr2,
  771                     IEEE80211_REASON_NOT_AUTHED);
  772                 return;
  773         }
  774 
  775         /* Check supported rates against ours. */
  776         if (wihap_check_rates(sta, rates, rates_len) < 0) {
  777                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  778                         printf("wihap_assoc_req: rates mismatch.\n");
  779                 status = IEEE80211_STATUS_BASIC_RATE;
  780                 goto fail;
  781         }
  782 
  783         /* Check capinfo.
  784          * Check for ESS, not IBSS.
  785          * Check WEP/PRIVACY flags match.
  786          * Refuse stations requesting to be put on CF-polling list.
  787          */
  788         sta->capinfo = capinfo;
  789         status = IEEE80211_STATUS_CAPINFO;
  790         if ((capinfo & (IEEE80211_CAPINFO_ESS | IEEE80211_CAPINFO_IBSS)) !=
  791             IEEE80211_CAPINFO_ESS) {
  792                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  793                         printf("wihap_assoc_req: capinfo: not ESS: "
  794                             "capinfo=0x%x\n", capinfo);
  795                 goto fail;
  796 
  797         }
  798         if ((sc->wi_use_wep && !(capinfo & IEEE80211_CAPINFO_PRIVACY)) ||
  799             (!sc->wi_use_wep && (capinfo & IEEE80211_CAPINFO_PRIVACY))) {
  800                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  801                         printf("wihap_assoc_req: WEP flag mismatch: "
  802                             "capinfo=0x%x\n", capinfo);
  803                 goto fail;
  804         }
  805         if ((capinfo & (IEEE80211_CAPINFO_CF_POLLABLE |
  806             IEEE80211_CAPINFO_CF_POLLREQ)) == IEEE80211_CAPINFO_CF_POLLABLE) {
  807                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  808                         printf("wihap_assoc_req: polling not supported: "
  809                             "capinfo=0x%x\n", capinfo);
  810                 goto fail;
  811         }
  812 
  813         /* Use ASID is allocated by whi_sta_alloc(). */
  814         asid = sta->asid;
  815 
  816         if (sta->flags & WI_SIFLAGS_ASSOC) {
  817                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  818                         printf("wihap_assoc_req: already assoc'ed?\n");
  819         }
  820 
  821         sta->flags |= WI_SIFLAGS_ASSOC;
  822         timeout_add_sec(&sta->tmo, whi->inactivity_time);
  823         status = IEEE80211_STATUS_SUCCESS;
  824 
  825 fail:
  826         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  827                 printf("wihap_assoc_req: returns status=0x%x\n", status);
  828 
  829         /* Send response. */
  830         resp_hdr = (struct wi_80211_hdr *)&sc->wi_txbuf;
  831         bzero(resp_hdr, sizeof(struct wi_80211_hdr));
  832         resp_hdr->frame_ctl = htole16(WI_FTYPE_MGMT | WI_STYPE_MGMT_ASRESP);
  833         pkt = (caddr_t)&sc->wi_txbuf + sizeof(struct wi_80211_hdr);
  834 
  835         bcopy(rxfrm->wi_addr2, resp_hdr->addr1, ETHER_ADDR_LEN);
  836         bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr2, IEEE80211_ADDR_LEN);
  837         bcopy(sc->sc_ic.ic_myaddr, resp_hdr->addr3, IEEE80211_ADDR_LEN);
  838 
  839         put_hword(&pkt, capinfo);
  840         put_hword(&pkt, status);
  841         put_hword(&pkt, asid);
  842         rates_len = put_rates(&pkt, sc->wi_supprates);
  843 
  844         wi_mgmt_xmit(sc, (caddr_t)&sc->wi_txbuf,
  845             8 + rates_len + sizeof(struct wi_80211_hdr));
  846 }
  847 
  848 /* wihap_deauth_req()
  849  *
  850  *      Handle deauthentication requests.  Delete the station.
  851  */
  852 void
  853 wihap_deauth_req(struct wi_softc *sc, struct wi_frame *rxfrm,
  854                  caddr_t pkt, int len)
  855 {
  856         struct wihap_info       *whi = &sc->wi_hostap_info;
  857         struct wihap_sta_info   *sta;
  858         u_int16_t               reason;
  859 
  860         if (len<2)
  861                 return;
  862 
  863         reason = take_hword(&pkt, &len);
  864 
  865         sta = wihap_sta_find(whi, rxfrm->wi_addr2);
  866         if (sta == NULL) {
  867                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  868                         printf("wihap_deauth_req: unknown station: %s\n",
  869                             ether_sprintf(rxfrm->wi_addr2));
  870         }
  871         else
  872                 wihap_sta_delete(sta);
  873 }
  874 
  875 /* wihap_disassoc_req()
  876  *
  877  *      Handle disassociation requests.  Just reset the assoc flag.
  878  *      We'll free up the station resources when we get a deauth
  879  *      request or when it times out.
  880  */
  881 void
  882 wihap_disassoc_req(struct wi_softc *sc, struct wi_frame *rxfrm,
  883     caddr_t pkt, int len)
  884 {
  885         struct wihap_info       *whi = &sc->wi_hostap_info;
  886         struct wihap_sta_info   *sta;
  887         u_int16_t               reason;
  888 
  889         if (len < 2)
  890                 return;
  891 
  892         reason = take_hword(&pkt, &len);
  893 
  894         sta = wihap_sta_find(whi, rxfrm->wi_addr2);
  895         if (sta == NULL) {
  896                 if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  897                         printf("wihap_disassoc_req: unknown station: %s\n",
  898                             ether_sprintf(rxfrm->wi_addr2));
  899         }
  900         else if (!(sta->flags & WI_SIFLAGS_AUTHEN)) {
  901                 /*
  902                  * If station is not authenticated, send deauthentication
  903                  * frame.
  904                  */
  905                 wihap_sta_deauth(sc, rxfrm->wi_addr2,
  906                     IEEE80211_REASON_NOT_AUTHED);
  907                 return;
  908         }
  909         else
  910                 sta->flags &= ~WI_SIFLAGS_ASSOC;
  911 }
  912 
  913 /* wihap_debug_frame_type()
  914  *
  915  * Print out frame type.  Used in early debugging.
  916  */
  917 static __inline void
  918 wihap_debug_frame_type(struct wi_frame *rxfrm)
  919 {
  920         printf("wihap_mgmt_input: len=%d ", letoh16(rxfrm->wi_dat_len));
  921 
  922         if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
  923             htole16(WI_FTYPE_MGMT)) {
  924 
  925                 printf("MGMT: ");
  926 
  927                 switch (letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) {
  928                 case WI_STYPE_MGMT_ASREQ:
  929                         printf("assoc req: \n");
  930                         break;
  931                 case WI_STYPE_MGMT_ASRESP:
  932                         printf("assoc resp: \n");
  933                         break;
  934                 case WI_STYPE_MGMT_REASREQ:
  935                         printf("reassoc req: \n");
  936                         break;
  937                 case WI_STYPE_MGMT_REASRESP:
  938                         printf("reassoc resp: \n");
  939                         break;
  940                 case WI_STYPE_MGMT_PROBEREQ:
  941                         printf("probe req: \n");
  942                         break;
  943                 case WI_STYPE_MGMT_PROBERESP:
  944                         printf("probe resp: \n");
  945                         break;
  946                 case WI_STYPE_MGMT_BEACON:
  947                         printf("beacon: \n");
  948                         break;
  949                 case WI_STYPE_MGMT_ATIM:
  950                         printf("ann traf ind \n");
  951                         break;
  952                 case WI_STYPE_MGMT_DISAS:
  953                         printf("disassociation: \n");
  954                         break;
  955                 case WI_STYPE_MGMT_AUTH:
  956                         printf("auth: \n");
  957                         break;
  958                 case WI_STYPE_MGMT_DEAUTH:
  959                         printf("deauth: \n");
  960                         break;
  961                 default:
  962                         printf("unknown (stype=0x%x)\n",
  963                             letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE);
  964                 }
  965 
  966         }
  967         else {
  968                 printf("ftype=0x%x (ctl=0x%x)\n",
  969                     letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_FTYPE,
  970                     letoh16(rxfrm->wi_frame_ctl));
  971         }
  972 }
  973 
  974 /*
  975  * wihap_mgmt_input:
  976  *
  977  *      Called for each management frame received in host ap mode.
  978  *      wihap_mgmt_input() is expected to free the mbuf.
  979  */
  980 void
  981 wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
  982 {
  983         caddr_t pkt;
  984         int     s, len;
  985 
  986         if (sc->sc_ic.ic_if.if_flags & IFF_DEBUG)
  987                 wihap_debug_frame_type(rxfrm);
  988 
  989         pkt = mtod(m, caddr_t) + WI_802_11_OFFSET_RAW;
  990         len = m->m_len - WI_802_11_OFFSET_RAW;
  991 
  992         if ((rxfrm->wi_frame_ctl & htole16(WI_FCTL_FTYPE)) ==
  993             htole16(WI_FTYPE_MGMT)) {
  994 
  995                 /* any of the following will mess w/ the station list */
  996                 s = splsoftclock();
  997                 switch (letoh16(rxfrm->wi_frame_ctl) & WI_FCTL_STYPE) {
  998                 case WI_STYPE_MGMT_ASREQ:
  999                         wihap_assoc_req(sc, rxfrm, pkt, len);
 1000                         break;
 1001                 case WI_STYPE_MGMT_ASRESP:
 1002                         break;
 1003                 case WI_STYPE_MGMT_REASREQ:
 1004                         wihap_assoc_req(sc, rxfrm, pkt, len);
 1005                         break;
 1006                 case WI_STYPE_MGMT_REASRESP:
 1007                         break;
 1008                 case WI_STYPE_MGMT_PROBEREQ:
 1009                         break;
 1010                 case WI_STYPE_MGMT_PROBERESP:
 1011                         break;
 1012                 case WI_STYPE_MGMT_BEACON:
 1013                         break;
 1014                 case WI_STYPE_MGMT_ATIM:
 1015                         break;
 1016                 case WI_STYPE_MGMT_DISAS:
 1017                         wihap_disassoc_req(sc, rxfrm, pkt, len);
 1018                         break;
 1019                 case WI_STYPE_MGMT_AUTH:
 1020                         wihap_auth_req(sc, rxfrm, pkt, len);
 1021                         break;
 1022                 case WI_STYPE_MGMT_DEAUTH:
 1023                         wihap_deauth_req(sc, rxfrm, pkt, len);
 1024                         break;
 1025                 }
 1026                 splx(s);
 1027         }
 1028 
 1029         m_freem(m);
 1030 }
 1031 
 1032 /* wihap_sta_is_assoc()
 1033  *
 1034  *      Determine if a station is assoc'ed.  Update its activity
 1035  *      counter as a side-effect.
 1036  */
 1037 int
 1038 wihap_sta_is_assoc(struct wihap_info *whi, u_int8_t addr[])
 1039 {
 1040         struct wihap_sta_info *sta;
 1041 
 1042         sta = wihap_sta_find(whi, addr);
 1043         if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) {
 1044                 /* Keep it active. */
 1045                 timeout_add_sec(&sta->tmo, whi->inactivity_time);
 1046                 return (1);
 1047         }
 1048 
 1049         return (0);
 1050 }
 1051 
 1052 /* wihap_check_tx()
 1053  *
 1054  *      Determine if a station is assoc'ed, get its tx rate, and update
 1055  *      its activity.
 1056  */
 1057 int
 1058 wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
 1059 {
 1060         struct wihap_sta_info *sta;
 1061         static u_int8_t txratetable[] = { 10, 20, 55, 110 };
 1062         int s;
 1063 
 1064         if (addr[0] & 0x01) {
 1065                 *txrate = 0; /* XXX: multicast rate? */
 1066                 return (1);
 1067         }
 1068 
 1069         s = splsoftclock();
 1070         sta = wihap_sta_find(whi, addr);
 1071         if (sta != NULL && (sta->flags & WI_SIFLAGS_ASSOC)) {
 1072                 /* Keep it active. */
 1073                 timeout_add_sec(&sta->tmo, whi->inactivity_time);
 1074                 *txrate = txratetable[sta->tx_curr_rate];
 1075                 splx(s);
 1076                 return (1);
 1077         }
 1078         splx(s);
 1079 
 1080         return (0);
 1081 }
 1082 
 1083 /*
 1084  * wihap_data_input()
 1085  *
 1086  *      Handle all data input on interface when in Host AP mode.
 1087  *      Some packets are destined for this machine, others are
 1088  *      repeated to other stations.
 1089  *
 1090  *      If wihap_data_input() returns a non-zero, it has processed
 1091  *      the packet and will free the mbuf.
 1092  */
 1093 int
 1094 wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
 1095 {
 1096         struct ifnet            *ifp = &sc->sc_ic.ic_if;
 1097         struct wihap_info       *whi = &sc->wi_hostap_info;
 1098         struct wihap_sta_info   *sta;
 1099         int                     mcast, s;
 1100         u_int16_t               fctl;
 1101 
 1102         /*
 1103          * TODS flag must be set.  However, Lucent cards set NULLFUNC but
 1104          * not TODS when probing an AP to see if it is alive after it has
 1105          * been down for a while.  We accept these probe packets and send a
 1106          * disassoc packet later on if the station is not already associated.
 1107          */
 1108         fctl = letoh16(rxfrm->wi_frame_ctl);
 1109         if (!(fctl & WI_FCTL_TODS) && !(fctl & WI_STYPE_NULLFUNC)) {
 1110                 if (ifp->if_flags & IFF_DEBUG)
 1111                         printf("wihap_data_input: no TODS src=%s, fctl=0x%x\n",
 1112                             ether_sprintf(rxfrm->wi_addr2), fctl);
 1113                 m_freem(m);
 1114                 return (1);
 1115         }
 1116 
 1117         /* Check BSSID. (Is this necessary?) */
 1118         if (!addr_cmp(rxfrm->wi_addr1, sc->sc_ic.ic_myaddr)) {
 1119                 if (ifp->if_flags & IFF_DEBUG)
 1120                         printf("wihap_data_input: incorrect bss: %s\n",
 1121                             ether_sprintf(rxfrm->wi_addr1));
 1122                 m_freem(m);
 1123                 return (1);
 1124         }
 1125 
 1126         s = splsoftclock();
 1127 
 1128         /* Find source station. */
 1129         sta = wihap_sta_find(whi, rxfrm->wi_addr2);
 1130 
 1131         /* Source station must be associated. */
 1132         if (sta == NULL || !(sta->flags & WI_SIFLAGS_ASSOC)) {
 1133                 if (ifp->if_flags & IFF_DEBUG)
 1134                         printf("wihap_data_input: dropping unassoc src %s\n",
 1135                             ether_sprintf(rxfrm->wi_addr2));
 1136                 wihap_sta_disassoc(sc, rxfrm->wi_addr2,
 1137                     IEEE80211_REASON_ASSOC_LEAVE);
 1138                 splx(s);
 1139                 m_freem(m);
 1140                 return (1);
 1141         }
 1142 
 1143         timeout_add_sec(&sta->tmo, whi->inactivity_time);
 1144         sta->sig_info = letoh16(rxfrm->wi_q_info);
 1145 
 1146         splx(s);
 1147 
 1148         /* Repeat this packet to BSS? */
 1149         mcast = (rxfrm->wi_addr3[0] & 0x01) != 0;
 1150         if (mcast || wihap_sta_is_assoc(whi, rxfrm->wi_addr3)) {
 1151 
 1152                 /* If it's multicast, make a copy.
 1153                  */
 1154                 if (mcast) {
 1155                         m = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
 1156                         if (m == NULL)
 1157                                 return (0);
 1158                         m->m_flags |= M_MCAST; /* XXX */
 1159                 }
 1160 
 1161                 /* Queue up for repeating.
 1162                  */
 1163                 if_enqueue(ifp, m);
 1164                 return (!mcast);
 1165         }
 1166 
 1167         return (0);
 1168 }
 1169 
 1170 /* wihap_ioctl()
 1171  *
 1172  *      Handle Host AP specific ioctls.  Called from wi_ioctl().
 1173  */
 1174 int
 1175 wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
 1176 {
 1177         struct proc             *p = curproc;
 1178         struct ifreq            *ifr = (struct ifreq *) data;
 1179         struct wihap_info       *whi = &sc->wi_hostap_info;
 1180         struct wihap_sta_info   *sta;
 1181         struct hostap_getall    reqall;
 1182         struct hostap_sta       reqsta;
 1183         struct hostap_sta       stabuf;
 1184         int                     s, error = 0, n, flag;
 1185 
 1186         struct ieee80211_nodereq nr;
 1187         struct ieee80211_nodereq_all *na;
 1188 
 1189         if (!(sc->sc_ic.ic_if.if_flags & IFF_RUNNING))
 1190                 return ENODEV;
 1191 
 1192         switch (command) {
 1193         case SIOCHOSTAP_DEL:
 1194                 if ((error = suser(p)))
 1195                         break;
 1196                 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
 1197                         break;
 1198                 s = splnet();
 1199                 sta = wihap_sta_find(whi, reqsta.addr);
 1200                 if (sta == NULL)
 1201                         error = ENOENT;
 1202                 else {
 1203                         /* Disassociate station. */
 1204                         if (sta->flags & WI_SIFLAGS_ASSOC)
 1205                                 wihap_sta_disassoc(sc, sta->addr,
 1206                                     IEEE80211_REASON_ASSOC_LEAVE);
 1207                         /* Deauth station. */
 1208                         if (sta->flags & WI_SIFLAGS_AUTHEN)
 1209                                 wihap_sta_deauth(sc, sta->addr,
 1210                                     IEEE80211_REASON_AUTH_LEAVE);
 1211 
 1212                         wihap_sta_delete(sta);
 1213                 }
 1214                 splx(s);
 1215                 break;
 1216 
 1217         case SIOCHOSTAP_GET:
 1218                 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
 1219                         break;
 1220                 s = splnet();
 1221                 sta = wihap_sta_find(whi, reqsta.addr);
 1222                 if (sta == NULL)
 1223                         error = ENOENT;
 1224                 else {
 1225                         reqsta.flags = sta->flags;
 1226                         reqsta.asid = sta->asid;
 1227                         reqsta.capinfo = sta->capinfo;
 1228                         reqsta.sig_info = sta->sig_info;
 1229                         reqsta.rates = sta->rates;
 1230 
 1231                         error = copyout(&reqsta, ifr->ifr_data,
 1232                             sizeof(reqsta));
 1233                 }
 1234                 splx(s);
 1235                 break;
 1236 
 1237         case SIOCHOSTAP_ADD:
 1238                 if ((error = suser(p)))
 1239                         break;
 1240                 if ((error = copyin(ifr->ifr_data, &reqsta, sizeof(reqsta))))
 1241                         break;
 1242                 s = splnet();
 1243                 sta = wihap_sta_find(whi, reqsta.addr);
 1244                 if (sta != NULL) {
 1245                         error = EEXIST;
 1246                         splx(s);
 1247                         break;
 1248                 }
 1249                 if (whi->n_stations >= WIHAP_MAX_STATIONS) {
 1250                         error = ENOSPC;
 1251                         splx(s);
 1252                         break;
 1253                 }
 1254                 sta = wihap_sta_alloc(sc, reqsta.addr);
 1255                 sta->flags = reqsta.flags;
 1256                 timeout_add_sec(&sta->tmo, whi->inactivity_time);
 1257                 splx(s);
 1258                 break;
 1259 
 1260         case SIOCHOSTAP_SFLAGS:
 1261                 if ((error = suser(p)))
 1262                         break;
 1263                 if ((error = copyin(ifr->ifr_data, &flag, sizeof(int))))
 1264                         break;
 1265 
 1266                 whi->apflags = (whi->apflags & WIHAPFL_CANTCHANGE) |
 1267                     (flag & ~WIHAPFL_CANTCHANGE);
 1268                 break;
 1269 
 1270         case SIOCHOSTAP_GFLAGS:
 1271                 flag = (int) whi->apflags;
 1272                 error = copyout(&flag, ifr->ifr_data, sizeof(int));
 1273                 break;
 1274 
 1275         case SIOCHOSTAP_GETALL:
 1276                 if ((error = copyin(ifr->ifr_data, &reqall, sizeof(reqall))))
 1277                         break;
 1278 
 1279                 reqall.nstations = whi->n_stations;
 1280                 n = 0;
 1281                 s = splnet();
 1282                 sta = TAILQ_FIRST(&whi->sta_list);
 1283                 while (sta && reqall.size >= n+sizeof(struct hostap_sta)) {
 1284 
 1285                         bcopy(sta->addr, stabuf.addr, ETHER_ADDR_LEN);
 1286                         stabuf.asid = sta->asid;
 1287                         stabuf.flags = sta->flags;
 1288                         stabuf.capinfo = sta->capinfo;
 1289                         stabuf.sig_info = sta->sig_info;
 1290                         stabuf.rates = sta->rates;
 1291 
 1292                         error = copyout(&stabuf, (caddr_t) reqall.addr + n,
 1293                             sizeof(struct hostap_sta));
 1294                         if (error)
 1295                                 break;
 1296 
 1297                         sta = TAILQ_NEXT(sta, list);
 1298                         n += sizeof(struct hostap_sta);
 1299                 }
 1300                 splx(s);
 1301 
 1302                 if (!error)
 1303                         error = copyout(&reqall, ifr->ifr_data,
 1304                             sizeof(reqall));
 1305                 break;
 1306 
 1307         case SIOCG80211ALLNODES:
 1308                 na = (struct ieee80211_nodereq_all *)data;
 1309                 na->na_nodes = n = 0;
 1310                 s = splnet();
 1311                 sta = TAILQ_FIRST(&whi->sta_list);
 1312                 while (sta && na->na_size >=
 1313                     n + sizeof(struct ieee80211_nodereq)) {
 1314                         bzero(&nr, sizeof(nr));
 1315                         IEEE80211_ADDR_COPY(nr.nr_macaddr, sta->addr);
 1316                         IEEE80211_ADDR_COPY(nr.nr_bssid,
 1317                             &sc->sc_ic.ic_myaddr);
 1318                         nr.nr_channel = sc->wi_channel;
 1319                         nr.nr_chan_flags = IEEE80211_CHAN_B;
 1320                         nr.nr_associd = sta->asid;
 1321                         nr.nr_rssi = sta->sig_info >> 8;
 1322                         nr.nr_max_rssi = 0;
 1323                         nr.nr_capinfo = sta->capinfo;
 1324                         nr.nr_nrates = 0;
 1325                         if (sta->rates & WI_SUPPRATES_1M)
 1326                                 nr.nr_rates[nr.nr_nrates++] = 2;
 1327                         if (sta->rates & WI_SUPPRATES_2M)
 1328                                 nr.nr_rates[nr.nr_nrates++] = 4;
 1329                         if (sta->rates & WI_SUPPRATES_5M)
 1330                                 nr.nr_rates[nr.nr_nrates++] = 11;
 1331                         if (sta->rates & WI_SUPPRATES_11M)
 1332                                 nr.nr_rates[nr.nr_nrates++] = 22;
 1333 
 1334                         error = copyout(&nr, (caddr_t)na->na_node + n,
 1335                             sizeof(struct ieee80211_nodereq));
 1336                         if (error)
 1337                                 break;
 1338                         n += sizeof(struct ieee80211_nodereq);
 1339                         na->na_nodes++;
 1340                         sta = TAILQ_NEXT(sta, list);
 1341                 }
 1342                 splx(s);
 1343                 break;
 1344 
 1345         default:
 1346                 printf("wihap_ioctl: i shouldn't get other ioctls!\n");
 1347                 error = EINVAL;
 1348         }
 1349 
 1350         return (error);
 1351 }
 1352 
 1353 #else
 1354 void
 1355 wihap_init(struct wi_softc *sc)
 1356 {
 1357         return;
 1358 }
 1359 
 1360 void
 1361 wihap_shutdown(struct wi_softc *sc)
 1362 {
 1363         return;
 1364 }
 1365 
 1366 void
 1367 wihap_mgmt_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
 1368 {
 1369         return;
 1370 }
 1371 
 1372 int
 1373 wihap_data_input(struct wi_softc *sc, struct wi_frame *rxfrm, struct mbuf *m)
 1374 {
 1375         return (0);
 1376 }
 1377 
 1378 int
 1379 wihap_ioctl(struct wi_softc *sc, u_long command, caddr_t data)
 1380 {
 1381         return (EINVAL);
 1382 }
 1383 
 1384 int
 1385 wihap_check_tx(struct wihap_info *whi, u_int8_t addr[], u_int8_t *txrate)
 1386 {
 1387         return (0);
 1388 }
 1389 #endif

Cache object: c73860e30e211fdab5ac9b43bcb3fb7e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.