| /*! |
| * @file wilc_wfi_netdevice.c |
| * @brief File Operations OS wrapper functionality |
| * @author mdaftedar |
| * @sa wilc_wfi_netdevice.h |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| |
| #ifdef SIMULATION |
| |
| #include "wilc_wfi_cfgoperations.h" |
| #include "host_interface.h" |
| |
| |
| MODULE_AUTHOR("Mai Daftedar"); |
| MODULE_LICENSE("Dual BSD/GPL"); |
| |
| |
| struct net_device *WILC_WFI_devs[2]; |
| |
| /* |
| * Transmitter lockup simulation, normally disabled. |
| */ |
| static int lockup; |
| module_param(lockup, int, 0); |
| |
| static int timeout = WILC_WFI_TIMEOUT; |
| module_param(timeout, int, 0); |
| |
| /* |
| * Do we run in NAPI mode? |
| */ |
| static int use_napi ; |
| module_param(use_napi, int, 0); |
| |
| |
| /* |
| * A structure representing an in-flight packet. |
| */ |
| struct WILC_WFI_packet { |
| struct WILC_WFI_packet *next; |
| struct net_device *dev; |
| int datalen; |
| u8 data[ETH_DATA_LEN]; |
| }; |
| |
| |
| |
| int pool_size = 8; |
| module_param(pool_size, int, 0); |
| |
| |
| static void WILC_WFI_TxTimeout(struct net_device *dev); |
| static void (*WILC_WFI_Interrupt)(int, void *, struct pt_regs *); |
| |
| /** |
| * @brief WILC_WFI_SetupPool |
| * @details Set up a device's packet pool. |
| * @param[in] struct net_device *dev : Network Device Pointer |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| void WILC_WFI_SetupPool(struct net_device *dev) |
| { |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| int i; |
| struct WILC_WFI_packet *pkt; |
| |
| priv->ppool = NULL; |
| for (i = 0; i < pool_size; i++) { |
| pkt = kmalloc (sizeof (struct WILC_WFI_packet), GFP_KERNEL); |
| if (pkt == NULL) { |
| PRINT_D(RX_DBG, "Ran out of memory allocating packet pool\n"); |
| return; |
| } |
| pkt->dev = dev; |
| pkt->next = priv->ppool; |
| priv->ppool = pkt; |
| } |
| } |
| |
| /** |
| * @brief WILC_WFI_TearDownPool |
| * @details Internal cleanup function that's called after the network device |
| * driver is unregistered |
| * @param[in] struct net_device *dev : Network Device Driver |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| void WILC_WFI_TearDownPool(struct net_device *dev) |
| { |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| struct WILC_WFI_packet *pkt; |
| |
| while ((pkt = priv->ppool)) { |
| priv->ppool = pkt->next; |
| kfree (pkt); |
| /* FIXME - in-flight packets ? */ |
| } |
| } |
| |
| /** |
| * @brief WILC_WFI_GetTxBuffer |
| * @details Buffer/pool management |
| * @param[in] net_device *dev : Network Device Driver Structure |
| * @return struct WILC_WFI_packet |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| struct WILC_WFI_packet *WILC_WFI_GetTxBuffer(struct net_device *dev) |
| { |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| unsigned long flags; |
| struct WILC_WFI_packet *pkt; |
| |
| spin_lock_irqsave(&priv->lock, flags); |
| pkt = priv->ppool; |
| priv->ppool = pkt->next; |
| if (priv->ppool == NULL) { |
| PRINT_INFO(RX_DBG, "Pool empty\n"); |
| netif_stop_queue(dev); |
| } |
| spin_unlock_irqrestore(&priv->lock, flags); |
| return pkt; |
| } |
| /** |
| * @brief WILC_WFI_ReleaseBuffer |
| * @details Buffer/pool management |
| * @param[in] WILC_WFI_packet *pkt : Structure holding in-flight packet |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| void WILC_WFI_ReleaseBuffer(struct WILC_WFI_packet *pkt) |
| { |
| unsigned long flags; |
| struct WILC_WFI_priv *priv = netdev_priv(pkt->dev); |
| |
| spin_lock_irqsave(&priv->lock, flags); |
| pkt->next = priv->ppool; |
| priv->ppool = pkt; |
| spin_unlock_irqrestore(&priv->lock, flags); |
| if (netif_queue_stopped(pkt->dev) && pkt->next == NULL) |
| netif_wake_queue(pkt->dev); |
| } |
| |
| /** |
| * @brief WILC_WFI_EnqueueBuf |
| * @details Enqueuing packets in an RX buffer queue |
| * @param[in] WILC_WFI_packet *pkt : Structure holding in-flight packet |
| * @param[in] net_device *dev : Network Device Driver Structure |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| void WILC_WFI_EnqueueBuf(struct net_device *dev, struct WILC_WFI_packet *pkt) |
| { |
| unsigned long flags; |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| |
| spin_lock_irqsave(&priv->lock, flags); |
| pkt->next = priv->rx_queue; /* FIXME - misorders packets */ |
| priv->rx_queue = pkt; |
| spin_unlock_irqrestore(&priv->lock, flags); |
| } |
| |
| /** |
| * @brief WILC_WFI_DequeueBuf |
| * @details Dequeuing packets from the RX buffer queue |
| * @param[in] net_device *dev : Network Device Driver Structure |
| * @return WILC_WFI_packet *pkt : Structure holding in-flight pac |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| struct WILC_WFI_packet *WILC_WFI_DequeueBuf(struct net_device *dev) |
| { |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| struct WILC_WFI_packet *pkt; |
| unsigned long flags; |
| |
| spin_lock_irqsave(&priv->lock, flags); |
| pkt = priv->rx_queue; |
| if (pkt != NULL) |
| priv->rx_queue = pkt->next; |
| spin_unlock_irqrestore(&priv->lock, flags); |
| return pkt; |
| } |
| /** |
| * @brief WILC_WFI_RxInts |
| * @details Enable and disable receive interrupts. |
| * @param[in] net_device *dev : Network Device Driver Structure |
| * @param[in] enable : Enable/Disable flag |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| static void WILC_WFI_RxInts(struct net_device *dev, int enable) |
| { |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| priv->rx_int_enabled = enable; |
| } |
| |
| /** |
| * @brief WILC_WFI_Open |
| * @details Open Network Device Driver, called when the network |
| * interface is opened. It starts the interface's transmit queue. |
| * @param[in] net_device *dev : Network Device Driver Structure |
| * @param[in] enable : Enable/Disable flag |
| * @return int : Returns 0 upon success. |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| int WILC_WFI_Open(struct net_device *dev) |
| { |
| /* request_region(), request_irq(), .... (like fops->open) */ |
| /* |
| * Assign the hardware address of the board: use "\0SNULx", where |
| * x is 0 or 1. The first byte is '\0' to avoid being a multicast |
| * address (the first byte of multicast addrs is odd). |
| */ |
| memcpy(dev->dev_addr, "\0WLAN0", ETH_ALEN); |
| if (dev == WILC_WFI_devs[1]) |
| dev->dev_addr[ETH_ALEN - 1]++; /* \0SNUL1 */ |
| |
| WILC_WFI_InitHostInt(dev); |
| netif_start_queue(dev); |
| return 0; |
| } |
| /** |
| * @brief WILC_WFI_Release |
| * @details Release Network Device Driver, called when the network |
| * interface is stopped or brought down. This function marks |
| * the network driver as not being able to transmit |
| * @param[in] net_device *dev : Network Device Driver Structure |
| * @return int : Return 0 on Success. |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| int WILC_WFI_Release(struct net_device *dev) |
| { |
| /* release ports, irq and such -- like fops->close */ |
| |
| netif_stop_queue(dev); /* can't transmit any more */ |
| |
| return 0; |
| } |
| /** |
| * @brief WILC_WFI_Config |
| * @details Configuration changes (passed on by ifconfig) |
| * @param[in] net_device *dev : Network Device Driver Structure |
| * @param[in] struct ifmap *map : Contains the ioctl implementation for the |
| * network driver. |
| * @return int : Return 0 on Success. |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| int WILC_WFI_Config(struct net_device *dev, struct ifmap *map) |
| { |
| if (dev->flags & IFF_UP) /* can't act on a running interface */ |
| return -EBUSY; |
| |
| /* Don't allow changing the I/O address */ |
| if (map->base_addr != dev->base_addr) { |
| PRINT_D(RX_DBG, KERN_WARNING "WILC_WFI: Can't change I/O address\n"); |
| return -EOPNOTSUPP; |
| } |
| |
| /* Allow changing the IRQ */ |
| if (map->irq != dev->irq) { |
| dev->irq = map->irq; |
| /* request_irq() is delayed to open-time */ |
| } |
| |
| /* ignore other fields */ |
| return 0; |
| } |
| /** |
| * @brief WILC_WFI_Rx |
| * @details Receive a packet: retrieve, encapsulate and pass over to upper |
| * levels |
| * @param[in] net_device *dev : Network Device Driver Structure |
| * @param[in] WILC_WFI_packet : |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| void WILC_WFI_Rx(struct net_device *dev, struct WILC_WFI_packet *pkt) |
| { |
| int i; |
| struct sk_buff *skb; |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| s8 rssi; |
| /* |
| * The packet has been retrieved from the transmission |
| * medium. Build an skb around it, so upper layers can handle it |
| */ |
| |
| |
| skb = dev_alloc_skb(pkt->datalen + 2); |
| if (!skb) { |
| if (printk_ratelimit()) |
| PRINT_D(RX_DBG, "WILC_WFI rx: low on mem - packet dropped\n"); |
| priv->stats.rx_dropped++; |
| goto out; |
| } |
| skb_reserve(skb, 2); /* align IP on 16B boundary */ |
| memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); |
| |
| if (priv->monitor_flag) { |
| PRINT_INFO(RX_DBG, "In monitor device name %s\n", dev->name); |
| priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); |
| PRINT_D(RX_DBG, "VALUE PASSED IN OF HRWD %p\n", priv->hWILCWFIDrv); |
| /* host_int_get_rssi(priv->hWILCWFIDrv, &(rssi)); */ |
| if (INFO) { |
| for (i = 14; i < skb->len; i++) |
| PRINT_INFO(RX_DBG, "RXdata[%d] %02x\n", i, skb->data[i]); |
| } |
| WILC_WFI_monitor_rx(dev, skb); |
| return; |
| } |
| out: |
| return; |
| } |
| |
| /** |
| * @brief WILC_WFI_Poll |
| * @details The poll implementation |
| * @param[in] struct napi_struct *napi : |
| * @param[in] int budget : |
| * @return int : Return 0 on Success. |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| static int WILC_WFI_Poll(struct napi_struct *napi, int budget) |
| { |
| int npackets = 0; |
| struct sk_buff *skb; |
| struct WILC_WFI_priv *priv = container_of(napi, struct WILC_WFI_priv, napi); |
| struct net_device *dev = priv->dev; |
| struct WILC_WFI_packet *pkt; |
| |
| while (npackets < budget && priv->rx_queue) { |
| pkt = WILC_WFI_DequeueBuf(dev); |
| skb = dev_alloc_skb(pkt->datalen + 2); |
| if (!skb) { |
| if (printk_ratelimit()) |
| PRINT_D(RX_DBG, "WILC_WFI: packet dropped\n"); |
| priv->stats.rx_dropped++; |
| WILC_WFI_ReleaseBuffer(pkt); |
| continue; |
| } |
| skb_reserve(skb, 2); /* align IP on 16B boundary */ |
| memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); |
| skb->dev = dev; |
| skb->protocol = eth_type_trans(skb, dev); |
| skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ |
| netif_receive_skb(skb); |
| /* Maintain stats */ |
| npackets++; |
| WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, pkt->datalen, WILC_WFI_RX_PKT); |
| WILC_WFI_ReleaseBuffer(pkt); |
| } |
| /* If we processed all packets, we're done; tell the kernel and re-enable ints */ |
| if (npackets < budget) { |
| napi_complete(napi); |
| WILC_WFI_RxInts(dev, 1); |
| } |
| return npackets; |
| } |
| |
| /** |
| * @brief WILC_WFI_Poll |
| * @details The typical interrupt entry point |
| * @param[in] struct napi_struct *napi : |
| * @param[in] int budget : |
| * @return int : Return 0 on Success. |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| static void WILC_WFI_RegularInterrupt(int irq, void *dev_id, struct pt_regs *regs) |
| { |
| int statusword; |
| struct WILC_WFI_priv *priv; |
| struct WILC_WFI_packet *pkt = NULL; |
| /* |
| * As usual, check the "device" pointer to be sure it is |
| * really interrupting. |
| * Then assign "struct device *dev" |
| */ |
| struct net_device *dev = (struct net_device *)dev_id; |
| /* ... and check with hw if it's really ours */ |
| |
| /* paranoid */ |
| if (!dev) |
| return; |
| |
| /* Lock the device */ |
| priv = netdev_priv(dev); |
| spin_lock(&priv->lock); |
| |
| /* retrieve statusword: real netdevices use I/O instructions */ |
| statusword = priv->status; |
| priv->status = 0; |
| if (statusword & WILC_WFI_RX_INTR) { |
| /* send it to WILC_WFI_rx for handling */ |
| pkt = priv->rx_queue; |
| if (pkt) { |
| priv->rx_queue = pkt->next; |
| WILC_WFI_Rx(dev, pkt); |
| } |
| } |
| if (statusword & WILC_WFI_TX_INTR) { |
| /* a transmission is over: free the skb */ |
| WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, priv->tx_packetlen, WILC_WFI_TX_PKT); |
| dev_kfree_skb(priv->skb); |
| } |
| |
| /* Unlock the device and we are done */ |
| spin_unlock(&priv->lock); |
| if (pkt) |
| WILC_WFI_ReleaseBuffer(pkt); /* Do this outside the lock! */ |
| return; |
| } |
| /** |
| * @brief WILC_WFI_NapiInterrupt |
| * @details A NAPI interrupt handler |
| * @param[in] irq: |
| * @param[in] dev_id: |
| * @param[in] pt_regs: |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| static void WILC_WFI_NapiInterrupt(int irq, void *dev_id, struct pt_regs *regs) |
| { |
| int statusword; |
| struct WILC_WFI_priv *priv; |
| |
| /* |
| * As usual, check the "device" pointer for shared handlers. |
| * Then assign "struct device *dev" |
| */ |
| struct net_device *dev = (struct net_device *)dev_id; |
| /* ... and check with hw if it's really ours */ |
| |
| /* paranoid */ |
| if (!dev) |
| return; |
| |
| /* Lock the device */ |
| priv = netdev_priv(dev); |
| spin_lock(&priv->lock); |
| |
| /* retrieve statusword: real netdevices use I/O instructions */ |
| statusword = priv->status; |
| priv->status = 0; |
| if (statusword & WILC_WFI_RX_INTR) { |
| WILC_WFI_RxInts(dev, 0); /* Disable further interrupts */ |
| napi_schedule(&priv->napi); |
| } |
| if (statusword & WILC_WFI_TX_INTR) { |
| /* a transmission is over: free the skb */ |
| |
| WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, priv->tx_packetlen, WILC_WFI_TX_PKT); |
| dev_kfree_skb(priv->skb); |
| } |
| |
| /* Unlock the device and we are done */ |
| spin_unlock(&priv->lock); |
| return; |
| } |
| |
| /** |
| * @brief MI_WFI_HwTx |
| * @details Transmit a packet (low level interface) |
| * @param[in] buf: |
| * @param[in] len: |
| * @param[in] net_device *dev: |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| void WILC_WFI_HwTx(char *buf, int len, struct net_device *dev) |
| { |
| /* |
| * This function deals with hw details. This interface loops |
| * back the packet to the other WILC_WFI interface (if any). |
| * In other words, this function implements the WILC_WFI behaviour, |
| * while all other procedures are rather device-independent |
| */ |
| struct iphdr *ih; |
| struct net_device *dest; |
| struct WILC_WFI_priv *priv; |
| u32 *saddr, *daddr; |
| struct WILC_WFI_packet *tx_buffer; |
| |
| |
| /* I am paranoid. Ain't I? */ |
| if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { |
| PRINT_D(RX_DBG, "WILC_WFI: Hmm... packet too short (%i octets)\n", |
| len); |
| return; |
| } |
| |
| if (0) { /* enable this conditional to look at the data */ |
| int i; |
| PRINT_D(RX_DBG, "len is %i", len); |
| for (i = 14; i < len; i++) |
| PRINT_D(RX_DBG, "TXdata[%d] %02x\n", i, buf[i] & 0xff); |
| /* PRINT_D(RX_DBG, "\n"); */ |
| } |
| /* |
| * Ethhdr is 14 bytes, but the kernel arranges for iphdr |
| * to be aligned (i.e., ethhdr is unaligned) |
| */ |
| ih = (struct iphdr *)(buf + sizeof(struct ethhdr)); |
| saddr = &ih->saddr; |
| daddr = &ih->daddr; |
| |
| ((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */ |
| ((u8 *)daddr)[2] ^= 1; |
| |
| ih->check = 0; /* and rebuild the checksum (ip needs it) */ |
| ih->check = ip_fast_csum((unsigned char *)ih, ih->ihl); |
| |
| |
| if (dev == WILC_WFI_devs[0]) |
| PRINT_D(RX_DBG, "%08x:%05i --> %08x:%05i\n", |
| ntohl(ih->saddr), ntohs(((struct tcphdr *)(ih + 1))->source), |
| ntohl(ih->daddr), ntohs(((struct tcphdr *)(ih + 1))->dest)); |
| else |
| PRINT_D(RX_DBG, "%08x:%05i <-- %08x:%05i\n", |
| ntohl(ih->daddr), ntohs(((struct tcphdr *)(ih + 1))->dest), |
| ntohl(ih->saddr), ntohs(((struct tcphdr *)(ih + 1))->source)); |
| |
| /* |
| * Ok, now the packet is ready for transmission: first simulate a |
| * receive interrupt on the twin device, then a |
| * transmission-done on the transmitting device |
| */ |
| dest = WILC_WFI_devs[dev == WILC_WFI_devs[0] ? 1 : 0]; |
| priv = netdev_priv(dest); |
| |
| tx_buffer = WILC_WFI_GetTxBuffer(dev); |
| tx_buffer->datalen = len; |
| memcpy(tx_buffer->data, buf, len); |
| WILC_WFI_EnqueueBuf(dest, tx_buffer); |
| if (priv->rx_int_enabled) { |
| priv->status |= WILC_WFI_RX_INTR; |
| WILC_WFI_Interrupt(0, dest, NULL); |
| } |
| |
| priv = netdev_priv(dev); |
| priv->tx_packetlen = len; |
| priv->tx_packetdata = buf; |
| priv->status |= WILC_WFI_TX_INTR; |
| if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0) { |
| /* Simulate a dropped transmit interrupt */ |
| netif_stop_queue(dev); |
| PRINT_D(RX_DBG, "Simulate lockup at %ld, txp %ld\n", jiffies, |
| (unsigned long) priv->stats.tx_packets); |
| } else |
| WILC_WFI_Interrupt(0, dev, NULL); |
| |
| } |
| |
| /** |
| * @brief WILC_WFI_Tx |
| * @details Transmit a packet (called by the kernel) |
| * @param[in] sk_buff *skb: |
| * @param[in] net_device *dev: |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| int WILC_WFI_Tx(struct sk_buff *skb, struct net_device *dev) |
| { |
| int len; |
| char *data, shortpkt[ETH_ZLEN]; |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| |
| /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */ |
| |
| /* if(priv->monitor_flag) */ |
| /* mac80211_hwsim_monitor_rx(skb); */ |
| |
| |
| data = skb->data; |
| len = skb->len; |
| |
| if (len < ETH_ZLEN) { |
| memset(shortpkt, 0, ETH_ZLEN); |
| memcpy(shortpkt, skb->data, skb->len); |
| len = ETH_ZLEN; |
| data = shortpkt; |
| } |
| dev->trans_start = jiffies; /* save the timestamp */ |
| |
| /* Remember the skb, so we can free it at interrupt time */ |
| priv->skb = skb; |
| |
| /* actual deliver of data is device-specific, and not shown here */ |
| WILC_WFI_HwTx(data, len, dev); |
| |
| return 0; /* Our simple device can not fail */ |
| } |
| |
| /** |
| * @brief WILC_WFI_TxTimeout |
| * @details Deal with a transmit timeout. |
| * @param[in] net_device *dev: |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| void WILC_WFI_TxTimeout(struct net_device *dev) |
| { |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| |
| PRINT_D(RX_DBG, "Transmit timeout at %ld, latency %ld\n", jiffies, |
| jiffies - dev->trans_start); |
| /* Simulate a transmission interrupt to get things moving */ |
| priv->status = WILC_WFI_TX_INTR; |
| WILC_WFI_Interrupt(0, dev, NULL); |
| priv->stats.tx_errors++; |
| netif_wake_queue(dev); |
| return; |
| } |
| |
| /** |
| * @brief WILC_WFI_Ioctl |
| * @details Ioctl commands |
| * @param[in] net_device *dev: |
| * @param[in] ifreq *rq |
| * @param[in] cmd: |
| * @return int : Return 0 on Success |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| int WILC_WFI_Ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
| { |
| PRINT_D(RX_DBG, "ioctl\n"); |
| return 0; |
| } |
| |
| /** |
| * @brief WILC_WFI_Stat |
| * @details Return statistics to the caller |
| * @param[in] net_device *dev: |
| * @return WILC_WFI_Stats : Return net_device_stats stucture with the |
| * network device driver private data contents. |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| struct net_device_stats *WILC_WFI_Stats(struct net_device *dev) |
| { |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| return &priv->stats; |
| } |
| |
| /** |
| * @brief WILC_WFI_RebuildHeader |
| * @details This function is called to fill up an eth header, since arp is not |
| * available on the interface |
| * @param[in] sk_buff *skb: |
| * @return int : Return 0 on Success |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| int WILC_WFI_RebuildHeader(struct sk_buff *skb) |
| { |
| struct ethhdr *eth = (struct ethhdr *) skb->data; |
| struct net_device *dev = skb->dev; |
| |
| memcpy(eth->h_source, dev->dev_addr, dev->addr_len); |
| memcpy(eth->h_dest, dev->dev_addr, dev->addr_len); |
| eth->h_dest[ETH_ALEN - 1] ^= 0x01; /* dest is us xor 1 */ |
| return 0; |
| } |
| /** |
| * @brief WILC_WFI_RebuildHeader |
| * @details This function is called to fill up an eth header, since arp is not |
| * available on the interface |
| * @param[in] sk_buff *skb: |
| * @param[in] struct net_device *dev: |
| * @param[in] unsigned short type: |
| * @param[in] const void *saddr, |
| * @param[in] const void *daddr: |
| * @param[in] unsigned int len |
| * @return int : Return 0 on Success |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| int WILC_WFI_Header(struct sk_buff *skb, struct net_device *dev, |
| unsigned short type, const void *daddr, const void *saddr, |
| unsigned int len) |
| { |
| struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); |
| |
| eth->h_proto = htons(type); |
| memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len); |
| memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len); |
| eth->h_dest[ETH_ALEN - 1] ^= 0x01; /* dest is us xor 1 */ |
| return dev->hard_header_len; |
| } |
| |
| /** |
| * @brief WILC_WFI_ChangeMtu |
| * @details The "change_mtu" method is usually not needed. |
| * If you need it, it must be like this. |
| * @param[in] net_device *dev : Network Device Driver Structure |
| * @param[in] new_mtu : |
| * @return int : Returns 0 on Success. |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| int WILC_WFI_ChangeMtu(struct net_device *dev, int new_mtu) |
| { |
| unsigned long flags; |
| struct WILC_WFI_priv *priv = netdev_priv(dev); |
| spinlock_t *lock = &priv->lock; |
| |
| /* check ranges */ |
| if ((new_mtu < 68) || (new_mtu > 1500)) |
| return -EINVAL; |
| /* |
| * Do anything you need, and the accept the value |
| */ |
| spin_lock_irqsave(lock, flags); |
| dev->mtu = new_mtu; |
| spin_unlock_irqrestore(lock, flags); |
| return 0; /* success */ |
| } |
| |
| static const struct header_ops WILC_WFI_header_ops = { |
| .create = WILC_WFI_Header, |
| .rebuild = WILC_WFI_RebuildHeader, |
| .cache = NULL, /* disable caching */ |
| }; |
| |
| |
| static const struct net_device_ops WILC_WFI_netdev_ops = { |
| .ndo_open = WILC_WFI_Open, |
| .ndo_stop = WILC_WFI_Release, |
| .ndo_set_config = WILC_WFI_Config, |
| .ndo_start_xmit = WILC_WFI_Tx, |
| .ndo_do_ioctl = WILC_WFI_Ioctl, |
| .ndo_get_stats = WILC_WFI_Stats, |
| .ndo_change_mtu = WILC_WFI_ChangeMtu, |
| .ndo_tx_timeout = WILC_WFI_TxTimeout, |
| }; |
| |
| /** |
| * @brief WILC_WFI_Init |
| * @details The init function (sometimes called probe). |
| * It is invoked by register_netdev() |
| * @param[in] net_device *dev: |
| * @return NONE |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| void WILC_WFI_Init(struct net_device *dev) |
| { |
| struct WILC_WFI_priv *priv; |
| |
| |
| /* |
| * Then, assign other fields in dev, using ether_setup() and some |
| * hand assignments |
| */ |
| ether_setup(dev); /* assign some of the fields */ |
| /* 1- Allocate space */ |
| |
| dev->netdev_ops = &WILC_WFI_netdev_ops; |
| dev->header_ops = &WILC_WFI_header_ops; |
| dev->watchdog_timeo = timeout; |
| /* keep the default flags, just add NOARP */ |
| dev->flags |= IFF_NOARP; |
| dev->features |= NETIF_F_NO_CSUM; |
| /* |
| * Then, initialize the priv field. This encloses the statistics |
| * and a few private fields. |
| */ |
| priv = netdev_priv(dev); |
| memset(priv, 0, sizeof(struct WILC_WFI_priv)); |
| priv->dev = dev; |
| netif_napi_add(dev, &priv->napi, WILC_WFI_Poll, 2); |
| /* The last parameter above is the NAPI "weight". */ |
| spin_lock_init(&priv->lock); |
| WILC_WFI_RxInts(dev, 1); /* enable receive interrupts */ |
| WILC_WFI_SetupPool(dev); |
| } |
| |
| /** |
| * @brief WILC_WFI_Stat |
| * @details Return statistics to the caller |
| * @param[in] net_device *dev: |
| * @return WILC_WFI_Stats : Return net_device_stats stucture with the |
| * network device driver private data contents. |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| |
| void WILC_WFI_Cleanup(void) |
| { |
| int i; |
| struct WILC_WFI_priv *priv[2]; |
| |
| /*if(hwsim_mon!=NULL) |
| * { |
| * PRINT_D(RX_DBG, "Freeing monitor interface\n"); |
| * unregister_netdev(hwsim_mon); |
| * free_netdev(hwsim_mon); |
| * }*/ |
| for (i = 0; i < 2; i++) { |
| priv[i] = netdev_priv(WILC_WFI_devs[i]); |
| |
| if (WILC_WFI_devs[i]) { |
| PRINT_D(RX_DBG, "Unregistering\n"); |
| unregister_netdev(WILC_WFI_devs[i]); |
| WILC_WFI_TearDownPool(WILC_WFI_devs[i]); |
| free_netdev(WILC_WFI_devs[i]); |
| PRINT_D(RX_DBG, "[NETDEV]Stopping interface\n"); |
| WILC_WFI_DeInitHostInt(WILC_WFI_devs[i]); |
| WILC_WFI_WiphyFree(WILC_WFI_devs[i]); |
| } |
| |
| } |
| /* unregister_netdev(hwsim_mon); */ |
| WILC_WFI_deinit_mon_interface(); |
| return; |
| } |
| |
| |
| void StartConfigSim(void); |
| |
| |
| |
| |
| |
| |
| |
| /** |
| * @brief WILC_WFI_Stat |
| * @details Return statistics to the caller |
| * @param[in] net_device *dev: |
| * @return WILC_WFI_Stats : Return net_device_stats stucture with the |
| * network device driver private data contents. |
| * @author mdaftedar |
| * @date 01 MAR 2012 |
| * @version 1.0 |
| */ |
| int WILC_WFI_InitModule(void) |
| { |
| |
| int result, i, ret = -ENOMEM; |
| struct WILC_WFI_priv *priv[2], *netpriv; |
| struct wireless_dev *wdev; |
| WILC_WFI_Interrupt = use_napi ? WILC_WFI_NapiInterrupt : WILC_WFI_RegularInterrupt; |
| char buf[IFNAMSIZ]; |
| |
| for (i = 0; i < 2; i++) { |
| |
| /* Allocate the net devices */ |
| WILC_WFI_devs[i] = alloc_netdev(sizeof(struct WILC_WFI_priv), "wlan%d", |
| WILC_WFI_Init); |
| if (WILC_WFI_devs[i] == NULL) |
| goto out; |
| /* priv[i] = netdev_priv(WILC_WFI_devs[i]); */ |
| |
| wdev = WILC_WFI_WiphyRegister(WILC_WFI_devs[i]); |
| WILC_WFI_devs[i]->ieee80211_ptr = wdev; |
| netpriv = netdev_priv(WILC_WFI_devs[i]); |
| netpriv->dev->ieee80211_ptr = wdev; |
| netpriv->dev->ml_priv = netpriv; |
| wdev->netdev = netpriv->dev; |
| |
| /*Registering the net device*/ |
| result = register_netdev(WILC_WFI_devs[i]); |
| if (result) |
| PRINT_D(RX_DBG, "WILC_WFI: error %i registering device \"%s\"\n", |
| result, WILC_WFI_devs[i]->name); |
| else |
| ret = 0; |
| } |
| |
| |
| /*init atmel driver */ |
| priv[0] = netdev_priv(WILC_WFI_devs[0]); |
| priv[1] = netdev_priv(WILC_WFI_devs[1]); |
| |
| if (priv[1]->dev->ieee80211_ptr->wiphy->interface_modes && BIT(NL80211_IFTYPE_MONITOR)) { |
| /* snprintf(buf, IFNAMSIZ, "mon.%s", priv[1]->dev->name); */ |
| /* WILC_WFI_init_mon_interface(); */ |
| /* priv[1]->monitor_flag = 1; */ |
| |
| } |
| priv[0]->bCfgScanning = false; |
| priv[0]->u32RcvdChCount = 0; |
| |
| WILC_memset(priv[0]->au8AssociatedBss, 0xFF, ETH_ALEN); |
| |
| |
| /* ret = host_int_init(&priv[0]->hWILCWFIDrv); */ |
| /*copy handle to the other driver*/ |
| /* priv[1]->hWILCWFIDrv = priv[0]->hWILCWFIDrv; */ |
| if (ret) { |
| PRINT_ER("Error Init Driver\n"); |
| } |
| |
| |
| out: |
| if (ret) |
| WILC_WFI_Cleanup(); |
| return ret; |
| |
| |
| } |
| |
| |
| module_init(WILC_WFI_InitModule); |
| module_exit(WILC_WFI_Cleanup); |
| |
| #endif |