--- linux/drivers/net/wireless/bcm43xx/bcm43xx_main.c 2007-04-17 16:39:08.000000000 +0200 +++ linux-bcm43xx-patch/drivers/net/wireless/bcm43xx/bcm43xx_main.c 2007-04-20 00:09:09.000000000 +0200 @@ -104,6 +104,13 @@ #endif /* CONFIG_BCM43XX_DEBUG*/ +static ssize_t bcm43xx_inject_nofcs(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t cnt); +static DEVICE_ATTR(inject_nofcs, 0200, + NULL, bcm43xx_inject_nofcs); + /* If you want to debug with just a single device, enable this, * where the string is the pci device ID (as given by the kernel's * pci_name function) of the device to be used. @@ -3365,6 +3372,8 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) { bcm43xx_rng_exit(bcm); + + device_remove_file(&bcm->pci_dev->dev, &dev_attr_inject_nofcs); bcm43xx_sysfs_unregister(bcm); bcm43xx_periodic_tasks_delete(bcm); @@ -3636,6 +3645,10 @@ err = bcm43xx_rng_init(bcm); if (err) goto err_sysfs_unreg; + + err = device_create_file(&bcm->pci_dev->dev, &dev_attr_inject_nofcs); + if (err) + goto err_inject_if; bcm43xx_periodic_tasks_setup(bcm); /*FIXME: This should be handled by softmac instead. */ @@ -3645,7 +3658,8 @@ mutex_unlock(&(bcm)->mutex); return err; - +err_inject_if: + device_remove_file(&bcm->pci_dev->dev, &dev_attr_inject_nofcs); err_sysfs_unreg: bcm43xx_sysfs_unregister(bcm); err_wlshutdown: @@ -3892,6 +3906,48 @@ return err; } +static ssize_t bcm43xx_inject_nofcs(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t cnt) +{ + struct bcm43xx_private *bcm = dev_to_bcm(dev); + struct ieee80211_txb *faketxb; + struct sk_buff *skb; + unsigned long flags; + int err = -ENODEV; + + faketxb = kzalloc(sizeof(struct ieee80211_txb) + sizeof(void *), GFP_KERNEL); + if (!faketxb) + return -ENOMEM; + faketxb->nr_frags = 1; + faketxb->frag_size = cnt; + faketxb->payload_size = cnt; + skb = __dev_alloc_skb(cnt + bcm->ieee->tx_headroom, GFP_KERNEL); + if (!skb) { + kfree(faketxb); + return -ENOMEM; + } + skb_reserve(skb, bcm->ieee->tx_headroom); + memcpy(skb_put(skb, cnt), buf, cnt); + faketxb->fragments[0] = skb; + + spin_lock_irqsave(&bcm->irq_lock, flags); + + if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) + err = bcm43xx_tx(bcm, faketxb); + + spin_unlock_irqrestore(&bcm->irq_lock, flags); + + if (unlikely(err)) { + dev_kfree_skb(skb); + kfree(faketxb); + return err; + } + + return cnt; +} + static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, u8 channel) {