root/dev/ic/if_wi_hostap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. take_hword
  2. take_tlv
  3. put_hword
  4. put_tlv
  5. put_rates
  6. wihap_init
  7. wihap_sta_disassoc
  8. wihap_sta_deauth
  9. wihap_shutdown
  10. sta_hash_func
  11. addr_cmp
  12. wihap_sta_movetail
  13. wihap_timeout
  14. wihap_sta_timeout
  15. wihap_sta_delete
  16. wihap_sta_alloc
  17. wihap_sta_find
  18. wihap_check_rates
  19. wihap_auth_req
  20. wihap_assoc_req
  21. wihap_deauth_req
  22. wihap_disassoc_req
  23. wihap_debug_frame_type
  24. wihap_mgmt_input
  25. wihap_sta_is_assoc
  26. wihap_check_tx
  27. wihap_data_input
  28. wihap_ioctl
  29. wihap_init
  30. wihap_shutdown
  31. wihap_mgmt_input
  32. wihap_data_input
  33. wihap_ioctl
  34. wihap_check_tx

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

/* [<][>][^][v][top][bottom][index][help] */