struct mutex proto_block;
- /* Thread to issue ioctl for multicast */
- struct task_struct *sysioc_tsk;
- wait_queue_head_t sysioc_waitq;
- bool set_multicast;
- bool set_macaddress;
+ struct work_struct setmacaddr_work;
+ struct work_struct multicast_work;
u8 macvalue[ETH_ALEN];
atomic_t pend_8021x_cnt;
};
/* Error bits */
module_param(brcmf_msg_level, int, 0);
-/* Spawn a thread for system ioctls (set mac, set mcast) */
-uint brcmf_sysioc = true;
-module_param(brcmf_sysioc, uint, 0);
-
-/* ARP offload agent mode : Enable ARP Host Auto-Reply
-and ARP Peer Auto-Reply */
-uint brcmf_arp_mode = 0xb;
-module_param(brcmf_arp_mode, uint, 0);
-
-/* ARP offload enable */
-uint brcmf_arp_enable = true;
-module_param(brcmf_arp_enable, uint, 0);
-
-/* Network inteface name */
-char iface_name[IFNAMSIZ] = "wlan";
-module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *net)
{
return "<if_none>";
}
-static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
+static void _brcmf_set_multicast_list(struct work_struct *work)
{
struct net_device *dev;
struct netdev_hw_addr *ha;
u32 allmulti, cnt;
+ __le32 cnt_le;
+ __le32 allmulti_le;
struct brcmf_ioctl ioc;
char *buf, *bufp;
uint buflen;
int ret;
- dev = drvr_priv->iflist[ifidx]->net;
+ struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
+ multicast_work);
+
+ dev = drvr_priv->iflist[0]->net;
cnt = netdev_mc_count(dev);
/* Determine initial value of allmulti flag */
buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN);
bufp = buf = kmalloc(buflen, GFP_ATOMIC);
- if (!bufp) {
- brcmf_dbg(ERROR, "%s: out of memory for mcast_list, cnt %d\n",
- brcmf_ifname(&drvr_priv->pub, ifidx), cnt);
+ if (!bufp)
return;
- }
strcpy(bufp, "mcast_list");
bufp += strlen("mcast_list") + 1;
- cnt = cpu_to_le32(cnt);
- memcpy(bufp, &cnt, sizeof(cnt));
- bufp += sizeof(cnt);
+ cnt_le = cpu_to_le32(cnt);
+ memcpy(bufp, &cnt_le, sizeof(cnt));
+ bufp += sizeof(cnt_le);
netdev_for_each_mc_addr(ha, dev) {
if (!cnt)
ioc.len = buflen;
ioc.set = true;
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, 0, &ioc, ioc.len);
if (ret < 0) {
brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n",
- brcmf_ifname(&drvr_priv->pub, ifidx), cnt);
+ brcmf_ifname(&drvr_priv->pub, 0), cnt);
allmulti = cnt ? true : allmulti;
}
buflen = sizeof("allmulti") + sizeof(allmulti);
buf = kmalloc(buflen, GFP_ATOMIC);
- if (!buf) {
- brcmf_dbg(ERROR, "%s: out of memory for allmulti\n",
- brcmf_ifname(&drvr_priv->pub, ifidx));
+ if (!buf)
return;
- }
- allmulti = cpu_to_le32(allmulti);
+
+ allmulti_le = cpu_to_le32(allmulti);
if (!brcmu_mkiovar
- ("allmulti", (void *)&allmulti, sizeof(allmulti), buf, buflen)) {
+ ("allmulti", (void *)&allmulti_le,
+ sizeof(allmulti_le), buf, buflen)) {
brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
- brcmf_ifname(&drvr_priv->pub, ifidx),
+ brcmf_ifname(&drvr_priv->pub, 0),
(int)sizeof(allmulti), buflen);
kfree(buf);
return;
ioc.len = buflen;
ioc.set = true;
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, 0, &ioc, ioc.len);
if (ret < 0) {
brcmf_dbg(ERROR, "%s: set allmulti %d failed\n",
- brcmf_ifname(&drvr_priv->pub, ifidx),
- le32_to_cpu(allmulti));
+ brcmf_ifname(&drvr_priv->pub, 0),
+ le32_to_cpu(allmulti_le));
}
kfree(buf);
driver does */
allmulti = (dev->flags & IFF_PROMISC) ? true : false;
- allmulti = cpu_to_le32(allmulti);
+ allmulti_le = cpu_to_le32(allmulti);
memset(&ioc, 0, sizeof(ioc));
ioc.cmd = BRCMF_C_SET_PROMISC;
- ioc.buf = &allmulti;
- ioc.len = sizeof(allmulti);
+ ioc.buf = &allmulti_le;
+ ioc.len = sizeof(allmulti_le);
ioc.set = true;
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, 0, &ioc, ioc.len);
if (ret < 0) {
brcmf_dbg(ERROR, "%s: set promisc %d failed\n",
- brcmf_ifname(&drvr_priv->pub, ifidx),
- le32_to_cpu(allmulti));
+ brcmf_ifname(&drvr_priv->pub, 0),
+ le32_to_cpu(allmulti_le));
}
}
-static int
-_brcmf_set_mac_address(struct brcmf_info *drvr_priv, int ifidx, u8 *addr)
+static void
+_brcmf_set_mac_address(struct work_struct *work)
{
char buf[32];
struct brcmf_ioctl ioc;
int ret;
+ struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
+ setmacaddr_work);
+
brcmf_dbg(TRACE, "enter\n");
- if (!brcmu_mkiovar("cur_etheraddr", (char *)addr, ETH_ALEN, buf, 32)) {
+ if (!brcmu_mkiovar("cur_etheraddr", (char *)drvr_priv->macvalue,
+ ETH_ALEN, buf, 32)) {
brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n",
- brcmf_ifname(&drvr_priv->pub, ifidx));
- return -1;
+ brcmf_ifname(&drvr_priv->pub, 0));
+ return;
}
memset(&ioc, 0, sizeof(ioc));
ioc.cmd = BRCMF_C_SET_VAR;
ioc.len = 32;
ioc.set = true;
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, 0, &ioc, ioc.len);
if (ret < 0)
brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n",
- brcmf_ifname(&drvr_priv->pub, ifidx));
+ brcmf_ifname(&drvr_priv->pub, 0));
else
- memcpy(drvr_priv->iflist[ifidx]->net->dev_addr, addr, ETH_ALEN);
+ memcpy(drvr_priv->iflist[0]->net->dev_addr,
+ drvr_priv->macvalue, ETH_ALEN);
- return ret;
+ return;
}
/* Virtual interfaces only ((ifp && ifp->info && ifp->idx == true) */
unregister_netdev(ifp->net);
free_netdev(ifp->net);
}
- /* Allocate etherdev, including space for private structure */
- ifp->net = alloc_etherdev(sizeof(drvr_priv));
+ /* Allocate netdev, including space for private structure */
+ ifp->net = alloc_netdev(sizeof(drvr_priv), "wlan%d",
+ ether_setup);
if (!ifp->net) {
- brcmf_dbg(ERROR, "OOM - alloc_etherdev\n");
+ brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
ret = -ENOMEM;
}
if (ret == 0) {
}
}
-static int _brcmf_sysioc_thread(void *data)
-{
- struct brcmf_info *drvr_priv = (struct brcmf_info *) data;
- int i;
-#ifdef SOFTAP
- bool in_ap = false;
-#endif
- DECLARE_WAITQUEUE(wait, current);
- allow_signal(SIGTERM);
-
- add_wait_queue(&drvr_priv->sysioc_waitq, &wait);
- while (1) {
- prepare_to_wait(&drvr_priv->sysioc_waitq, &wait,
- TASK_INTERRUPTIBLE);
-
- /* wait for event */
- schedule();
-
- if (kthread_should_stop())
- break;
-
- for (i = 0; i < BRCMF_MAX_IFS; i++) {
- struct brcmf_if *ifentry = drvr_priv->iflist[i];
- if (ifentry) {
-#ifdef SOFTAP
- in_ap = (ap_net_dev != NULL);
-#endif /* SOFTAP */
- if (ifentry->state)
- brcmf_op_if(ifentry);
-#ifdef SOFTAP
- if (drvr_priv->iflist[i] == NULL) {
- brcmf_dbg(TRACE, "interface %d removed!\n",
- i);
- continue;
- }
-
- if (in_ap && drvr_priv->set_macaddress) {
- brcmf_dbg(TRACE, "attempt to set MAC for %s in AP Mode, blocked.\n",
- ifentry->net->name);
- drvr_priv->set_macaddress = false;
- continue;
- }
-
- if (in_ap && drvr_priv->set_multicast) {
- brcmf_dbg(TRACE, "attempt to set MULTICAST list for %s in AP Mode, blocked.\n",
- ifentry->net->name);
- drvr_priv->set_multicast = false;
- continue;
- }
-#endif /* SOFTAP */
- if (drvr_priv->set_multicast) {
- drvr_priv->set_multicast = false;
- _brcmf_set_multicast_list(drvr_priv, i);
- }
- if (drvr_priv->set_macaddress) {
- drvr_priv->set_macaddress = false;
- _brcmf_set_mac_address(drvr_priv, i,
- drvr_priv->macvalue);
- }
- }
- }
- }
- finish_wait(&drvr_priv->sysioc_waitq, &wait);
- return 0;
-}
-
static int brcmf_netdev_set_mac_address(struct net_device *dev, void *addr)
{
- int ret = 0;
-
struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(dev);
struct sockaddr *sa = (struct sockaddr *)addr;
int ifidx;
return -1;
memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);
- drvr_priv->set_macaddress = true;
- wake_up(&drvr_priv->sysioc_waitq);
- return ret;
+ schedule_work(&drvr_priv->setmacaddr_work);
+ return 0;
}
static void brcmf_netdev_set_multicast_list(struct net_device *dev)
if (ifidx == BRCMF_BAD_IF)
return;
- drvr_priv->set_multicast = true;
- wake_up(&drvr_priv->sysioc_waitq);
+ schedule_work(&drvr_priv->multicast_work);
}
int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
ioc.set = false;
strcpy(buf, "toe_ol");
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.len);
if (ret < 0) {
/* Check for older dongle image that doesn't support toe_ol */
if (ret == -EIO) {
strcpy(buf, "toe_ol");
memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(u32));
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.len);
if (ret < 0) {
brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n",
brcmf_ifname(&drvr_priv->pub, ifidx), ret);
strcpy(buf, "toe");
memcpy(&buf[sizeof("toe")], &toe, sizeof(u32));
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.len);
if (ret < 0) {
brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n",
brcmf_ifname(&drvr_priv->pub, ifidx), ret);
if (is_set_key_cmd)
brcmf_netdev_wait_pend8021x(net);
- bcmerror = brcmf_proto_ioctl(&drvr_priv->pub, ifidx,
- ioc, ioc->buf, buflen);
+ bcmerror = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, ioc, buflen);
done:
if (bcmerror > 0)
/* Allow transmit calls */
netif_start_queue(net);
drvr_priv->pub.up = 1;
- if (unlikely(brcmf_cfg80211_up(drvr_priv->pub.config))) {
+ if (brcmf_cfg80211_up(drvr_priv->pub.config)) {
brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
return -1;
}
ifp = drvr_priv->iflist[ifidx];
if (!ifp) {
ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC);
- if (!ifp) {
- brcmf_dbg(ERROR, "OOM - struct brcmf_if\n");
+ if (!ifp)
return -ENOMEM;
- }
}
memset(ifp, 0, sizeof(struct brcmf_if));
if (net == NULL) {
ifp->state = BRCMF_E_IF_ADD;
ifp->idx = ifidx;
- wake_up(&drvr_priv->sysioc_waitq);
+ brcmf_op_if(ifp);
} else
ifp->net = net;
ifp->state = BRCMF_E_IF_DEL;
ifp->idx = ifidx;
- wake_up(&drvr_priv->sysioc_waitq);
+ brcmf_op_if(ifp);
}
struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
brcmf_dbg(TRACE, "Enter\n");
- /* Allocate etherdev, including space for private structure */
- net = alloc_etherdev(sizeof(drvr_priv));
+ /* Allocate netdev, including space for private structure */
+ net = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup);
if (!net) {
- brcmf_dbg(ERROR, "OOM - alloc_etherdev\n");
+ brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
goto fail;
}
/* Allocate primary brcmf_info */
drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);
- if (!drvr_priv) {
- brcmf_dbg(ERROR, "OOM - alloc brcmf_info\n");
+ if (!drvr_priv)
goto fail;
- }
/*
* Save the brcmf_info into the priv
*/
memcpy(netdev_priv(net), &drvr_priv, sizeof(drvr_priv));
- /* Set network interface name if it was provided as module parameter */
- if (iface_name[0]) {
- int len;
- char ch;
- strncpy(net->name, iface_name, IFNAMSIZ);
- net->name[IFNAMSIZ - 1] = 0;
- len = strlen(net->name);
- ch = net->name[len - 1];
- if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
- strcat(net->name, "%d");
- }
-
if (brcmf_add_if(drvr_priv, 0, net, net->name, NULL, 0, 0) ==
BRCMF_BAD_IF)
goto fail;
brcmf_cfg80211_attach(net,
brcmf_bus_get_device(bus),
&drvr_priv->pub);
- if (unlikely(drvr_priv->pub.config == NULL)) {
+ if (drvr_priv->pub.config == NULL) {
brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
goto fail;
}
- if (brcmf_sysioc) {
- init_waitqueue_head(&drvr_priv->sysioc_waitq);
- drvr_priv->sysioc_tsk = kthread_run(_brcmf_sysioc_thread,
- drvr_priv, "_brcmf_sysioc");
- if (IS_ERR(drvr_priv->sysioc_tsk)) {
- printk(KERN_WARNING
- "_brcmf_sysioc thread failed to start\n");
- drvr_priv->sysioc_tsk = NULL;
- }
- } else
- drvr_priv->sysioc_tsk = NULL;
+ INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address);
+ INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list);
/*
* Save the brcmf_info into the priv
unregister_netdev(ifp->net);
}
- if (drvr_priv->sysioc_tsk) {
- send_sig(SIGTERM, drvr_priv->sysioc_tsk, 1);
- kthread_stop(drvr_priv->sysioc_tsk);
- drvr_priv->sysioc_tsk = NULL;
- }
+ cancel_work_sync(&drvr_priv->setmacaddr_work);
+ cancel_work_sync(&drvr_priv->multicast_work);
brcmf_bus_detach(drvr);