~ubuntu-branches/ubuntu/raring/bcmwl/raring

« back to all changes in this revision

Viewing changes to src/src/wl/sys/wl_linux.c

  • Committer: Package Import Robot
  • Author(s): Alberto Milone
  • Date: 2012-06-20 13:30:20 UTC
  • mfrom: (2.1.5)
  • Revision ID: package-import@ubuntu.com-20120620133020-gg9dqv39dy32ovbh
Tags: 5.100.82.112+bdcom-0ubuntu1
* New upstream release:
  - Add Monitor mode.
  - Add cfg80211 API support. The choice of API is
    done at compile time. If kernel version >= 2.6.32,
    cfg80211 is used, otherwise wireless extension
    is used. (End users should notice little
    difference.)
  - Fix problem with triggered a reboot when the
    wireless was disabled using the function key.
  - Fix a kernel panic observed on some 64-bit
    systems.

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
11
11
 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12
12
 *
13
 
 * $Id: wl_linux.c,v 1.524.2.40.2.12 2010/12/08 23:33:57 Exp $
 
13
 * $Id: wl_linux.c,v 1.524.2.40.2.15 2011-02-09 02:28:28 Exp $
14
14
 */
15
15
 
16
16
#define LINUX_PORT
65
65
 
66
66
#include <wlc_pub.h>
67
67
#include <wl_dbg.h>
 
68
#include <wlc_ethereal.h>
 
69
#include <proto/ieee80211_radiotap.h>
68
70
 
69
 
#undef USE_IW
70
 
#if defined(CONFIG_WIRELESS_EXT)
71
 
#define USE_IW
72
 
#endif
73
 
#ifdef USE_IW
74
71
#include <wl_iw.h>
 
72
#ifdef USE_IW
75
73
struct iw_statistics *wl_get_wireless_stats(struct net_device *dev);
76
74
#endif
77
75
 
82
80
#ifdef WL_THREAD
83
81
#include <linux/kthread.h>
84
82
#endif 
 
83
 
 
84
#if defined(USE_CFG80211)
 
85
#include <wl_cfg80211.h>
 
86
#endif
 
87
 
85
88
static void wl_timer(ulong data);
86
89
static void _wl_timer(wl_timer_t *t);
87
90
 
 
91
static int wl_monitor_start(struct sk_buff *skb, struct net_device *dev);
 
92
 
88
93
#ifdef WL_ALL_PASSIVE
89
94
static void wl_start_txqwork(struct wl_task *task);
90
95
static void wl_txq_free(wl_info_t *wl);
99
104
 
100
105
#endif 
101
106
 
 
107
static int wl_reg_proc_entry(wl_info_t *wl);
 
108
 
102
109
static int wl_linux_watchdog(void *ctx);
103
110
static
104
111
int wl_found = 0;
159
166
#endif 
160
167
static void wl_link_up(wl_info_t *wl, char * ifname);
161
168
static void wl_link_down(wl_info_t *wl, char *ifname);
 
169
static int wl_schedule_task(wl_info_t *wl, void (*fn)(struct wl_task *), void *context);
162
170
#ifdef WL_THREAD
163
171
static int wl_start_enqueue_wlthread(wl_info_t *wl, struct sk_buff *skb);
164
172
#endif 
165
 
#if defined(CONFIG_PROC_FS)
166
 
static int wl_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
167
 
#endif 
168
173
#if defined(BCMDBG)
169
174
static int wl_dump(wl_info_t *wl, struct bcmstrbuf *b);
170
175
#endif 
268
273
#define IEEE80211_RADIOTAP_HTMOD_STBC_MASK      0x30
269
274
#define IEEE80211_RADIOTAP_HTMOD_STBC_SHIFT     4
270
275
 
 
276
struct wl_radiotap_legacy {
 
277
        struct ieee80211_radiotap_header        ieee_radiotap;
 
278
        uint32       tsft_h;
 
279
        uint32       tsft_l;
 
280
        uint8        flags;
 
281
        uint8        rate;
 
282
        uint16       channel_freq;
 
283
        uint16       channel_flags;
 
284
        uint8        signal;
 
285
        uint8        noise;
 
286
        uint8        antenna;
 
287
} __attribute__((__packed__));
 
288
 
 
289
struct wl_radiotap_ht {
 
290
        struct ieee80211_radiotap_header        ieee_radiotap;
 
291
        uint32_t                                it_present_ext;
 
292
        uint32_t        pad1;
 
293
        uint32          tsft_h;
 
294
        uint32          tsft_l;
 
295
        u_int8_t        flags;
 
296
        u_int8_t        pad2;
 
297
        u_int16_t       channel_freq;
 
298
        u_int16_t       channel_flags;
 
299
        u_int8_t        signal;
 
300
        u_int8_t        noise;
 
301
        u_int8_t        antenna;
 
302
        u_int8_t        pad3;
 
303
        u_int8_t        vend_oui[3];
 
304
        u_int8_t        vend_sns;
 
305
        u_int16_t       vend_skip_len;
 
306
        u_int8_t        mcs;
 
307
        u_int8_t        htflags;
 
308
} __attribute__((packed));
 
309
 
 
310
#define WL_RADIOTAP_PRESENT_LEGACY                      \
 
311
        ((1 << IEEE80211_RADIOTAP_TSFT) |               \
 
312
         (1 << IEEE80211_RADIOTAP_RATE) |               \
 
313
         (1 << IEEE80211_RADIOTAP_CHANNEL) |            \
 
314
         (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |      \
 
315
         (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |       \
 
316
         (1 << IEEE80211_RADIOTAP_FLAGS) |              \
 
317
         (1 << IEEE80211_RADIOTAP_ANTENNA))
 
318
 
 
319
#define WL_RADIOTAP_PRESENT_HT                          \
 
320
        ((1 << IEEE80211_RADIOTAP_TSFT) |               \
 
321
         (1 << IEEE80211_RADIOTAP_FLAGS) |              \
 
322
         (1 << IEEE80211_RADIOTAP_CHANNEL) |            \
 
323
         (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |      \
 
324
         (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |       \
 
325
         (1 << IEEE80211_RADIOTAP_ANTENNA) |            \
 
326
         (1 << IEEE80211_RADIOTAP_VENDOR_NAMESPACE) |   \
 
327
         (1 << IEEE80211_RADIOTAP_EXT))
 
328
 
 
329
#ifndef ARPHRD_IEEE80211_RADIOTAP
 
330
#define ARPHRD_IEEE80211_RADIOTAP 803
 
331
#endif
 
332
 
271
333
#ifndef SRCBASE
272
334
#define SRCBASE "."
273
335
#endif
327
389
        .ndo_do_ioctl = wl_ioctl
328
390
};
329
391
 
 
392
static const struct net_device_ops wl_netdev_monitor_ops =
 
393
{
 
394
        .ndo_start_xmit = wl_monitor_start,
 
395
        .ndo_get_stats = wl_get_stats,
 
396
        .ndo_do_ioctl = wl_ioctl
 
397
};
330
398
#endif 
331
399
 
332
400
static
371
439
#if WIRELESS_EXT > 12
372
440
        dev->wireless_handlers = (struct iw_handler_def *) &wl_iw_handler_def;
373
441
#endif
374
 
#endif 
375
 
 
376
442
#if WIRELESS_EXT >= 19 || LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
377
443
        dev->ethtool_ops = &wl_ethtool_ops;
378
444
#endif
 
445
#endif 
 
446
 
 
447
#if defined(USE_CFG80211) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
 
448
        dev->ethtool_ops = &wl_ethtool_ops;
 
449
#endif 
 
450
 
379
451
}
380
452
 
381
453
static wl_info_t *
384
456
        struct net_device *dev;
385
457
        wl_if_t *wlif;
386
458
        wl_info_t *wl;
387
 
#if defined(CONFIG_PROC_FS)
388
 
        char tmp[128];
389
 
#endif
390
459
        osl_t *osh;
391
460
        int unit, err;
 
461
#if defined(USE_CFG80211)
 
462
        struct device *parentdev;
 
463
#endif
392
464
 
393
465
        unit = wl_found + instance_base;
394
466
        err = 0;
482
554
#ifdef WL_ALL_PASSIVE
483
555
                spin_lock_init(&wl->txq_lock);
484
556
#endif 
485
 
                init_MUTEX(&wl->sem);
 
557
                sema_init(&wl->sem, 1);
486
558
        }
487
559
 
488
560
        if (!(wl->wlc = wlc_attach((void *) wl, vendor, device, unit, wl->piomode,
502
574
 
503
575
        wlc_iovar_setint(wl->wlc, "qtxpower", 23 * 4);
504
576
 
505
 
#if defined(CONFIG_PROC_FS)
506
 
 
507
 
        sprintf(tmp, "net/wl%d", wl->pub->unit);
508
 
        create_proc_read_entry(tmp, 0, 0, wl_read_proc, (void*)wl);
509
 
#endif
510
 
 
511
577
#ifdef BCMDBG
512
578
        if (macaddr != NULL) {  
513
579
                int err;
536
602
                dev->irq = irq;
537
603
        }
538
604
 
 
605
#if defined(USE_IW)
 
606
        WL_ERROR(("Using Wireless Extension\n"));
 
607
#endif
 
608
 
 
609
#if defined(USE_CFG80211)
 
610
        parentdev = NULL;
 
611
        if (wl->bcm_bustype == PCI_BUS) {
 
612
                parentdev = &((struct pci_dev *)btparam)->dev;
 
613
        }
 
614
        if (parentdev) {
 
615
                if (wl_cfg80211_attach(dev, parentdev)) {
 
616
                        goto fail;
 
617
                }
 
618
        }
 
619
        else {
 
620
                WL_ERROR(("unsupported bus type\n"));
 
621
                goto fail;
 
622
        }
 
623
#else
539
624
        if (wl->bcm_bustype == PCI_BUS) {
540
625
                struct pci_dev *pci_dev = (struct pci_dev *)btparam;
541
626
                if (pci_dev != NULL)
542
627
                        SET_NETDEV_DEV(dev, &pci_dev->dev);
543
628
        }
 
629
#endif 
544
630
 
545
631
        if (register_netdev(dev)) {
546
632
                WL_ERROR(("wl%d: register_netdev() failed\n", unit));
610
696
        wlc_dump_register(wl->pub, "wl", (dump_fn_t)wl_dump, (void *)wl);
611
697
#endif
612
698
 
 
699
        wl_reg_proc_entry(wl);
 
700
 
613
701
        printf("%s: Broadcom BCM%04x 802.11 Hybrid Wireless Controller " EPI_VERSION_STR,
614
702
                dev->name, device);
615
703
 
626
714
        return NULL;
627
715
}
628
716
 
629
 
#if defined(CONFIG_PROC_FS)
630
 
static int
631
 
wl_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
632
 
{
633
 
        wl_info_t *wl;
634
 
        int len;
635
 
        off_t pos;
636
 
        off_t begin;
637
 
 
638
 
        len = pos = begin = 0;
639
 
 
640
 
        wl = (wl_info_t*) data;
641
 
 
642
 
        WL_LOCK(wl);
643
 
 
644
 
#if defined(BCMDBG)
645
 
        wlc_iovar_dump(wl->wlc, "all", strlen("all") + 1, buffer, PAGE_SIZE);
646
 
        len = strlen(buffer);
647
 
#endif 
648
 
        WL_UNLOCK(wl);
649
 
        pos = begin + len;
650
 
 
651
 
        if (pos < offset) {
652
 
                len = 0;
653
 
                begin = pos;
654
 
        }
655
 
 
656
 
        *eof = 1;
657
 
 
658
 
        *start = buffer + (offset - begin);
659
 
        len -= (offset - begin);
660
 
 
661
 
        if (len > length)
662
 
                len = length;
663
 
 
664
 
        return (len);
665
 
}
666
 
#endif 
667
 
 
668
717
static void __devexit wl_remove(struct pci_dev *pdev);
669
718
 
670
719
int __devinit
908
957
        }
909
958
 
910
959
        if (wl->wlc) {
911
 
#if defined(CONFIG_PROC_FS)
912
 
                char tmp[128];
913
 
 
914
 
                sprintf(tmp, "net/wl%d", wl->pub->unit);
915
 
                remove_proc_entry(tmp, 0);
916
 
#endif 
 
960
 
 
961
                {
 
962
                char tmp1[128];
 
963
                sprintf(tmp1, "%s%d", HYBRID_PROC, wl->pub->unit);
 
964
                remove_proc_entry(tmp1, 0);
 
965
                }
 
966
 
917
967
                wlc_detach(wl->wlc);
918
968
                wl->wlc = NULL;
919
969
                wl->pub = NULL;
1002
1052
        if (!error)
1003
1053
                OLD_MOD_INC_USE_COUNT;
1004
1054
 
 
1055
#if defined(USE_CFG80211)
 
1056
        if (wl_cfg80211_up(dev)) {
 
1057
                WL_ERROR(("%s: failed to bring up cfg80211\n", __func__));
 
1058
                return -1;
 
1059
        }
 
1060
#endif
 
1061
 
1005
1062
        return (error? -ENODEV: 0);
1006
1063
}
1007
1064
 
1013
1070
        if (!dev)
1014
1071
                return -ENETDOWN;
1015
1072
 
 
1073
#if defined(USE_CFG80211)
 
1074
        wl_cfg80211_down(dev);
 
1075
#endif
 
1076
 
1016
1077
        wl = WL_INFO(dev);
1017
1078
 
1018
1079
        WL_TRACE(("wl%d: wl_close\n", wl->pub->unit));
1073
1134
                netif_wake_queue(dev);
1074
1135
}
1075
1136
 
1076
 
#if defined(WL_ALL_PASSIVE)
1077
 
 
1078
1137
static int
1079
1138
wl_schedule_task(wl_info_t *wl, void (*fn)(struct wl_task *task), void *context)
1080
1139
{
1101
1160
 
1102
1161
        return 0;
1103
1162
}
1104
 
#endif 
1105
1163
 
1106
1164
static struct wl_if *
1107
1165
wl_alloc_if(wl_info_t *wl, int iftype, uint subunit, struct wlc_if* wlcif)
1150
1208
        wlif->wl = wl;
1151
1209
        wlif->wlcif = wlcif;
1152
1210
        wlif->subunit = subunit;
 
1211
        wlif->if_type = iftype;
1153
1212
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
1154
1213
        dev->priv = wlif;
1155
1214
#endif
1177
1236
                unregister_netdev(wlif->dev);
1178
1237
        }
1179
1238
 
 
1239
#if defined(USE_CFG80211)
 
1240
        if (wlif->if_type != WL_IFTYPE_MON)
 
1241
                wl_cfg80211_detach(wlif->dev);
 
1242
#endif
 
1243
 
1180
1244
        p = wl->if_list;
1181
1245
        if (p == wlif)
1182
1246
                wl->if_list = p->next;
1300
1364
wl_down(wl_info_t *wl)
1301
1365
{
1302
1366
        wl_if_t *wlif;
 
1367
        int monitor = 0;
1303
1368
        uint callbacks, ret_val = 0;
1304
1369
 
1305
1370
        WL_TRACE(("wl%d: wl_down\n", wl->pub->unit));
1309
1374
                netif_stop_queue(wlif->dev);
1310
1375
        }
1311
1376
 
 
1377
        if (wl->monitor_dev) {
 
1378
                ret_val = wlc_ioctl(wl->wlc, WLC_SET_MONITOR, &monitor, sizeof(int), NULL);
 
1379
                if (ret_val != BCME_OK) {
 
1380
                        WL_ERROR(("%s: Disabling MONITOR failed %d\n", __FUNCTION__, ret_val));
 
1381
                }
 
1382
        }
 
1383
 
1312
1384
        ret_val = wlc_down(wl->wlc);
1313
1385
        callbacks = atomic_read(&wl->callbacks) - ret_val;
1314
1386
 
2025
2097
        wl_iw_event(wl->dev, &(e->event), e->data);
2026
2098
#endif 
2027
2099
 
 
2100
#if defined(USE_CFG80211)
 
2101
        wl_cfg80211_event(wl->dev, &(e->event), e->data);
 
2102
#endif
 
2103
 
2028
2104
        switch (e->event.event_type) {
2029
2105
        case WLC_E_LINK:
2030
2106
        case WLC_E_NDIS_LINK:
2345
2421
void
2346
2422
wl_monitor(wl_info_t *wl, wl_rxsts_t *rxsts, void *p)
2347
2423
{
 
2424
        struct sk_buff *oskb = (struct sk_buff *)p;
 
2425
        struct sk_buff *skb;
 
2426
        uchar *pdata;
 
2427
        uint len;
 
2428
 
 
2429
        len = 0;
 
2430
        skb = NULL;
 
2431
        WL_TRACE(("wl%d: wl_monitor\n", wl->pub->unit));
 
2432
 
 
2433
        if (!wl->monitor_dev)
 
2434
                return;
 
2435
 
 
2436
        if (wl->monitor_type == ARPHRD_IEEE80211_PRISM) {
 
2437
                p80211msg_t *phdr;
 
2438
 
 
2439
                len = sizeof(p80211msg_t) + oskb->len - D11_PHY_HDR_LEN;
 
2440
                if ((skb = dev_alloc_skb(len)) == NULL)
 
2441
                        return;
 
2442
 
 
2443
                skb_put(skb, len);
 
2444
                phdr = (p80211msg_t*)skb->data;
 
2445
 
 
2446
                phdr->msgcode = WL_MON_FRAME;
 
2447
                phdr->msglen = sizeof(p80211msg_t);
 
2448
                strcpy(phdr->devname, wl->dev->name);
 
2449
 
 
2450
                phdr->hosttime.did = WL_MON_FRAME_HOSTTIME;
 
2451
                phdr->hosttime.status = P80211ITEM_OK;
 
2452
                phdr->hosttime.len = 4;
 
2453
                phdr->hosttime.data = jiffies;
 
2454
 
 
2455
                phdr->channel.did = WL_MON_FRAME_CHANNEL;
 
2456
                phdr->channel.status = P80211ITEM_NO_VALUE;
 
2457
                phdr->channel.len = 4;
 
2458
                phdr->channel.data = 0;
 
2459
 
 
2460
                phdr->signal.did = WL_MON_FRAME_SIGNAL;
 
2461
                phdr->signal.status = P80211ITEM_OK;
 
2462
                phdr->signal.len = 4;
 
2463
 
 
2464
                phdr->signal.data = rxsts->preamble;
 
2465
 
 
2466
                phdr->noise.did = WL_MON_FRAME_NOISE;
 
2467
                phdr->noise.status = P80211ITEM_NO_VALUE;
 
2468
                phdr->noise.len = 4;
 
2469
                phdr->noise.data = 0;
 
2470
 
 
2471
                phdr->rate.did = WL_MON_FRAME_RATE;
 
2472
                phdr->rate.status = P80211ITEM_OK;
 
2473
                phdr->rate.len = 4;
 
2474
                phdr->rate.data = rxsts->datarate;
 
2475
 
 
2476
                phdr->istx.did = WL_MON_FRAME_ISTX;
 
2477
                phdr->istx.status = P80211ITEM_NO_VALUE;
 
2478
                phdr->istx.len = 4;
 
2479
                phdr->istx.data = 0;
 
2480
 
 
2481
                phdr->mactime.did = WL_MON_FRAME_MACTIME;
 
2482
                phdr->mactime.status = P80211ITEM_OK;
 
2483
                phdr->mactime.len = 4;
 
2484
                phdr->mactime.data = rxsts->mactime;
 
2485
 
 
2486
                phdr->rssi.did = WL_MON_FRAME_RSSI;
 
2487
                phdr->rssi.status = P80211ITEM_OK;
 
2488
                phdr->rssi.len = 4;
 
2489
                phdr->rssi.data = rxsts->signal;                
 
2490
 
 
2491
                phdr->sq.did = WL_MON_FRAME_SQ;
 
2492
                phdr->sq.status = P80211ITEM_OK;
 
2493
                phdr->sq.len = 4;
 
2494
                phdr->sq.data = rxsts->sq;
 
2495
 
 
2496
                phdr->frmlen.did = WL_MON_FRAME_FRMLEN;
 
2497
                phdr->frmlen.status = P80211ITEM_OK;
 
2498
                phdr->frmlen.status = P80211ITEM_OK;
 
2499
                phdr->frmlen.len = 4;
 
2500
                phdr->frmlen.data = rxsts->pktlength;
 
2501
 
 
2502
                pdata = skb->data + sizeof(p80211msg_t);
 
2503
                bcopy(oskb->data + D11_PHY_HDR_LEN, pdata, oskb->len - D11_PHY_HDR_LEN);
 
2504
 
 
2505
        } else if (wl->monitor_type == ARPHRD_IEEE80211_RADIOTAP) {
 
2506
                int channel_frequency;
 
2507
                uint16 channel_flags;
 
2508
                uint8 flags;
 
2509
                uint16 rtap_len;
 
2510
                struct dot11_header * mac_header;
 
2511
                uint16 fc;
 
2512
 
 
2513
                if (rxsts->datarate != 0)
 
2514
                        rtap_len = sizeof(struct wl_radiotap_legacy);
 
2515
                else
 
2516
                        rtap_len = sizeof(struct wl_radiotap_ht);
 
2517
 
 
2518
                len = rtap_len + (oskb->len - D11_PHY_HDR_LEN);
 
2519
                if ((skb = dev_alloc_skb(len)) == NULL)
 
2520
                        return;
 
2521
 
 
2522
                skb_put(skb, len);
 
2523
 
 
2524
                if (CHSPEC_IS2G(rxsts->chanspec)) {
 
2525
                        channel_flags = IEEE80211_CHAN_2GHZ;
 
2526
                        channel_frequency = wf_channel2mhz(CHSPEC_CHANNEL(rxsts->chanspec),
 
2527
                                                           WF_CHAN_FACTOR_2_4_G);
 
2528
                } else {
 
2529
                        channel_flags = IEEE80211_CHAN_5GHZ;
 
2530
                        channel_frequency = wf_channel2mhz(CHSPEC_CHANNEL(rxsts->chanspec),
 
2531
                                                           WF_CHAN_FACTOR_5_G);
 
2532
                }
 
2533
 
 
2534
                mac_header = (struct dot11_header *)(oskb->data + D11_PHY_HDR_LEN);
 
2535
                fc = ntoh16(mac_header->fc);
 
2536
 
 
2537
                flags = IEEE80211_RADIOTAP_F_FCS;
 
2538
 
 
2539
                if (rxsts->preamble == WL_RXS_PREAMBLE_SHORT)
 
2540
                        flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
 
2541
 
 
2542
                if (fc & (FC_WEP >> FC_WEP_SHIFT))
 
2543
                        flags |= IEEE80211_RADIOTAP_F_WEP;
 
2544
 
 
2545
                if (fc & (FC_MOREFRAG >> FC_MOREFRAG_SHIFT))
 
2546
                        flags |= IEEE80211_RADIOTAP_F_FRAG;
 
2547
 
 
2548
                if (rxsts->pkterror & WL_RXS_CRC_ERROR)
 
2549
                        flags |= IEEE80211_RADIOTAP_F_BADFCS;
 
2550
 
 
2551
                if (rxsts->datarate != 0) {
 
2552
                        struct wl_radiotap_legacy *rtl = (struct wl_radiotap_legacy*)skb->data;
 
2553
 
 
2554
                        rtl->ieee_radiotap.it_version = 0;
 
2555
                        rtl->ieee_radiotap.it_pad = 0;
 
2556
                        rtl->ieee_radiotap.it_len = HTOL16(rtap_len);
 
2557
                        rtl->ieee_radiotap.it_present = HTOL32(WL_RADIOTAP_PRESENT_LEGACY);
 
2558
 
 
2559
                        rtl->tsft_l = htol32(rxsts->mactime);
 
2560
                        rtl->flags = flags;
 
2561
                        rtl->rate = rxsts->datarate;
 
2562
                        rtl->channel_freq = HTOL16(channel_frequency);
 
2563
                        rtl->channel_flags = HTOL16(channel_flags);
 
2564
                        rtl->signal = (int8)rxsts->signal;
 
2565
                        rtl->noise = (int8)rxsts->noise;
 
2566
                        rtl->antenna = rxsts->antenna;
 
2567
                } else {
 
2568
                        struct wl_radiotap_ht *rtht = (struct wl_radiotap_ht*)skb->data;
 
2569
 
 
2570
                        rtht->ieee_radiotap.it_version = 0;
 
2571
                        rtht->ieee_radiotap.it_pad = 0;
 
2572
                        rtht->ieee_radiotap.it_len = HTOL16(rtap_len);
 
2573
                        rtht->ieee_radiotap.it_present = HTOL32(WL_RADIOTAP_PRESENT_HT);
 
2574
                        rtht->it_present_ext = HTOL32(WL_RADIOTAP_BRCM_MCS);
 
2575
 
 
2576
                        rtht->pad1 = 0;
 
2577
                        rtht->tsft_l = htol32(rxsts->mactime);
 
2578
                        rtht->flags = flags;
 
2579
                        rtht->pad2 = 0;
 
2580
                        rtht->channel_freq = HTOL16(channel_frequency);
 
2581
                        rtht->channel_flags = HTOL16(channel_flags);
 
2582
                        rtht->signal = (int8)rxsts->signal;
 
2583
                        rtht->noise = (int8)rxsts->noise;
 
2584
                        rtht->antenna = rxsts->antenna;
 
2585
 
 
2586
                        rtht->pad3 = 0;
 
2587
                        memcpy(rtht->vend_oui, "\x00\x10\x18", 3);
 
2588
                        rtht->vend_sns = WL_RADIOTAP_BRCM_SNS;
 
2589
                        rtht->vend_skip_len = 2;
 
2590
 
 
2591
                        rtht->mcs = rxsts->mcs;
 
2592
                        rtht->htflags = 0;
 
2593
                        if (rxsts->htflags & WL_RXS_HTF_40)
 
2594
                                   rtht->htflags |= IEEE80211_RADIOTAP_HTMOD_40;
 
2595
                        if (rxsts->htflags & WL_RXS_HTF_SGI)
 
2596
                                   rtht->htflags |= IEEE80211_RADIOTAP_HTMOD_SGI;
 
2597
                        if (rxsts->preamble & WL_RXS_PREAMBLE_HT_GF)
 
2598
                                   rtht->htflags |= IEEE80211_RADIOTAP_HTMOD_GF;
 
2599
                        if (rxsts->htflags & WL_RXS_HTF_LDPC)
 
2600
                                   rtht->htflags |= IEEE80211_RADIOTAP_HTMOD_LDPC;
 
2601
                        rtht->htflags |=
 
2602
                                (rxsts->htflags & WL_RXS_HTF_STBC_MASK) <<
 
2603
                                IEEE80211_RADIOTAP_HTMOD_STBC_SHIFT;
 
2604
                }
 
2605
 
 
2606
                pdata = skb->data + rtap_len;
 
2607
                bcopy(oskb->data + D11_PHY_HDR_LEN, pdata, oskb->len - D11_PHY_HDR_LEN);
 
2608
        }
 
2609
 
 
2610
        skb->dev = wl->monitor_dev;
 
2611
        skb->dev->last_rx = jiffies;
 
2612
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
 
2613
        skb_reset_mac_header(skb);
 
2614
#else
 
2615
        skb->mac.raw = skb->data;
 
2616
#endif
 
2617
        skb->ip_summed = CHECKSUM_NONE;
 
2618
        skb->pkt_type = PACKET_OTHERHOST;
 
2619
        skb->protocol = htons(ETH_P_80211_RAW);
 
2620
 
 
2621
#ifdef NAPI_POLL
 
2622
        netif_receive_skb(skb);
 
2623
#else 
 
2624
        netif_rx(skb);
 
2625
#endif 
 
2626
}
 
2627
 
 
2628
static int
 
2629
wl_monitor_start(struct sk_buff *skb, struct net_device *dev)
 
2630
{
 
2631
        wl_info_t *wl;
 
2632
 
 
2633
        wl = WL_DEV_IF(dev)->wl;
 
2634
        PKTFREE(wl->osh, skb, FALSE);
 
2635
        return 0;
 
2636
}
 
2637
 
 
2638
static void
 
2639
wl_add_monitor(wl_task_t *task)
 
2640
{
 
2641
        wl_info_t *wl = (wl_info_t *) task->context;
 
2642
        struct net_device *dev;
 
2643
        wl_if_t *wlif;
 
2644
 
 
2645
        ASSERT(wl);
 
2646
        WL_LOCK(wl);
 
2647
        WL_TRACE(("wl%d: wl_add_monitor\n", wl->pub->unit));
 
2648
 
 
2649
        if (wl->monitor_dev)
 
2650
                goto done;
 
2651
 
 
2652
        wlif = wl_alloc_if(wl, WL_IFTYPE_MON, wl->pub->unit, NULL);
 
2653
        if (!wlif) {
 
2654
                WL_ERROR(("wl%d: wl_add_monitor: alloc wlif failed\n", wl->pub->unit));
 
2655
                goto done;
 
2656
        }
 
2657
 
 
2658
        dev = wlif->dev;
 
2659
        wl->monitor_dev = dev;
 
2660
 
 
2661
        bcopy(wl->dev->dev_addr, dev->dev_addr, ETHER_ADDR_LEN);
 
2662
        dev->flags = wl->dev->flags;
 
2663
        dev->type = wl->monitor_type;
 
2664
        if (wl->monitor_type == ARPHRD_IEEE80211_PRISM) {
 
2665
                sprintf(dev->name, "prism%d", wl->pub->unit);
 
2666
        } else {
 
2667
                sprintf(dev->name, "radiotap%d", wl->pub->unit);
 
2668
        }
 
2669
 
 
2670
#if defined(WL_USE_NETDEV_OPS)
 
2671
        dev->netdev_ops = &wl_netdev_monitor_ops;
 
2672
#else
 
2673
        dev->hard_start_xmit = wl_monitor_start;
 
2674
        dev->do_ioctl = wl_ioctl;
 
2675
        dev->get_stats = wl_get_stats;
 
2676
#endif 
 
2677
 
 
2678
        WL_UNLOCK(wl);
 
2679
        if (register_netdev(dev)) {
 
2680
                WL_ERROR(("wl%d: wl_add_monitor, register_netdev failed for \"%s\"\n",
 
2681
                        wl->pub->unit, wl->monitor_dev->name));
 
2682
                wl->monitor_dev = NULL;
 
2683
                wl_free_if(wl, wlif);
 
2684
        } else
 
2685
                wlif->dev_registed = TRUE;
 
2686
        WL_LOCK(wl);
 
2687
done:
 
2688
        MFREE(wl->osh, task, sizeof(wl_task_t));
 
2689
        atomic_dec(&wl->callbacks);
 
2690
        WL_UNLOCK(wl);
 
2691
}
 
2692
 
 
2693
static void
 
2694
wl_del_monitor(wl_task_t *task)
 
2695
{
 
2696
        wl_info_t *wl = (wl_info_t *) task->context;
 
2697
        struct net_device *dev;
 
2698
        wl_if_t *wlif = NULL;
 
2699
 
 
2700
        ASSERT(wl);
 
2701
        WL_LOCK(wl);
 
2702
        WL_TRACE(("wl%d: wl_del_monitor\n", wl->pub->unit));
 
2703
        dev = wl->monitor_dev;
 
2704
        if (!dev)
 
2705
                goto done;
 
2706
        wlif = WL_DEV_IF(dev);
 
2707
        ASSERT(wlif);
 
2708
        wl->monitor_dev = NULL;
 
2709
        WL_UNLOCK(wl);
 
2710
        wl_free_if(wl, wlif);
 
2711
        WL_LOCK(wl);
 
2712
done:
 
2713
        MFREE(wl->osh, task, sizeof(wl_task_t));
 
2714
        WL_UNLOCK(wl);
 
2715
        atomic_dec(&wl->callbacks);
2348
2716
}
2349
2717
 
2350
2718
void
2351
2719
wl_set_monitor(wl_info_t *wl, int val)
2352
2720
{
 
2721
        WL_TRACE(("wl%d: wl_set_monitor: val %d\n", wl->pub->unit, val));
 
2722
 
 
2723
        if (val && !wl->monitor_dev) {
 
2724
                if (val == 1)
 
2725
                        wl->monitor_type = ARPHRD_IEEE80211_PRISM;
 
2726
                else if (val == 2)
 
2727
                        wl->monitor_type = ARPHRD_IEEE80211_RADIOTAP;
 
2728
                else {
 
2729
                        WL_ERROR(("monitor type %d not supported\n", val));
 
2730
                        ASSERT(0);
 
2731
                }
 
2732
 
 
2733
                (void) wl_schedule_task(wl, wl_add_monitor, wl);
 
2734
        } else if (!val && wl->monitor_dev) {
 
2735
                (void) wl_schedule_task(wl, wl_del_monitor, wl);
 
2736
        }
2353
2737
}
2354
2738
 
2355
2739
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
2734
3118
 
2735
3119
        return 0;
2736
3120
}
 
3121
 
 
3122
static int
 
3123
wl_proc_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
 
3124
{
 
3125
        wl_info_t * wl = (wl_info_t *)data;
 
3126
        int bcmerror, to_user;
 
3127
        int len;
 
3128
 
 
3129
        if (offset > 0) {
 
3130
                *eof = 1;
 
3131
                return 0;
 
3132
        }
 
3133
 
 
3134
        if (!length) {
 
3135
                WL_ERROR(("%s: Not enough return buf space\n", __FUNCTION__));
 
3136
                return 0;
 
3137
        }
 
3138
        WL_LOCK(wl);
 
3139
        bcmerror = wlc_ioctl(wl->wlc, WLC_GET_MONITOR, &to_user, sizeof(int), NULL);
 
3140
        len = sprintf(buffer, "%d\n", to_user);
 
3141
        WL_UNLOCK(wl);
 
3142
        return len;
 
3143
}
 
3144
 
 
3145
static int
 
3146
wl_proc_write(struct file *filp, const char __user *buff, unsigned long length, void *data)
 
3147
{
 
3148
        wl_info_t * wl = (wl_info_t *)data;
 
3149
        int from_user = 0;
 
3150
        int bcmerror;
 
3151
 
 
3152
        if (length == 0 || length > 2) {
 
3153
 
 
3154
                WL_ERROR(("%s: Invalid data length\n", __FUNCTION__));
 
3155
                return -EIO;
 
3156
        }
 
3157
        if (copy_from_user(&from_user, buff, 1)) {
 
3158
                WL_ERROR(("%s: copy from user failed\n", __FUNCTION__));
 
3159
                return -EIO;
 
3160
        }
 
3161
 
 
3162
        if (from_user >= 0x30)
 
3163
                from_user -= 0x30;
 
3164
 
 
3165
        WL_LOCK(wl);
 
3166
        bcmerror = wlc_ioctl(wl->wlc, WLC_SET_MONITOR, &from_user, sizeof(int), NULL);
 
3167
        WL_UNLOCK(wl);
 
3168
 
 
3169
        if (bcmerror < 0) {
 
3170
                WL_ERROR(("%s: SET_MONITOR failed with %d\n", __FUNCTION__, bcmerror));
 
3171
                return -EIO;
 
3172
        }
 
3173
        return length;
 
3174
}
 
3175
 
 
3176
static int
 
3177
wl_reg_proc_entry(wl_info_t *wl)
 
3178
{
 
3179
        char tmp[32];
 
3180
        sprintf(tmp, "%s%d", HYBRID_PROC, wl->pub->unit);
 
3181
        if ((wl->proc_entry = create_proc_entry(tmp, 0644, NULL)) == NULL) {
 
3182
                WL_ERROR(("%s: create_proc_entry %s failed\n", __FUNCTION__, tmp));
 
3183
                ASSERT(0);
 
3184
                return -1;
 
3185
        }
 
3186
        wl->proc_entry->read_proc = wl_proc_read;
 
3187
        wl->proc_entry->write_proc = wl_proc_write;
 
3188
        wl->proc_entry->data = wl;
 
3189
        return 0;
 
3190
}