]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/wtap/if_wtap.c
MFV r336851:
[FreeBSD/FreeBSD.git] / sys / dev / wtap / if_wtap.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2010-2011 Monthadar Al Jaberi, TerraNet AB
5  * All rights reserved.
6  *
7  * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer,
15  *    without modification.
16  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
18  *    redistribution must be conditioned upon including a substantially
19  *    similar Disclaimer requirement for further binary redistribution.
20  *
21  * NO WARRANTY
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
25  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
26  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
27  * OR 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
30  * IN 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 DAMAGES.
33  *
34  * $FreeBSD$
35  */
36 #include "if_wtapvar.h"
37 #include <sys/uio.h>    /* uio struct */
38 #include <sys/jail.h>
39 #include <net/if_var.h>
40 #include <net/vnet.h>
41
42 #include <net80211/ieee80211_ratectl.h>
43 #include "if_medium.h"
44
45 /*
46  * This _requires_ vimage to be useful.
47  */
48 #ifndef VIMAGE
49 #error  if_wtap requires VIMAGE.
50 #endif  /* VIMAGE */
51
52 /* device for IOCTL and read/write for debuggin purposes */
53 /* Function prototypes */
54 static  d_open_t        wtap_node_open;
55 static  d_close_t       wtap_node_close;
56 static  d_write_t       wtap_node_write;
57 static  d_ioctl_t       wtap_node_ioctl;
58
59 static struct cdevsw wtap_cdevsw = {
60         .d_version =    D_VERSION,
61         .d_flags =      0,
62         .d_open =       wtap_node_open,
63         .d_close =      wtap_node_close,
64         .d_write =      wtap_node_write,
65         .d_ioctl =      wtap_node_ioctl,
66         .d_name =       "wtapnode",
67 };
68
69 static int
70 wtap_node_open(struct cdev *dev, int oflags, int devtype, struct thread *p)
71 {
72
73         int err = 0;
74         uprintf("Opened device \"echo\" successfully.\n");
75         return(err);
76 }
77
78 static int
79 wtap_node_close(struct cdev *dev, int fflag, int devtype, struct thread *p)
80 {
81
82         uprintf("Closing device \"echo.\"\n");
83         return(0);
84 }
85
86 static int
87 wtap_node_write(struct cdev *dev, struct uio *uio, int ioflag)
88 {
89         int err = 0;
90         struct mbuf *m;
91         struct ifnet *ifp;
92         struct wtap_softc *sc;
93         uint8_t buf[1024];
94         int buf_len;
95
96         uprintf("write device %s \"echo.\"\n", devtoname(dev));
97         buf_len = MIN(uio->uio_iov->iov_len, 1024);
98         err = copyin(uio->uio_iov->iov_base, buf, buf_len);
99
100         if (err != 0) {
101                 uprintf("Write failed: bad address!\n");
102                 return (err);
103         }
104
105         MGETHDR(m, M_NOWAIT, MT_DATA);
106         m_copyback(m, 0, buf_len, buf);
107
108         CURVNET_SET(TD_TO_VNET(curthread));
109         IFNET_RLOCK_NOSLEEP();
110
111         CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
112                 printf("ifp->if_xname = %s\n", ifp->if_xname);
113                 if(strcmp(devtoname(dev), ifp->if_xname) == 0){
114                         printf("found match, correspoding wtap = %s\n",
115                             ifp->if_xname);
116                         sc = (struct wtap_softc *)ifp->if_softc;
117                         printf("wtap id = %d\n", sc->id);
118                         wtap_inject(sc, m);
119                 }
120         }
121
122         IFNET_RUNLOCK_NOSLEEP();
123         CURVNET_RESTORE();
124
125         return(err);
126 }
127
128 int
129 wtap_node_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
130     int fflag, struct thread *td)
131 {
132         int error = 0;
133
134         switch(cmd) {
135         default:
136                 DWTAP_PRINTF("Unknown WTAP IOCTL\n");
137                 error = EINVAL;
138         }
139         return error;
140 }
141
142 static int wtap_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
143         const struct ieee80211_bpf_params *params);
144
145 static int
146 wtap_medium_enqueue(struct wtap_vap *avp, struct mbuf *m)
147 {
148
149         return medium_transmit(avp->av_md, avp->id, m);
150 }
151
152 static int
153 wtap_media_change(struct ifnet *ifp)
154 {
155
156         DWTAP_PRINTF("%s\n", __func__);
157         int error = ieee80211_media_change(ifp);
158         /* NB: only the fixed rate can change and that doesn't need a reset */
159         return (error == ENETRESET ? 0 : error);
160 }
161
162 /*
163  * Intercept management frames to collect beacon rssi data
164  * and to do ibss merges.
165  */
166 static void
167 wtap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
168     int subtype, const struct ieee80211_rx_stats *stats, int rssi, int nf)
169 {
170         struct ieee80211vap *vap = ni->ni_vap;
171 #if 0
172         DWTAP_PRINTF("[%d] %s\n", myath_id(ni), __func__);
173 #endif
174         WTAP_VAP(vap)->av_recv_mgmt(ni, m, subtype, stats, rssi, nf);
175 }
176
177 static int
178 wtap_reset_vap(struct ieee80211vap *vap, u_long cmd)
179 {
180
181         DWTAP_PRINTF("%s\n", __func__);
182         return 0;
183 }
184
185 static void
186 wtap_beacon_update(struct ieee80211vap *vap, int item)
187 {
188         struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off;
189
190         DWTAP_PRINTF("%s\n", __func__);
191         setbit(bo->bo_flags, item);
192 }
193
194 /*
195  * Allocate and setup an initial beacon frame.
196  */
197 static int
198 wtap_beacon_alloc(struct wtap_softc *sc, struct ieee80211_node *ni)
199 {
200         struct ieee80211vap *vap = ni->ni_vap;
201         struct wtap_vap *avp = WTAP_VAP(vap);
202
203         DWTAP_PRINTF("[%s] %s\n", ether_sprintf(ni->ni_macaddr), __func__);
204
205         /*
206          * NB: the beacon data buffer must be 32-bit aligned;
207          * we assume the mbuf routines will return us something
208          * with this alignment (perhaps should assert).
209          */
210         avp->beacon = ieee80211_beacon_alloc(ni);
211         if (avp->beacon == NULL) {
212                 printf("%s: cannot get mbuf\n", __func__);
213                 return ENOMEM;
214         }
215         callout_init(&avp->av_swba, 0);
216         avp->bf_node = ieee80211_ref_node(ni);
217
218         return 0;
219 }
220
221 static void
222 wtap_beacon_config(struct wtap_softc *sc, struct ieee80211vap *vap)
223 {
224
225         DWTAP_PRINTF("%s\n", __func__);
226 }
227
228 static void
229 wtap_beacon_intrp(void *arg)
230 {
231         struct wtap_vap *avp = arg;
232         struct ieee80211vap *vap = arg;
233         struct mbuf *m;
234
235         if (vap->iv_state < IEEE80211_S_RUN) {
236             DWTAP_PRINTF("Skip beacon, not running, state %d", vap->iv_state);
237             return ;
238         }
239         DWTAP_PRINTF("[%d] beacon intrp\n", avp->id);   //burst mode
240         /*
241          * Update dynamic beacon contents.  If this returns
242          * non-zero then we need to remap the memory because
243          * the beacon frame changed size (probably because
244          * of the TIM bitmap).
245          */
246         m = m_dup(avp->beacon, M_NOWAIT);
247         if (ieee80211_beacon_update(avp->bf_node, m, 0)) {
248                 printf("%s, need to remap the memory because the beacon frame"
249                     " changed size.\n",__func__);
250         }
251
252         if (ieee80211_radiotap_active_vap(vap))
253             ieee80211_radiotap_tx(vap, m);
254
255 #if 0
256         medium_transmit(avp->av_md, avp->id, m);
257 #endif
258         wtap_medium_enqueue(avp, m);
259         callout_schedule(&avp->av_swba, avp->av_bcinterval);
260 }
261
262 static int
263 wtap_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
264 {
265         struct ieee80211com *ic = vap->iv_ic;
266         struct wtap_softc *sc = ic->ic_softc;
267         struct wtap_vap *avp = WTAP_VAP(vap);
268         struct ieee80211_node *ni = NULL;
269         int error;
270
271         DWTAP_PRINTF("%s\n", __func__);
272
273         ni = ieee80211_ref_node(vap->iv_bss);
274         /*
275          * Invoke the parent method to do net80211 work.
276          */
277         error = avp->av_newstate(vap, nstate, arg);
278         if (error != 0)
279                 goto bad;
280
281         if (nstate == IEEE80211_S_RUN) {
282                 /* NB: collect bss node again, it may have changed */
283                 ieee80211_free_node(ni);
284                 ni = ieee80211_ref_node(vap->iv_bss);
285                 switch (vap->iv_opmode) {
286                 case IEEE80211_M_MBSS:
287                         error = wtap_beacon_alloc(sc, ni);
288                         if (error != 0)
289                                 goto bad;
290                         wtap_beacon_config(sc, vap);
291                         callout_reset(&avp->av_swba, avp->av_bcinterval,
292                             wtap_beacon_intrp, vap);
293                         break;
294                 default:
295                         goto bad;
296                 }
297         } else if (nstate == IEEE80211_S_INIT) {
298                 callout_stop(&avp->av_swba);
299         }
300         ieee80211_free_node(ni);
301         return 0;
302 bad:
303         printf("%s: bad\n", __func__);
304         ieee80211_free_node(ni);
305         return error;
306 }
307
308 static void
309 wtap_bmiss(struct ieee80211vap *vap)
310 {
311         struct wtap_vap *avp = (struct wtap_vap *)vap;
312
313         DWTAP_PRINTF("%s\n", __func__);
314         avp->av_bmiss(vap);
315 }
316
317 static struct ieee80211vap *
318 wtap_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
319     int unit, enum ieee80211_opmode opmode, int flags,
320     const uint8_t bssid[IEEE80211_ADDR_LEN],
321     const uint8_t mac[IEEE80211_ADDR_LEN])
322 {
323          struct wtap_softc *sc = ic->ic_softc;
324          struct ieee80211vap *vap;
325          struct wtap_vap *avp;
326          int error;
327         struct ieee80211_node *ni;
328
329          DWTAP_PRINTF("%s\n", __func__);
330
331         avp = malloc(sizeof(struct wtap_vap), M_80211_VAP, M_WAITOK | M_ZERO);
332         avp->id = sc->id;
333         avp->av_md = sc->sc_md;
334         avp->av_bcinterval = msecs_to_ticks(BEACON_INTRERVAL + 100*sc->id);
335         vap = (struct ieee80211vap *) avp;
336         error = ieee80211_vap_setup(ic, vap, name, unit, IEEE80211_M_MBSS,
337             flags | IEEE80211_CLONE_NOBEACONS, bssid);
338         if (error) {
339                 free(avp, M_80211_VAP);
340                 return (NULL);
341         }
342
343         /* override various methods */
344         avp->av_recv_mgmt = vap->iv_recv_mgmt;
345         vap->iv_recv_mgmt = wtap_recv_mgmt;
346         vap->iv_reset = wtap_reset_vap;
347         vap->iv_update_beacon = wtap_beacon_update;
348         avp->av_newstate = vap->iv_newstate;
349         vap->iv_newstate = wtap_newstate;
350         avp->av_bmiss = vap->iv_bmiss;
351         vap->iv_bmiss = wtap_bmiss;
352
353         /* complete setup */
354         ieee80211_vap_attach(vap, wtap_media_change, ieee80211_media_status,
355             mac);
356         avp->av_dev = make_dev(&wtap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
357             "%s", (const char *)sc->name);
358
359         /* TODO this is a hack to force it to choose the rate we want */
360         ni = ieee80211_ref_node(vap->iv_bss);
361         ni->ni_txrate = 130;
362         ieee80211_free_node(ni);
363         return vap;
364 }
365
366 static void
367 wtap_vap_delete(struct ieee80211vap *vap)
368 {
369         struct wtap_vap *avp = WTAP_VAP(vap);
370
371         DWTAP_PRINTF("%s\n", __func__);
372         destroy_dev(avp->av_dev);
373         callout_stop(&avp->av_swba);
374         ieee80211_vap_detach(vap);
375         free((struct wtap_vap*) vap, M_80211_VAP);
376 }
377
378 static void
379 wtap_parent(struct ieee80211com *ic)
380 {
381         struct wtap_softc *sc = ic->ic_softc;
382
383         if (ic->ic_nrunning > 0) {
384                 sc->up = 1;
385                 ieee80211_start_all(ic);
386         } else
387                 sc->up = 0;
388 }
389
390 static void
391 wtap_scan_start(struct ieee80211com *ic)
392 {
393
394 #if 0
395         DWTAP_PRINTF("%s\n", __func__);
396 #endif
397 }
398
399 static void
400 wtap_scan_end(struct ieee80211com *ic)
401 {
402
403 #if 0
404         DWTAP_PRINTF("%s\n", __func__);
405 #endif
406 }
407
408 static void
409 wtap_set_channel(struct ieee80211com *ic)
410 {
411
412 #if 0
413         DWTAP_PRINTF("%s\n", __func__);
414 #endif
415 }
416
417 static int
418 wtap_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
419         const struct ieee80211_bpf_params *params)
420 {
421 #if 0
422         DWTAP_PRINTF("%s, %p\n", __func__, m);
423 #endif
424         struct ieee80211vap     *vap = ni->ni_vap;
425         struct wtap_vap         *avp = WTAP_VAP(vap);
426
427         if (ieee80211_radiotap_active_vap(vap)) {
428                 ieee80211_radiotap_tx(vap, m);
429         }
430         if (m->m_flags & M_TXCB)
431                 ieee80211_process_callback(ni, m, 0);
432         ieee80211_free_node(ni);
433         return wtap_medium_enqueue(avp, m);
434 }
435
436 void
437 wtap_inject(struct wtap_softc *sc, struct mbuf *m)
438 {
439       struct wtap_buf *bf = (struct wtap_buf *)malloc(sizeof(struct wtap_buf),
440           M_WTAP_RXBUF, M_NOWAIT | M_ZERO);
441       KASSERT(bf != NULL, ("could not allocated a new wtap_buf\n"));
442       bf->m = m;
443
444       mtx_lock(&sc->sc_mtx);
445       STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
446       taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask);
447       mtx_unlock(&sc->sc_mtx);
448 }
449
450 void
451 wtap_rx_deliver(struct wtap_softc *sc, struct mbuf *m)
452 {
453         struct ieee80211com *ic = &sc->sc_ic;
454         struct ieee80211_node *ni;
455         int type;
456 #if 0
457         DWTAP_PRINTF("%s\n", __func__);
458 #endif
459
460         DWTAP_PRINTF("[%d] receiving m=%p\n", sc->id, m);
461         if (m == NULL) {                /* NB: shouldn't happen */
462                 ic_printf(ic, "%s: no mbuf!\n", __func__);
463         }
464
465         ieee80211_dump_pkt(ic, mtod(m, caddr_t), 0,0,0);
466
467         /*
468           * Locate the node for sender, track state, and then
469           * pass the (referenced) node up to the 802.11 layer
470           * for its use.
471           */
472         ni = ieee80211_find_rxnode_withkey(ic,
473             mtod(m, const struct ieee80211_frame_min *),IEEE80211_KEYIX_NONE);
474         if (ni != NULL) {
475                 /*
476                  * Sending station is known, dispatch directly.
477                  */
478                 type = ieee80211_input(ni, m, 1<<7, 10);
479                 ieee80211_free_node(ni);
480         } else {
481                 type = ieee80211_input_all(ic, m, 1<<7, 10);
482         }
483 }
484
485 static void
486 wtap_rx_proc(void *arg, int npending)
487 {
488         struct wtap_softc *sc = (struct wtap_softc *)arg;
489         struct ieee80211com *ic = &sc->sc_ic;
490         struct mbuf *m;
491         struct ieee80211_node *ni;
492         int type;
493         struct wtap_buf *bf;
494
495 #if 0
496         DWTAP_PRINTF("%s\n", __func__);
497 #endif
498
499         for(;;) {
500                 mtx_lock(&sc->sc_mtx);
501                 bf = STAILQ_FIRST(&sc->sc_rxbuf);
502                 if (bf == NULL) {
503                         mtx_unlock(&sc->sc_mtx);
504                         return;
505                 }
506                 STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
507                 mtx_unlock(&sc->sc_mtx);
508                 KASSERT(bf != NULL, ("wtap_buf is NULL\n"));
509                 m = bf->m;
510                 DWTAP_PRINTF("[%d] receiving m=%p\n", sc->id, bf->m);
511                 if (m == NULL) {                /* NB: shouldn't happen */
512                         ic_printf(ic, "%s: no mbuf!\n", __func__);
513                         free(bf, M_WTAP_RXBUF);
514                         return;
515                 }
516 #if 0
517                 ieee80211_dump_pkt(ic, mtod(m, caddr_t), 0,0,0);
518 #endif
519
520                 /*
521                  * Locate the node for sender, track state, and then
522                  * pass the (referenced) node up to the 802.11 layer
523                  * for its use.
524                  */
525                 ni = ieee80211_find_rxnode_withkey(ic,
526                     mtod(m, const struct ieee80211_frame_min *),
527                     IEEE80211_KEYIX_NONE);
528                 if (ni != NULL) {
529                         /*
530                          * Sending station is known, dispatch directly.
531                          */
532                         type = ieee80211_input(ni, m, 1<<7, 10);
533                         ieee80211_free_node(ni);
534                 } else {
535                         type = ieee80211_input_all(ic, m, 1<<7, 10);
536                 }
537                 
538                 /* The mbufs are freed by the Net80211 stack */
539                 free(bf, M_WTAP_RXBUF);
540         }
541 }
542
543 static void
544 wtap_newassoc(struct ieee80211_node *ni, int isnew)
545 {
546
547         DWTAP_PRINTF("%s\n", __func__);
548 }
549
550 /*
551  * Callback from the 802.11 layer to update WME parameters.
552  */
553 static int
554 wtap_wme_update(struct ieee80211com *ic)
555 {
556
557         DWTAP_PRINTF("%s\n", __func__);
558         return 0;
559 }
560
561 static void
562 wtap_update_mcast(struct ieee80211com *ic)
563 {
564
565         DWTAP_PRINTF("%s\n", __func__);
566 }
567
568 static void
569 wtap_update_promisc(struct ieee80211com *ic)
570 {
571
572         DWTAP_PRINTF("%s\n", __func__);
573 }
574
575 static int
576 wtap_transmit(struct ieee80211com *ic, struct mbuf *m)
577 {
578         struct ieee80211_node *ni =
579             (struct ieee80211_node *) m->m_pkthdr.rcvif;
580         struct ieee80211vap *vap = ni->ni_vap;
581         struct wtap_vap *avp = WTAP_VAP(vap);
582
583         if(ni == NULL){
584                 printf("m->m_pkthdr.rcvif is NULL we cant radiotap_tx\n");
585         }else{
586                 if (ieee80211_radiotap_active_vap(vap))
587                         ieee80211_radiotap_tx(vap, m);
588         }
589         if (m->m_flags & M_TXCB)
590                 ieee80211_process_callback(ni, m, 0);
591         ieee80211_free_node(ni);
592         return wtap_medium_enqueue(avp, m);
593 }
594
595 static struct ieee80211_node *
596 wtap_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
597 {
598         struct ieee80211_node *ni;
599
600         DWTAP_PRINTF("%s\n", __func__);
601
602         ni = malloc(sizeof(struct ieee80211_node), M_80211_NODE,
603             M_NOWAIT|M_ZERO);
604
605         ni->ni_txrate = 130;
606         return ni;
607 }
608
609 static void
610 wtap_node_free(struct ieee80211_node *ni)
611 {
612         struct ieee80211com *ic = ni->ni_ic;
613         struct wtap_softc *sc = ic->ic_softc;
614
615         DWTAP_PRINTF("%s\n", __func__);
616         sc->sc_node_free(ni);
617 }
618
619 int32_t
620 wtap_attach(struct wtap_softc *sc, const uint8_t *macaddr)
621 {
622         struct ieee80211com *ic = &sc->sc_ic;
623
624         DWTAP_PRINTF("%s\n", __func__);
625
626         sc->up = 0;
627         STAILQ_INIT(&sc->sc_rxbuf);
628         sc->sc_tq = taskqueue_create("wtap_taskq", M_NOWAIT | M_ZERO,
629             taskqueue_thread_enqueue, &sc->sc_tq);
630         taskqueue_start_threads(&sc->sc_tq, 1, PI_SOFT, "%s taskQ", sc->name);
631         TASK_INIT(&sc->sc_rxtask, 0, wtap_rx_proc, sc);
632
633         ic->ic_softc = sc;
634         ic->ic_name = sc->name;
635         ic->ic_phytype = IEEE80211_T_DS;
636         ic->ic_opmode = IEEE80211_M_MBSS;
637         ic->ic_caps = IEEE80211_C_MBSS;
638
639         ic->ic_max_keyix = 128; /* A value read from Atheros ATH_KEYMAX */
640
641         ic->ic_regdomain.regdomain = SKU_ETSI;
642         ic->ic_regdomain.country = CTRY_SWEDEN;
643         ic->ic_regdomain.location = 1; /* Indoors */
644         ic->ic_regdomain.isocc[0] = 'S';
645         ic->ic_regdomain.isocc[1] = 'E';
646
647         ic->ic_nchans = 1;
648         ic->ic_channels[0].ic_flags = IEEE80211_CHAN_B;
649         ic->ic_channels[0].ic_freq = 2412;
650
651         IEEE80211_ADDR_COPY(ic->ic_macaddr, macaddr);
652         ieee80211_ifattach(ic);
653
654         /* override default methods */
655         ic->ic_newassoc = wtap_newassoc;
656         ic->ic_wme.wme_update = wtap_wme_update;
657         ic->ic_vap_create = wtap_vap_create;
658         ic->ic_vap_delete = wtap_vap_delete;
659         ic->ic_raw_xmit = wtap_raw_xmit;
660         ic->ic_update_mcast = wtap_update_mcast;
661         ic->ic_update_promisc = wtap_update_promisc;
662         ic->ic_transmit = wtap_transmit;
663         ic->ic_parent = wtap_parent;
664
665         sc->sc_node_alloc = ic->ic_node_alloc;
666         ic->ic_node_alloc = wtap_node_alloc;
667         sc->sc_node_free = ic->ic_node_free;
668         ic->ic_node_free = wtap_node_free;
669
670         ic->ic_scan_start = wtap_scan_start;
671         ic->ic_scan_end = wtap_scan_end;
672         ic->ic_set_channel = wtap_set_channel;
673
674         ieee80211_radiotap_attach(ic,
675             &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
676             WTAP_TX_RADIOTAP_PRESENT,
677             &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
678             WTAP_RX_RADIOTAP_PRESENT);
679
680         /* Work here, we must find a way to populate the rate table */
681 #if 0
682         if(ic->ic_rt == NULL){
683                 printf("no table for ic_curchan\n");
684                 ic->ic_rt = ieee80211_get_ratetable(&ic->ic_channels[0]);
685         }
686         printf("ic->ic_rt =%p\n", ic->ic_rt);
687         printf("rate count %d\n", ic->ic_rt->rateCount);
688
689         uint8_t code = ic->ic_rt->info[0].dot11Rate;
690         uint8_t cix = ic->ic_rt->info[0].ctlRateIndex;
691         uint8_t ctl_rate = ic->ic_rt->info[cix].dot11Rate;
692         printf("code=%d, cix=%d, ctl_rate=%d\n", code, cix, ctl_rate);
693
694         uint8_t rix0 = ic->ic_rt->rateCodeToIndex[130];
695         uint8_t rix1 = ic->ic_rt->rateCodeToIndex[132];
696         uint8_t rix2 = ic->ic_rt->rateCodeToIndex[139];
697         uint8_t rix3 = ic->ic_rt->rateCodeToIndex[150];
698         printf("rix0 %u,rix1 %u,rix2 %u,rix3 %u\n", rix0,rix1,rix2,rix3);
699         printf("lpAckDuration=%u\n", ic->ic_rt->info[0].lpAckDuration);
700         printf("rate=%d\n", ic->ic_rt->info[0].rateKbps);
701 #endif
702         return 0;
703 }
704
705 int32_t
706 wtap_detach(struct wtap_softc *sc)
707 {
708         struct ieee80211com *ic = &sc->sc_ic;
709
710         DWTAP_PRINTF("%s\n", __func__);
711         ieee80211_ageq_drain(&ic->ic_stageq);
712         ieee80211_ifdetach(ic);
713         return 0;
714 }
715
716 void
717 wtap_resume(struct wtap_softc *sc)
718 {
719
720         DWTAP_PRINTF("%s\n", __func__);
721 }
722
723 void
724 wtap_suspend(struct wtap_softc *sc)
725 {
726
727         DWTAP_PRINTF("%s\n", __func__);
728 }
729
730 void
731 wtap_shutdown(struct wtap_softc *sc)
732 {
733
734         DWTAP_PRINTF("%s\n", __func__);
735 }
736
737 void
738 wtap_intr(struct wtap_softc *sc)
739 {
740
741         DWTAP_PRINTF("%s\n", __func__);
742 }