📄 ib-net.c
字号:
/* iBurst (TM) compatible driver for 2.6 Linux kernel. * based on the original ArrayComm (TM) iBurst (TM) driver. * Nicholas Jefferson <nicholas@pythontraining.com.au> * 11 May 2005 * * Fixes by Nik Trevallyn-Jones. * Fixes to support new hardware by Shane MacPhillamy. * Support for 2.6.20 by Daniel Burr. * * Wireless Extension IOCTL code based on that in * orinoco.c (v0.15rc2 28 July 2004) in the orinoco driver, written by * Pavel Roskin, David Gibson, Jean Tourrilhes & Benjamin Herrenschmidt. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */#include "ib-net.h"#include <linux/version.h>#include <linux/etherdevice.h>#include <net/iw_handler.h>#define IB_NET_QUEUE_LO 4#define IB_NET_QUEUE_HI 10#define IB_PROTO_CONTROL 0x00#define IB_CONTROL_STATUS1 0x05#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */#define IW_QUAL_LEVEL_UPDATED 0x02#define IW_QUAL_NOISE_UPDATED 0x04#endifenum ib_net_offset{ OFFSET_STATUS1_NPAYLOAD = 0x00, OFFSET_STATUS1_TYPE = 0x01, OFFSET_STATUS1_LEVEL = 0x02, OFFSET_STATUS1_UPCOUNT = 0x03, OFFSET_STATUS1_DOWNCOUNT = 0x04, OFFSET_STATUS1_SAMPLE = 0x05, OFFSET_STATUS1_SUCCESS = 0x0a, OFFSET_STATUS1_ATTEMPT = 0x0b, OFFSET_STATUS1_SINR = 0x0c,};static int debug = 0;module_param(debug, int, 0);#define DEBUG(n, args...) if (debug < (n)) ; else printk(KERN_INFO args)/** * ifname - interface name. */static char *ifname = "ib%d";module_param(ifname, charp, 0);spinlock_t ib_lock = SPIN_LOCK_UNLOCKED;/** * ib_net_rx_deliver - deliver received radio frame as ethernet frame. * called under ib_lock * @modem: modem state. * @nbuf: radio frame size. */static void ib_net_rx_deliver(struct ib_net_modem_t *modem, int nbuf){ struct ib_net_radio_t *radio = (struct ib_net_radio_t*) modem->rx_buf; struct ib_net_ether_t *ether; struct sk_buff *skb; int npayload; modem->stats.rx_bytes += nbuf; modem->stats.rx_packets += 1; modem->netdev->last_rx = jiffies; npayload = nbuf - IB_NET_RADIO_HEAD; skb = alloc_skb(IB_NET_ETHER_HEAD + npayload, GFP_ATOMIC); if (skb == NULL) { modem->stats.rx_dropped += 1; return; } skb->dev = modem->netdev; ether = (struct ib_net_ether_t*) skb_put(skb, IB_NET_ETHER_HEAD + npayload); memcpy(ether->source, modem->netdev->dev_addr, ETH_ALEN); if (radio->word[0] & FLAG_BROADCAST) memset(ether->dest, 0xff, ETH_ALEN); else { ether->source[ETH_ALEN - 1] ^= 1; memcpy(ether->dest, modem->netdev->dev_addr, ETH_ALEN); } ether->proto[0] = radio->proto[0]; ether->proto[1] = radio->proto[1]; memcpy(ether->payload, radio->payload, npayload); skb->protocol = eth_type_trans(skb, modem->netdev); skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx(skb);}/** * ib_net_rx_control_parse - process received control frame. * called under ib_lock * @modem: modem state. * @nbuf: control frame size. */static void ib_net_rx_control_parse(struct ib_net_modem_t *modem, int nbuf){ struct ib_net_radio_t *radio = (struct ib_net_radio_t*) modem->rx_buf; int32_t *payload = (int32_t*) &radio->payload; int npayload, type, level, sinr, attempt, success;#if 17 <= WIRELESS_EXT int sample, upcount, downcount;#endif level = 0; // to silence a benign warning npayload = nbuf - IB_NET_RADIO_HEAD; if (npayload < 8) return; if (npayload != be32_to_cpup(payload + OFFSET_STATUS1_NPAYLOAD)) return; type = be32_to_cpup(payload + OFFSET_STATUS1_TYPE); if (type == IB_CONTROL_STATUS1 && 12 <= npayload) { /** * level is reported as an int 0 <= n <= 100, * or -1 => invalid */ level = le32_to_cpup(payload + OFFSET_STATUS1_LEVEL); if (level != -1) { modem->wstats.qual.level = modem->wstats.qual.qual = level; modem->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED | IW_QUAL_QUAL_UPDATED; } }#if 17 <= WIRELESS_EXT if (type == IB_CONTROL_STATUS1 && 24 <= npayload) { /** * up and down throughput are reported as int byte * counts; the sample time is reported in milliseconds. * * The rates are calculated as bits/sec. */ sample = le32_to_cpup(payload + OFFSET_STATUS1_SAMPLE); upcount = le32_to_cpup(payload + OFFSET_STATUS1_UPCOUNT); downcount = le32_to_cpup(payload + OFFSET_STATUS1_DOWNCOUNT); if (sample) { modem->uprate = upcount * 1000 / sample * 8; modem->downrate = downcount * 1000 / sample * 8; } }#endif if (type == IB_CONTROL_STATUS1 && 48 <= npayload) { /** * success and attempt report the number of bursts * attempted/successful since last report. * * Missed bursts are calculated as attempt - success. */ attempt = le32_to_cpup(payload + OFFSET_STATUS1_ATTEMPT); success = le32_to_cpup(payload + OFFSET_STATUS1_SUCCESS); modem->wstats.miss.beacon = attempt - success; } if (type == IB_CONTROL_STATUS1 && 52 <= npayload) { /** * sinr (signal to interference AND noise) is reported as * actual-sinr << 4 (ie sinr * 16). * * noise is calculated as level / (sinr+1). * * Since sinr is already multiplied by 16, top and bottom of * ratio are multiplied by 16. Hence level => level*16 and * sinr+1 => sinr+16 (sinr is already multiplied by 16). */ sinr = le32_to_cpup(payload + OFFSET_STATUS1_SINR); if (sinr) { modem->wstats.qual.noise = (level * 16) / (sinr + 16); modem->wstats.qual.updated |= IW_QUAL_NOISE_UPDATED; } }}/** * ib_net_rx_parse - process received radio frame. * called under ib_lock * @modem: modem state. * @nbuf: radio frame size. */void ib_net_rx_parse(struct ib_net_modem_t *modem, int nbuf){ struct ib_net_radio_t *radio = (struct ib_net_radio_t*) modem->rx_buf; if (radio->word[0] & FLAG_EXTENSION) return; if (radio->word[1] ^ radio->check ^ 0xff) return; if (radio->proto[0] != IB_PROTO) ib_net_rx_deliver(modem, nbuf); else if (radio->proto[1] == IB_PROTO_CONTROL) ib_net_rx_control_parse(modem, nbuf); else if (modem->driver->rx_parse) modem->driver->rx_parse(modem->pdriver);}/** * ib_net_tx_prepare - prepare next radio frame for transmission. * called under ib_lock * @modem: modem state. */int ib_net_tx_prepare(struct ib_net_modem_t *modem){ struct sk_buff *skb; struct ib_net_radio_t *radio; int nqueue; nqueue = skb_queue_len(&modem->tx_queue); if (nqueue < IB_NET_QUEUE_LO) netif_wake_queue(modem->netdev); skb = skb_dequeue(&modem->tx_queue); if (skb == NULL) return 0; memcpy(modem->tx_buf, skb->data, skb->len); dev_kfree_skb(skb); radio = (struct ib_net_radio_t*) modem->tx_buf; radio->packet = modem->stats.tx_packets & 0xff; modem->netdev->trans_start = jiffies; return skb->len;}/** * ib_net_deregister - deregister network device. * @modem: modem state. */void ib_net_deregister(struct ib_net_modem_t *modem){ unregister_netdev(modem->netdev); free_netdev(modem->netdev);}/** * ib_net_poll - bottom half handler for interrupts. * @_modem: modem state. */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)static void ib_net_poll(void *_modem)#elsestatic void ib_net_poll(struct work_struct *work)#endif{ unsigned long state; struct ib_net_modem_t *modem = #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) _modem;#else container_of(work, struct ib_net_modem_t, work_queue);#endif spin_lock_irqsave(&ib_lock, state); if (modem->driver->poll) modem->driver->poll(modem->pdriver); spin_unlock_irqrestore(&ib_lock, state);}/** * ib_net_stats - return network device statistics. * @netdev: network device state. */static struct net_device_stats *ib_net_stats(struct net_device *netdev){ struct ib_net_modem_t *modem = netdev->priv; return &modem->stats;}/** * ib_wireless_stats - return wireless statistics. * @netdev: network device state. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -