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

Cache object: 80fe8cf907bbfcb848eb487dab90da94


[ 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.