|
|
|
@ -41,6 +41,8 @@ static void housekeeping_disable(struct zd_mac *mac); |
|
|
|
|
|
|
|
|
|
static void set_multicast_hash_handler(struct work_struct *work); |
|
|
|
|
|
|
|
|
|
static void do_rx(unsigned long mac_ptr); |
|
|
|
|
|
|
|
|
|
int zd_mac_init(struct zd_mac *mac, |
|
|
|
|
struct net_device *netdev, |
|
|
|
|
struct usb_interface *intf) |
|
|
|
@ -53,6 +55,10 @@ int zd_mac_init(struct zd_mac *mac, |
|
|
|
|
INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work); |
|
|
|
|
INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work); |
|
|
|
|
|
|
|
|
|
skb_queue_head_init(&mac->rx_queue); |
|
|
|
|
tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac); |
|
|
|
|
tasklet_disable(&mac->rx_tasklet); |
|
|
|
|
|
|
|
|
|
ieee_init(ieee); |
|
|
|
|
softmac_init(ieee80211_priv(netdev)); |
|
|
|
|
zd_chip_init(&mac->chip, netdev, intf); |
|
|
|
@ -140,6 +146,8 @@ out: |
|
|
|
|
void zd_mac_clear(struct zd_mac *mac) |
|
|
|
|
{ |
|
|
|
|
flush_workqueue(zd_workqueue); |
|
|
|
|
skb_queue_purge(&mac->rx_queue); |
|
|
|
|
tasklet_kill(&mac->rx_tasklet); |
|
|
|
|
zd_chip_clear(&mac->chip); |
|
|
|
|
ZD_ASSERT(!spin_is_locked(&mac->lock)); |
|
|
|
|
ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); |
|
|
|
@ -168,6 +176,8 @@ int zd_mac_open(struct net_device *netdev) |
|
|
|
|
struct zd_chip *chip = &mac->chip; |
|
|
|
|
int r; |
|
|
|
|
|
|
|
|
|
tasklet_enable(&mac->rx_tasklet); |
|
|
|
|
|
|
|
|
|
r = zd_chip_enable_int(chip); |
|
|
|
|
if (r < 0) |
|
|
|
|
goto out; |
|
|
|
@ -218,6 +228,8 @@ int zd_mac_stop(struct net_device *netdev) |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
zd_chip_disable_rx(chip); |
|
|
|
|
skb_queue_purge(&mac->rx_queue); |
|
|
|
|
tasklet_disable(&mac->rx_tasklet); |
|
|
|
|
housekeeping_disable(mac); |
|
|
|
|
ieee80211softmac_stop(netdev); |
|
|
|
|
|
|
|
|
@ -470,13 +482,13 @@ static void bssinfo_change(struct net_device *netdev, u32 changes) |
|
|
|
|
|
|
|
|
|
if (changes & IEEE80211SOFTMAC_BSSINFOCHG_RATES) { |
|
|
|
|
/* Set RTS rate to highest available basic rate */ |
|
|
|
|
u8 rate = ieee80211softmac_highest_supported_rate(softmac, |
|
|
|
|
u8 hi_rate = ieee80211softmac_highest_supported_rate(softmac, |
|
|
|
|
&bssinfo->supported_rates, 1); |
|
|
|
|
rate = rate_to_zd_rate(rate); |
|
|
|
|
hi_rate = rate_to_zd_rate(hi_rate); |
|
|
|
|
|
|
|
|
|
spin_lock_irqsave(&mac->lock, flags); |
|
|
|
|
if (rate != mac->rts_rate) { |
|
|
|
|
mac->rts_rate = rate; |
|
|
|
|
if (hi_rate != mac->rts_rate) { |
|
|
|
|
mac->rts_rate = hi_rate; |
|
|
|
|
need_set_rts_cts = 1; |
|
|
|
|
} |
|
|
|
|
spin_unlock_irqrestore(&mac->lock, flags); |
|
|
|
@ -1072,43 +1084,75 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats, |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length) |
|
|
|
|
static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb) |
|
|
|
|
{ |
|
|
|
|
int r; |
|
|
|
|
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
|
|
|
|
struct ieee80211_rx_stats stats; |
|
|
|
|
const struct rx_status *status; |
|
|
|
|
struct sk_buff *skb; |
|
|
|
|
|
|
|
|
|
if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN + |
|
|
|
|
IEEE80211_FCS_LEN + sizeof(struct rx_status)) |
|
|
|
|
return -EINVAL; |
|
|
|
|
if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN + |
|
|
|
|
IEEE80211_FCS_LEN + sizeof(struct rx_status)) |
|
|
|
|
{ |
|
|
|
|
dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n", |
|
|
|
|
skb->len); |
|
|
|
|
goto free_skb; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
r = fill_rx_stats(&stats, &status, mac, buffer, length); |
|
|
|
|
if (r) |
|
|
|
|
return r; |
|
|
|
|
r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len); |
|
|
|
|
if (r) { |
|
|
|
|
/* Only packets with rx errors are included here. */ |
|
|
|
|
goto free_skb; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+ |
|
|
|
|
sizeof(struct rx_status); |
|
|
|
|
buffer += ZD_PLCP_HEADER_SIZE; |
|
|
|
|
__skb_pull(skb, ZD_PLCP_HEADER_SIZE); |
|
|
|
|
__skb_trim(skb, skb->len - |
|
|
|
|
(IEEE80211_FCS_LEN + sizeof(struct rx_status))); |
|
|
|
|
|
|
|
|
|
update_qual_rssi(mac, buffer, length, stats.signal, stats.rssi); |
|
|
|
|
update_qual_rssi(mac, skb->data, skb->len, stats.signal, |
|
|
|
|
status->signal_strength); |
|
|
|
|
|
|
|
|
|
r = filter_rx(ieee, buffer, length, &stats); |
|
|
|
|
if (r <= 0) |
|
|
|
|
return r; |
|
|
|
|
r = filter_rx(ieee, skb->data, skb->len, &stats); |
|
|
|
|
if (r <= 0) { |
|
|
|
|
if (r < 0) |
|
|
|
|
dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n"); |
|
|
|
|
goto free_skb; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length); |
|
|
|
|
if (!skb) |
|
|
|
|
return -ENOMEM; |
|
|
|
|
if (ieee->iw_mode == IW_MODE_MONITOR) |
|
|
|
|
fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac, |
|
|
|
|
fill_rt_header(skb_push(skb, sizeof(struct zd_rt_hdr)), mac, |
|
|
|
|
&stats, status); |
|
|
|
|
memcpy(skb_put(skb, length), buffer, length); |
|
|
|
|
|
|
|
|
|
r = ieee80211_rx(ieee, skb, &stats); |
|
|
|
|
if (!r) |
|
|
|
|
dev_kfree_skb_any(skb); |
|
|
|
|
if (r) |
|
|
|
|
return; |
|
|
|
|
free_skb: |
|
|
|
|
/* We are always in a soft irq. */ |
|
|
|
|
dev_kfree_skb(skb); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void do_rx(unsigned long mac_ptr) |
|
|
|
|
{ |
|
|
|
|
struct zd_mac *mac = (struct zd_mac *)mac_ptr; |
|
|
|
|
struct sk_buff *skb; |
|
|
|
|
|
|
|
|
|
while ((skb = skb_dequeue(&mac->rx_queue)) != NULL) |
|
|
|
|
zd_mac_rx(mac, skb); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length) |
|
|
|
|
{ |
|
|
|
|
struct sk_buff *skb; |
|
|
|
|
|
|
|
|
|
skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length); |
|
|
|
|
if (!skb) { |
|
|
|
|
dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n"); |
|
|
|
|
return -ENOMEM; |
|
|
|
|
} |
|
|
|
|
skb_reserve(skb, sizeof(struct zd_rt_hdr)); |
|
|
|
|
memcpy(__skb_put(skb, length), buffer, length); |
|
|
|
|
skb_queue_tail(&mac->rx_queue, skb); |
|
|
|
|
tasklet_schedule(&mac->rx_tasklet); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|