Newer
Older
if (modparam_workaround_interval < 0)
priv->param_workaround_interval = 500;
else
priv->param_workaround_interval = modparam_workaround_interval;
}
static int bcm4320a_early_init(struct usbnet *usbdev)
{
/* copy module parameters for bcm4320a so that iwconfig reports txpower
* and workaround parameter is copied to private structure correctly.
*/
rndis_copy_module_params(usbdev);
/* bcm4320a doesn't handle configuration parameters well. Try
* set any and you get partially zeroed mac and broken device.
*/
return 0;
}
static int bcm4320b_early_init(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
char buf[8];
rndis_copy_module_params(usbdev);
/* Early initialization settings, setting these won't have effect
* if called after generic_rndis_bind().
*/
rndis_set_config_parameter_str(usbdev, "Country", priv->param_country);
rndis_set_config_parameter_str(usbdev, "FrameBursting",
priv->param_frameburst ? "1" : "0");
rndis_set_config_parameter_str(usbdev, "Afterburner",
priv->param_afterburner ? "1" : "0");
sprintf(buf, "%d", priv->param_power_save);
rndis_set_config_parameter_str(usbdev, "PowerSaveMode", buf);
sprintf(buf, "%d", priv->param_power_output);
rndis_set_config_parameter_str(usbdev, "PwrOut", buf);
sprintf(buf, "%d", priv->param_roamtrigger);
rndis_set_config_parameter_str(usbdev, "RoamTrigger", buf);
sprintf(buf, "%d", priv->param_roamdelta);
rndis_set_config_parameter_str(usbdev, "RoamDelta", buf);
return 0;
}
/* same as rndis_netdev_ops but with local multicast handler */
static const struct net_device_ops rndis_wlan_netdev_ops = {
.ndo_open = usbnet_open,
.ndo_stop = usbnet_stop,
.ndo_start_xmit = usbnet_start_xmit,
.ndo_tx_timeout = usbnet_tx_timeout,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_multicast_list = rndis_wlan_set_multicast_list,
static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
struct rndis_wlan_private *priv;
int retval, len;
__le32 tmp;
/* allocate wiphy and rndis private data
* NOTE: We only support a single virtual interface, so wiphy
* and wireless_dev are somewhat synonymous for this device.
*/
wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wlan_private));
return -ENOMEM;
priv = wiphy_priv(wiphy);
usbdev->net->ieee80211_ptr = &priv->wdev;
priv->wdev.wiphy = wiphy;
priv->wdev.iftype = NL80211_IFTYPE_STATION;
/* These have to be initialized before calling generic_rndis_bind().
* Otherwise we'll be in big trouble in rndis_wlan_early_init().
usbdev->driver_priv = priv;
priv->usbdev = usbdev;
mutex_init(&priv->command_lock);
/* because rndis_command() sleeps we need to use workqueue */
priv->workqueue = create_singlethread_workqueue("rndis_wlan");
INIT_WORK(&priv->work, rndis_wlan_worker);
INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller);
INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results);
/* try bind rndis_host */
retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS);
if (retval < 0)
goto fail;
/* generic_rndis_bind set packet filter to multicast_all+
* promisc mode which doesn't work well for our devices (device
* picks up rssi to closest station instead of to access point).
*
* rndis_host wants to avoid all OID as much as possible
* so do promisc/multicast handling in rndis_wlan.
usbdev->net->netdev_ops = &rndis_wlan_netdev_ops;
tmp = RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST;
retval = rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &tmp,
sizeof(tmp));
len = sizeof(tmp);
retval = rndis_query_oid(usbdev, OID_802_3_MAXIMUM_LIST_SIZE, &tmp,
&len);
priv->multicast_size = le32_to_cpu(tmp);
if (retval < 0 || priv->multicast_size < 0)
priv->multicast_size = 0;
if (priv->multicast_size > 0)
usbdev->net->flags |= IFF_MULTICAST;
usbdev->net->flags &= ~IFF_MULTICAST;
/* fill-out wiphy structure and register w/ cfg80211 */
memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN);
wiphy->privid = rndis_wiphy_privid;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
| BIT(NL80211_IFTYPE_ADHOC);
wiphy->max_scan_ssids = 1;
/* TODO: fill-out band/encr information based on priv->caps */
rndis_wlan_get_caps(usbdev, wiphy);
memcpy(priv->channels, rndis_channels, sizeof(rndis_channels));
memcpy(priv->rates, rndis_rates, sizeof(rndis_rates));
priv->band.channels = priv->channels;
priv->band.n_channels = ARRAY_SIZE(rndis_channels);
priv->band.bitrates = priv->rates;
priv->band.n_bitrates = ARRAY_SIZE(rndis_rates);
wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
memcpy(priv->cipher_suites, rndis_cipher_suites,
sizeof(rndis_cipher_suites));
wiphy->cipher_suites = priv->cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(rndis_cipher_suites);
set_wiphy_dev(wiphy, &usbdev->udev->dev);
if (wiphy_register(wiphy)) {
retval = -ENODEV;
goto fail;
set_default_iw_params(usbdev);
/* set default rts/frag */
rndis_set_wiphy_params(wiphy,
WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD);
/* turn radio on */
priv->radio_on = true;
disassociate(usbdev, true);
netif_carrier_off(usbdev->net);
return 0;
fail:
cancel_delayed_work_sync(&priv->dev_poller_work);
cancel_delayed_work_sync(&priv->scan_work);
cancel_work_sync(&priv->work);
flush_workqueue(priv->workqueue);
destroy_workqueue(priv->workqueue);
wiphy_free(wiphy);
return retval;
}
static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
/* turn radio off */
disassociate(usbdev, false);
cancel_delayed_work_sync(&priv->dev_poller_work);
cancel_delayed_work_sync(&priv->scan_work);
cancel_work_sync(&priv->work);
flush_workqueue(priv->workqueue);
destroy_workqueue(priv->workqueue);
rndis_unbind(usbdev, intf);
wiphy_unregister(priv->wdev.wiphy);
wiphy_free(priv->wdev.wiphy);
static int rndis_wlan_reset(struct usbnet *usbdev)
Jussi Kivilinna
committed
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
int retval;
Jussi Kivilinna
committed
netdev_dbg(usbdev->net, "%s()\n", __func__);
Jussi Kivilinna
committed
retval = rndis_reset(usbdev);
if (retval)
netdev_warn(usbdev->net, "rndis_reset failed: %d\n", retval);
/* rndis_reset cleared multicast list, so restore here.
(set_multicast_list() also turns on current packet filter) */
set_multicast_list(usbdev);
queue_delayed_work(priv->workqueue, &priv->dev_poller_work,
round_jiffies_relative(DEVICE_POLLER_JIFFIES));
Jussi Kivilinna
committed
return deauthenticate(usbdev);
static int rndis_wlan_stop(struct usbnet *usbdev)
{
Jussi Kivilinna
committed
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
int retval;
Jussi Kivilinna
committed
netdev_dbg(usbdev->net, "%s()\n", __func__);
Jussi Kivilinna
committed
retval = disassociate(usbdev, false);
Jussi Kivilinna
committed
priv->work_pending = 0;
cancel_delayed_work_sync(&priv->dev_poller_work);
Jussi Kivilinna
committed
cancel_delayed_work_sync(&priv->scan_work);
cancel_work_sync(&priv->work);
flush_workqueue(priv->workqueue);
if (priv->scan_request) {
cfg80211_scan_done(priv->scan_request, true);
priv->scan_request = NULL;
}
/* Set current packet filter zero to block receiving data packets from
device. */
filter = 0;
rndis_set_oid(usbdev, OID_GEN_CURRENT_PACKET_FILTER, &filter,
sizeof(filter));
Jussi Kivilinna
committed
return retval;
static const struct driver_info bcm4320b_info = {
.description = "Wireless RNDIS device, BCM4320b based",
.flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
.early_init = bcm4320b_early_init,
.indication = rndis_wlan_indication,
};
static const struct driver_info bcm4320a_info = {
.description = "Wireless RNDIS device, BCM4320a based",
.flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
.indication = rndis_wlan_indication,
static const struct driver_info rndis_wlan_info = {
.description = "Wireless RNDIS device",
.flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
FLAG_AVOID_UNLINK_URBS,
.bind = rndis_wlan_bind,
.unbind = rndis_wlan_unbind,
.status = rndis_status,
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
.stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
.indication = rndis_wlan_indication,
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
};
/*-------------------------------------------------------------------------*/
static const struct usb_device_id products [] = {
#define RNDIS_MASTER_INTERFACE \
.bInterfaceClass = USB_CLASS_COMM, \
.bInterfaceSubClass = 2 /* ACM */, \
.bInterfaceProtocol = 0x0ff
/* INF driver for these devices have DriverVer >= 4.xx.xx.xx and many custom
* parameters available. Chipset marked as 'BCM4320SKFBG' in NDISwrapper-wiki.
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x0411,
.idProduct = 0x00bc, /* Buffalo WLI-U2-KG125S */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320b_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x0baf,
.idProduct = 0x011b, /* U.S. Robotics USR5421 */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320b_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x050d,
.idProduct = 0x011b, /* Belkin F5D7051 */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320b_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x1799, /* Belkin has two vendor ids */
.idProduct = 0x011b, /* Belkin F5D7051 */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320b_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x13b1,
.idProduct = 0x0014, /* Linksys WUSB54GSv2 */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320b_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x13b1,
.idProduct = 0x0026, /* Linksys WUSB54GSC */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320b_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x0b05,
.idProduct = 0x1717, /* Asus WL169gE */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320b_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x0a5c,
.idProduct = 0xd11b, /* Eminent EM4045 */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320b_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x1690,
.idProduct = 0x0715, /* BT Voyager 1055 */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320b_info,
},
/* These devices have DriverVer < 4.xx.xx.xx and do not have any custom
* parameters available, hardware probably contain older firmware version with
* no way of updating. Chipset marked as 'BCM4320????' in NDISwrapper-wiki.
*/
{
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x13b1,
.idProduct = 0x000e, /* Linksys WUSB54GSv1 */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320a_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x0baf,
.idProduct = 0x0111, /* U.S. Robotics USR5420 */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320a_info,
}, {
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = 0x0411,
.idProduct = 0x004b, /* BUFFALO WLI-USB-G54 */
RNDIS_MASTER_INTERFACE,
.driver_info = (unsigned long) &bcm4320a_info,
},
/* Generic Wireless RNDIS devices that we don't have exact
* idVendor/idProduct/chip yet.
*/
{
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
.driver_info = (unsigned long) &rndis_wlan_info,
}, {
/* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
.driver_info = (unsigned long) &rndis_wlan_info,
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
},
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver rndis_wlan_driver = {
.name = "rndis_wlan",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
};
static int __init rndis_wlan_init(void)
{
return usb_register(&rndis_wlan_driver);
}
module_init(rndis_wlan_init);
static void __exit rndis_wlan_exit(void)
{
usb_deregister(&rndis_wlan_driver);
}
module_exit(rndis_wlan_exit);
MODULE_AUTHOR("Bjorge Dijkstra");
MODULE_AUTHOR("Jussi Kivilinna");
MODULE_DESCRIPTION("Driver for RNDIS based USB Wireless adapters");
MODULE_LICENSE("GPL");