| /* |
| * WUSB Wire Adapter: WLP interface |
| * Driver for the Linux Network stack. |
| * |
| * Copyright (C) 2005-2006 Intel Corporation |
| * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License version |
| * 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| * 02110-1301, USA. |
| * |
| * |
| * i1480u's RX handling is simple. i1480u will send the received |
| * network packets broken up in fragments; 1 to N fragments make a |
| * packet, we assemble them together and deliver the packet with netif_rx(). |
| * |
| * Beacuse each USB transfer is a *single* fragment (except when the |
| * transfer contains a first fragment), each URB called thus |
| * back contains one or two fragments. So we queue N URBs, each with its own |
| * fragment buffer. When a URB is done, we process it (adding to the |
| * current skb from the fragment buffer until complete). Once |
| * processed, we requeue the URB. There is always a bunch of URBs |
| * ready to take data, so the intergap should be minimal. |
| * |
| * An URB's transfer buffer is the data field of a socket buffer. This |
| * reduces copying as data can be passed directly to network layer. If a |
| * complete packet or 1st fragment is received the URB's transfer buffer is |
| * taken away from it and used to send data to the network layer. In this |
| * case a new transfer buffer is allocated to the URB before being requeued. |
| * If a "NEXT" or "LAST" fragment is received, the fragment contents is |
| * appended to the RX packet under construction and the transfer buffer |
| * is reused. To be able to use this buffer to assemble complete packets |
| * we set each buffer's size to that of the MAX ethernet packet that can |
| * be received. There is thus room for improvement in memory usage. |
| * |
| * When the max tx fragment size increases, we should be able to read |
| * data into the skbs directly with very simple code. |
| * |
| * ROADMAP: |
| * |
| * ENTRY POINTS: |
| * |
| * i1480u_rx_setup(): setup RX context [from i1480u_open()] |
| * |
| * i1480u_rx_release(): release RX context [from i1480u_stop()] |
| * |
| * i1480u_rx_cb(): called when the RX USB URB receives a |
| * packet. It removes the header and pushes it up |
| * the Linux netdev stack with netif_rx(). |
| * |
| * i1480u_rx_buffer() |
| * i1480u_drop() and i1480u_fix() |
| * i1480u_skb_deliver |
| * |
| */ |
| |
| #include <linux/netdevice.h> |
| #include <linux/etherdevice.h> |
| #include "i1480u-wlp.h" |
| |
| #define D_LOCAL 0 |
| #include <linux/uwb/debug.h> |
| |
| |
| /** |
| * Setup the RX context |
| * |
| * Each URB is provided with a transfer_buffer that is the data field |
| * of a new socket buffer. |
| */ |
| int i1480u_rx_setup(struct i1480u *i1480u) |
| { |
| int result, cnt; |
| struct device *dev = &i1480u->usb_iface->dev; |
| struct net_device *net_dev = i1480u->net_dev; |
| struct usb_endpoint_descriptor *epd; |
| struct sk_buff *skb; |
| |
| /* Alloc RX stuff */ |
| i1480u->rx_skb = NULL; /* not in process of receiving packet */ |
| result = -ENOMEM; |
| epd = &i1480u->usb_iface->cur_altsetting->endpoint[1].desc; |
| for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { |
| struct i1480u_rx_buf *rx_buf = &i1480u->rx_buf[cnt]; |
| rx_buf->i1480u = i1480u; |
| skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE); |
| if (!skb) { |
| dev_err(dev, |
| "RX: cannot allocate RX buffer %d\n", cnt); |
| result = -ENOMEM; |
| goto error; |
| } |
| skb->dev = net_dev; |
| skb->ip_summed = CHECKSUM_NONE; |
| skb_reserve(skb, 2); |
| rx_buf->data = skb; |
| rx_buf->urb = usb_alloc_urb(0, GFP_KERNEL); |
| if (unlikely(rx_buf->urb == NULL)) { |
| dev_err(dev, "RX: cannot allocate URB %d\n", cnt); |
| result = -ENOMEM; |
| goto error; |
| } |
| usb_fill_bulk_urb(rx_buf->urb, i1480u->usb_dev, |
| usb_rcvbulkpipe(i1480u->usb_dev, epd->bEndpointAddress), |
| rx_buf->data->data, i1480u_MAX_RX_PKT_SIZE - 2, |
| i1480u_rx_cb, rx_buf); |
| result = usb_submit_urb(rx_buf->urb, GFP_NOIO); |
| if (unlikely(result < 0)) { |
| dev_err(dev, "RX: cannot submit URB %d: %d\n", |
| cnt, result); |
| goto error; |
| } |
| } |
| return 0; |
| |
| error: |
| i1480u_rx_release(i1480u); |
| return result; |
| } |
| |
| |
| /** Release resources associated to the rx context */ |
| void i1480u_rx_release(struct i1480u *i1480u) |
| { |
| int cnt; |
| for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { |
| if (i1480u->rx_buf[cnt].data) |
| dev_kfree_skb(i1480u->rx_buf[cnt].data); |
| if (i1480u->rx_buf[cnt].urb) { |
| usb_kill_urb(i1480u->rx_buf[cnt].urb); |
| usb_free_urb(i1480u->rx_buf[cnt].urb); |
| } |
| } |
| if (i1480u->rx_skb != NULL) |
| dev_kfree_skb(i1480u->rx_skb); |
| } |
| |
| static |
| void i1480u_rx_unlink_urbs(struct i1480u *i1480u) |
| { |
| int cnt; |
| for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { |
| if (i1480u->rx_buf[cnt].urb) |
| usb_unlink_urb(i1480u->rx_buf[cnt].urb); |
| } |
| } |
| |
| /** Fix an out-of-sequence packet */ |
| #define i1480u_fix(i1480u, msg...) \ |
| do { \ |
| if (printk_ratelimit()) \ |
| dev_err(&i1480u->usb_iface->dev, msg); \ |
| dev_kfree_skb_irq(i1480u->rx_skb); \ |
| i1480u->rx_skb = NULL; \ |
| i1480u->rx_untd_pkt_size = 0; \ |
| } while (0) |
| |
| |
| /** Drop an out-of-sequence packet */ |
| #define i1480u_drop(i1480u, msg...) \ |
| do { \ |
| if (printk_ratelimit()) \ |
| dev_err(&i1480u->usb_iface->dev, msg); \ |
| i1480u->stats.rx_dropped++; \ |
| } while (0) |
| |
| |
| |
| |
| /** Finalizes setting up the SKB and delivers it |
| * |
| * We first pass the incoming frame to WLP substack for verification. It |
| * may also be a WLP association frame in which case WLP will take over the |
| * processing. If WLP does not take it over it will still verify it, if the |
| * frame is invalid the skb will be freed by WLP and we will not continue |
| * parsing. |
| * */ |
| static |
| void i1480u_skb_deliver(struct i1480u *i1480u) |
| { |
| int should_parse; |
| struct net_device *net_dev = i1480u->net_dev; |
| struct device *dev = &i1480u->usb_iface->dev; |
| |
| d_printf(6, dev, "RX delivered pre skb(%p), %u bytes\n", |
| i1480u->rx_skb, i1480u->rx_skb->len); |
| d_dump(7, dev, i1480u->rx_skb->data, i1480u->rx_skb->len); |
| should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb, |
| &i1480u->rx_srcaddr); |
| if (!should_parse) |
| goto out; |
| i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev); |
| d_printf(5, dev, "RX delivered skb(%p), %u bytes\n", |
| i1480u->rx_skb, i1480u->rx_skb->len); |
| d_dump(7, dev, i1480u->rx_skb->data, |
| i1480u->rx_skb->len > 72 ? 72 : i1480u->rx_skb->len); |
| i1480u->stats.rx_packets++; |
| i1480u->stats.rx_bytes += i1480u->rx_untd_pkt_size; |
| net_dev->last_rx = jiffies; |
| /* FIXME: flow control: check netif_rx() retval */ |
| |
| netif_rx(i1480u->rx_skb); /* deliver */ |
| out: |
| i1480u->rx_skb = NULL; |
| i1480u->rx_untd_pkt_size = 0; |
| } |
| |
| |
| /** |
| * Process a buffer of data received from the USB RX endpoint |
| * |
| * First fragment arrives with next or last fragment. All other fragments |
| * arrive alone. |
| * |
| * /me hates long functions. |
| */ |
| static |
| void i1480u_rx_buffer(struct i1480u_rx_buf *rx_buf) |
| { |
| unsigned pkt_completed = 0; /* !0 when we got all pkt fragments */ |
| size_t untd_hdr_size, untd_frg_size; |
| size_t i1480u_hdr_size; |
| struct wlp_rx_hdr *i1480u_hdr = NULL; |
| |
| struct i1480u *i1480u = rx_buf->i1480u; |
| struct sk_buff *skb = rx_buf->data; |
| int size_left = rx_buf->urb->actual_length; |
| void *ptr = rx_buf->urb->transfer_buffer; /* also rx_buf->data->data */ |
| struct untd_hdr *untd_hdr; |
| |
| struct net_device *net_dev = i1480u->net_dev; |
| struct device *dev = &i1480u->usb_iface->dev; |
| struct sk_buff *new_skb; |
| |
| #if 0 |
| dev_fnstart(dev, |
| "(i1480u %p ptr %p size_left %zu)\n", i1480u, ptr, size_left); |
| dev_err(dev, "RX packet, %zu bytes\n", size_left); |
| dump_bytes(dev, ptr, size_left); |
| #endif |
| i1480u_hdr_size = sizeof(struct wlp_rx_hdr); |
| |
| while (size_left > 0) { |
| if (pkt_completed) { |
| i1480u_drop(i1480u, "RX: fragment follows completed" |
| "packet in same buffer. Dropping\n"); |
| break; |
| } |
| untd_hdr = ptr; |
| if (size_left < sizeof(*untd_hdr)) { /* Check the UNTD header */ |
| i1480u_drop(i1480u, "RX: short UNTD header! Dropping\n"); |
| goto out; |
| } |
| if (unlikely(untd_hdr_rx_tx(untd_hdr) == 0)) { /* Paranoia: TX set? */ |
| i1480u_drop(i1480u, "RX: TX bit set! Dropping\n"); |
| goto out; |
| } |
| switch (untd_hdr_type(untd_hdr)) { /* Check the UNTD header type */ |
| case i1480u_PKT_FRAG_1ST: { |
| struct untd_hdr_1st *untd_hdr_1st = (void *) untd_hdr; |
| dev_dbg(dev, "1st fragment\n"); |
| untd_hdr_size = sizeof(struct untd_hdr_1st); |
| if (i1480u->rx_skb != NULL) |
| i1480u_fix(i1480u, "RX: 1st fragment out of " |
| "sequence! Fixing\n"); |
| if (size_left < untd_hdr_size + i1480u_hdr_size) { |
| i1480u_drop(i1480u, "RX: short 1st fragment! " |
| "Dropping\n"); |
| goto out; |
| } |
| i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len) |
| - i1480u_hdr_size; |
| untd_frg_size = le16_to_cpu(untd_hdr_1st->fragment_len); |
| if (size_left < untd_hdr_size + untd_frg_size) { |
| i1480u_drop(i1480u, |
| "RX: short payload! Dropping\n"); |
| goto out; |
| } |
| i1480u->rx_skb = skb; |
| i1480u_hdr = (void *) untd_hdr_1st + untd_hdr_size; |
| i1480u->rx_srcaddr = i1480u_hdr->srcaddr; |
| skb_put(i1480u->rx_skb, untd_hdr_size + untd_frg_size); |
| skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size); |
| stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7); |
| stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18); |
| rx_buf->data = NULL; /* need to create new buffer */ |
| break; |
| } |
| case i1480u_PKT_FRAG_NXT: { |
| dev_dbg(dev, "nxt fragment\n"); |
| untd_hdr_size = sizeof(struct untd_hdr_rst); |
| if (i1480u->rx_skb == NULL) { |
| i1480u_drop(i1480u, "RX: next fragment out of " |
| "sequence! Dropping\n"); |
| goto out; |
| } |
| if (size_left < untd_hdr_size) { |
| i1480u_drop(i1480u, "RX: short NXT fragment! " |
| "Dropping\n"); |
| goto out; |
| } |
| untd_frg_size = le16_to_cpu(untd_hdr->len); |
| if (size_left < untd_hdr_size + untd_frg_size) { |
| i1480u_drop(i1480u, |
| "RX: short payload! Dropping\n"); |
| goto out; |
| } |
| memmove(skb_put(i1480u->rx_skb, untd_frg_size), |
| ptr + untd_hdr_size, untd_frg_size); |
| break; |
| } |
| case i1480u_PKT_FRAG_LST: { |
| dev_dbg(dev, "Lst fragment\n"); |
| untd_hdr_size = sizeof(struct untd_hdr_rst); |
| if (i1480u->rx_skb == NULL) { |
| i1480u_drop(i1480u, "RX: last fragment out of " |
| "sequence! Dropping\n"); |
| goto out; |
| } |
| if (size_left < untd_hdr_size) { |
| i1480u_drop(i1480u, "RX: short LST fragment! " |
| "Dropping\n"); |
| goto out; |
| } |
| untd_frg_size = le16_to_cpu(untd_hdr->len); |
| if (size_left < untd_frg_size + untd_hdr_size) { |
| i1480u_drop(i1480u, |
| "RX: short payload! Dropping\n"); |
| goto out; |
| } |
| memmove(skb_put(i1480u->rx_skb, untd_frg_size), |
| ptr + untd_hdr_size, untd_frg_size); |
| pkt_completed = 1; |
| break; |
| } |
| case i1480u_PKT_FRAG_CMP: { |
| dev_dbg(dev, "cmp fragment\n"); |
| untd_hdr_size = sizeof(struct untd_hdr_cmp); |
| if (i1480u->rx_skb != NULL) |
| i1480u_fix(i1480u, "RX: fix out-of-sequence CMP" |
| " fragment!\n"); |
| if (size_left < untd_hdr_size + i1480u_hdr_size) { |
| i1480u_drop(i1480u, "RX: short CMP fragment! " |
| "Dropping\n"); |
| goto out; |
| } |
| i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len); |
| untd_frg_size = i1480u->rx_untd_pkt_size; |
| if (size_left < i1480u->rx_untd_pkt_size + untd_hdr_size) { |
| i1480u_drop(i1480u, |
| "RX: short payload! Dropping\n"); |
| goto out; |
| } |
| i1480u->rx_skb = skb; |
| i1480u_hdr = (void *) untd_hdr + untd_hdr_size; |
| i1480u->rx_srcaddr = i1480u_hdr->srcaddr; |
| stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7); |
| stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18); |
| skb_put(i1480u->rx_skb, untd_hdr_size + i1480u->rx_untd_pkt_size); |
| skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size); |
| rx_buf->data = NULL; /* for hand off skb to network stack */ |
| pkt_completed = 1; |
| i1480u->rx_untd_pkt_size -= i1480u_hdr_size; /* accurate stat */ |
| break; |
| } |
| default: |
| i1480u_drop(i1480u, "RX: unknown packet type %u! " |
| "Dropping\n", untd_hdr_type(untd_hdr)); |
| goto out; |
| } |
| size_left -= untd_hdr_size + untd_frg_size; |
| if (size_left > 0) |
| ptr += untd_hdr_size + untd_frg_size; |
| } |
| if (pkt_completed) |
| i1480u_skb_deliver(i1480u); |
| out: |
| /* recreate needed RX buffers*/ |
| if (rx_buf->data == NULL) { |
| /* buffer is being used to receive packet, create new */ |
| new_skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE); |
| if (!new_skb) { |
| if (printk_ratelimit()) |
| dev_err(dev, |
| "RX: cannot allocate RX buffer\n"); |
| } else { |
| new_skb->dev = net_dev; |
| new_skb->ip_summed = CHECKSUM_NONE; |
| skb_reserve(new_skb, 2); |
| rx_buf->data = new_skb; |
| } |
| } |
| return; |
| } |
| |
| |
| /** |
| * Called when an RX URB has finished receiving or has found some kind |
| * of error condition. |
| * |
| * LIMITATIONS: |
| * |
| * - We read USB-transfers, each transfer contains a SINGLE fragment |
| * (can contain a complete packet, or a 1st, next, or last fragment |
| * of a packet). |
| * Looks like a transfer can contain more than one fragment (07/18/06) |
| * |
| * - Each transfer buffer is the size of the maximum packet size (minus |
| * headroom), i1480u_MAX_PKT_SIZE - 2 |
| * |
| * - We always read the full USB-transfer, no partials. |
| * |
| * - Each transfer is read directly into a skb. This skb will be used to |
| * send data to the upper layers if it is the first fragment or a complete |
| * packet. In the other cases the data will be copied from the skb to |
| * another skb that is being prepared for the upper layers from a prev |
| * first fragment. |
| * |
| * It is simply too much of a pain. Gosh, there should be a unified |
| * SG infrastructure for *everything* [so that I could declare a SG |
| * buffer, pass it to USB for receiving, append some space to it if |
| * I wish, receive more until I have the whole chunk, adapt |
| * pointers on each fragment to remove hardware headers and then |
| * attach that to an skbuff and netif_rx()]. |
| */ |
| void i1480u_rx_cb(struct urb *urb) |
| { |
| int result; |
| int do_parse_buffer = 1; |
| struct i1480u_rx_buf *rx_buf = urb->context; |
| struct i1480u *i1480u = rx_buf->i1480u; |
| struct device *dev = &i1480u->usb_iface->dev; |
| unsigned long flags; |
| u8 rx_buf_idx = rx_buf - i1480u->rx_buf; |
| |
| switch (urb->status) { |
| case 0: |
| break; |
| case -ECONNRESET: /* Not an error, but a controlled situation; */ |
| case -ENOENT: /* (we killed the URB)...so, no broadcast */ |
| case -ESHUTDOWN: /* going away! */ |
| dev_err(dev, "RX URB[%u]: goind down %d\n", |
| rx_buf_idx, urb->status); |
| goto error; |
| default: |
| dev_err(dev, "RX URB[%u]: unknown status %d\n", |
| rx_buf_idx, urb->status); |
| if (edc_inc(&i1480u->rx_errors, EDC_MAX_ERRORS, |
| EDC_ERROR_TIMEFRAME)) { |
| dev_err(dev, "RX: max acceptable errors exceeded," |
| " resetting device.\n"); |
| i1480u_rx_unlink_urbs(i1480u); |
| wlp_reset_all(&i1480u->wlp); |
| goto error; |
| } |
| do_parse_buffer = 0; |
| break; |
| } |
| spin_lock_irqsave(&i1480u->lock, flags); |
| /* chew the data fragments, extract network packets */ |
| if (do_parse_buffer) { |
| i1480u_rx_buffer(rx_buf); |
| if (rx_buf->data) { |
| rx_buf->urb->transfer_buffer = rx_buf->data->data; |
| result = usb_submit_urb(rx_buf->urb, GFP_ATOMIC); |
| if (result < 0) { |
| dev_err(dev, "RX URB[%u]: cannot submit %d\n", |
| rx_buf_idx, result); |
| } |
| } |
| } |
| spin_unlock_irqrestore(&i1480u->lock, flags); |
| error: |
| return; |
| } |
| |