LCOV - code coverage report
Current view: top level - dev/ic - if_wi_hostap.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 640 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 28 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13