diff options
author | Christian Lamparter <chunkeey@web.de> | 2008-10-15 06:07:16 +0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-11-01 02:00:33 +0300 |
commit | b92f30d65aeb0502e2ed8beb80c8465578b40002 (patch) | |
tree | 7d2669d864df5368377dcad11c1bbf4be266eff5 /drivers/net/wireless/p54/p54usb.c | |
parent | 9de5776ff33a006b864341a6ec8d31f1a3c628cf (diff) | |
download | linux-b92f30d65aeb0502e2ed8beb80c8465578b40002.tar.xz |
p54: fix memory management
We have to be careful if multiple "control frames" are passed in a very short intervals to
the device's firmware. As p54_assign_address always put them into same memory location.
To guarantee that this won't happen anymore, we have to treat control frames like normal
data frames in the devices own memory management.
Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54/p54usb.c')
-rw-r--r-- | drivers/net/wireless/p54/p54usb.c | 74 |
1 files changed, 51 insertions, 23 deletions
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 68f1b80f04d9..88fb65046c71 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -135,6 +135,16 @@ static void p54u_rx_cb(struct urb *urb) usb_submit_urb(urb, GFP_ATOMIC); } +static void p54u_tx_reuse_skb_cb(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct p54u_priv *priv = (struct p54u_priv *)((struct ieee80211_hw *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)))->priv; + + skb_pull(skb, priv->common.tx_hdr_len); + usb_free_urb(urb); +} + static void p54u_tx_cb(struct urb *urb) { usb_free_urb(urb); @@ -146,6 +156,16 @@ static void p54u_tx_free_cb(struct urb *urb) usb_free_urb(urb); } +static void p54u_tx_free_skb_cb(struct urb *urb) +{ + struct sk_buff *skb = urb->context; + struct ieee80211_hw *dev = (struct ieee80211_hw *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + + p54_free_skb(dev, skb); + usb_free_urb(urb); +} + static int p54u_init_urbs(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; @@ -192,8 +212,8 @@ static void p54u_free_urbs(struct ieee80211_hw *dev) } } -static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54u_priv *priv = dev->priv; struct urb *addr_urb, *data_urb; @@ -209,11 +229,14 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, } usb_fill_bulk_urb(addr_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id, - sizeof(data->req_id), p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + &((struct p54_control_hdr *)skb->data)->req_id, 4, + p54u_tx_cb, dev); usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len, - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, + free_on_tx ? p54u_tx_free_skb_cb : + p54u_tx_reuse_skb_cb, skb); usb_submit_urb(addr_urb, GFP_ATOMIC); usb_submit_urb(data_urb, GFP_ATOMIC); @@ -232,31 +255,35 @@ static __le32 p54u_lm87_chksum(const u32 *data, size_t length) return cpu_to_le32(chk); } -static void p54u_tx_lm87(struct ieee80211_hw *dev, - struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54u_priv *priv = dev->priv; struct urb *data_urb; - struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr); + struct lm87_tx_hdr *hdr; + __le32 checksum; + __le32 addr = ((struct p54_control_hdr *)skb->data)->req_id; data_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!data_urb) return; - hdr->chksum = p54u_lm87_chksum((u32 *)data, len); - hdr->device_addr = data->req_id; + checksum = p54u_lm87_chksum((u32 *)skb->data, skb->len); + hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr)); + hdr->chksum = checksum; + hdr->device_addr = addr; usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, - len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, - dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, + free_on_tx ? p54u_tx_free_skb_cb : + p54u_tx_reuse_skb_cb, skb); usb_submit_urb(data_urb, GFP_ATOMIC); } -static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb, + int free_on_tx) { struct p54u_priv *priv = dev->priv; struct urb *int_urb, *data_urb; @@ -284,11 +311,10 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *da reg->addr = cpu_to_le32(P54U_DEV_BASE); reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); - len += sizeof(*data); - hdr = (void *)data - sizeof(*hdr); + hdr = (void *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); - hdr->device_addr = data->req_id; - hdr->len = cpu_to_le16(len); + hdr->device_addr = ((struct p54_control_hdr *)skb->data)->req_id; + hdr->len = cpu_to_le16(skb->len + sizeof(struct p54_control_hdr)); usb_fill_bulk_urb(int_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), @@ -296,8 +322,10 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *da usb_submit_urb(int_urb, GFP_ATOMIC); usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr), - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, + free_on_tx ? p54u_tx_free_skb_cb : + p54u_tx_reuse_skb_cb, skb); usb_submit_urb(data_urb, GFP_ATOMIC); } |