diff --git a/MAINTAINERS b/MAINTAINERS index 0b7007a9c8a4..94ad1bab633a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -152,6 +152,7 @@ F: drivers/scsi/53c700* 6LOWPAN GENERIC (BTLE/IEEE 802.15.4) M: Alexander Aring +M: Jukka Rissanen L: linux-bluetooth@vger.kernel.org L: linux-wpan@vger.kernel.org S: Maintained diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a79d657c0845..a423b84a0ed3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -275,13 +275,19 @@ struct btusb_data { struct work_struct work; struct work_struct waker; + struct usb_anchor deferred; struct usb_anchor tx_anchor; + int tx_in_flight; + spinlock_t txlock; + struct usb_anchor intr_anchor; struct usb_anchor bulk_anchor; struct usb_anchor isoc_anchor; - struct usb_anchor deferred; - int tx_in_flight; - spinlock_t txlock; + spinlock_t rxlock; + + struct sk_buff *evt_skb; + struct sk_buff *acl_skb; + struct sk_buff *sco_skb; struct usb_endpoint_descriptor *intr_ep; struct usb_endpoint_descriptor *bulk_tx_ep; @@ -296,18 +302,189 @@ struct btusb_data { int suspend_count; }; -static int inc_tx(struct btusb_data *data) +static inline void btusb_free_frags(struct btusb_data *data) { unsigned long flags; - int rv; - spin_lock_irqsave(&data->txlock, flags); - rv = test_bit(BTUSB_SUSPENDING, &data->flags); - if (!rv) - data->tx_in_flight++; - spin_unlock_irqrestore(&data->txlock, flags); + spin_lock_irqsave(&data->rxlock, flags); - return rv; + kfree_skb(data->evt_skb); + data->evt_skb = NULL; + + kfree_skb(data->acl_skb); + data->acl_skb = NULL; + + kfree_skb(data->sco_skb); + data->sco_skb = NULL; + + spin_unlock_irqrestore(&data->rxlock, flags); +} + +static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count) +{ + struct sk_buff *skb; + int err = 0; + + spin_lock(&data->rxlock); + skb = data->evt_skb; + + while (count) { + int len; + + if (!skb) { + skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE, GFP_ATOMIC); + if (!skb) { + err = -ENOMEM; + break; + } + + bt_cb(skb)->pkt_type = HCI_EVENT_PKT; + bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE; + } + + len = min_t(uint, bt_cb(skb)->expect, count); + memcpy(skb_put(skb, len), buffer, len); + + count -= len; + buffer += len; + bt_cb(skb)->expect -= len; + + if (skb->len == HCI_EVENT_HDR_SIZE) { + /* Complete event header */ + bt_cb(skb)->expect = hci_event_hdr(skb)->plen; + + if (skb_tailroom(skb) < bt_cb(skb)->expect) { + kfree_skb(skb); + skb = NULL; + + err = -EILSEQ; + break; + } + } + + if (bt_cb(skb)->expect == 0) { + /* Complete frame */ + hci_recv_frame(data->hdev, skb); + skb = NULL; + } + } + + data->evt_skb = skb; + spin_unlock(&data->rxlock); + + return err; +} + +static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count) +{ + struct sk_buff *skb; + int err = 0; + + spin_lock(&data->rxlock); + skb = data->acl_skb; + + while (count) { + int len; + + if (!skb) { + skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!skb) { + err = -ENOMEM; + break; + } + + bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; + bt_cb(skb)->expect = HCI_ACL_HDR_SIZE; + } + + len = min_t(uint, bt_cb(skb)->expect, count); + memcpy(skb_put(skb, len), buffer, len); + + count -= len; + buffer += len; + bt_cb(skb)->expect -= len; + + if (skb->len == HCI_ACL_HDR_SIZE) { + __le16 dlen = hci_acl_hdr(skb)->dlen; + + /* Complete ACL header */ + bt_cb(skb)->expect = __le16_to_cpu(dlen); + + if (skb_tailroom(skb) < bt_cb(skb)->expect) { + kfree_skb(skb); + skb = NULL; + + err = -EILSEQ; + break; + } + } + + if (bt_cb(skb)->expect == 0) { + /* Complete frame */ + hci_recv_frame(data->hdev, skb); + skb = NULL; + } + } + + data->acl_skb = skb; + spin_unlock(&data->rxlock); + + return err; +} + +static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count) +{ + struct sk_buff *skb; + int err = 0; + + spin_lock(&data->rxlock); + skb = data->sco_skb; + + while (count) { + int len; + + if (!skb) { + skb = bt_skb_alloc(HCI_MAX_SCO_SIZE, GFP_ATOMIC); + if (!skb) { + err = -ENOMEM; + break; + } + + bt_cb(skb)->pkt_type = HCI_SCODATA_PKT; + bt_cb(skb)->expect = HCI_SCO_HDR_SIZE; + } + + len = min_t(uint, bt_cb(skb)->expect, count); + memcpy(skb_put(skb, len), buffer, len); + + count -= len; + buffer += len; + bt_cb(skb)->expect -= len; + + if (skb->len == HCI_SCO_HDR_SIZE) { + /* Complete SCO header */ + bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen; + + if (skb_tailroom(skb) < bt_cb(skb)->expect) { + kfree_skb(skb); + skb = NULL; + + err = -EILSEQ; + break; + } + } + + if (bt_cb(skb)->expect == 0) { + /* Complete frame */ + hci_recv_frame(data->hdev, skb); + skb = NULL; + } + } + + data->sco_skb = skb; + spin_unlock(&data->rxlock); + + return err; } static void btusb_intr_complete(struct urb *urb) @@ -316,8 +493,8 @@ static void btusb_intr_complete(struct urb *urb) struct btusb_data *data = hci_get_drvdata(hdev); int err; - BT_DBG("%s urb %p status %d count %d", hdev->name, - urb, urb->status, urb->actual_length); + BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, + urb->actual_length); if (!test_bit(HCI_RUNNING, &hdev->flags)) return; @@ -325,9 +502,8 @@ static void btusb_intr_complete(struct urb *urb) if (urb->status == 0) { hdev->stat.byte_rx += urb->actual_length; - if (hci_recv_fragment(hdev, HCI_EVENT_PKT, - urb->transfer_buffer, - urb->actual_length) < 0) { + if (btusb_recv_intr(data, urb->transfer_buffer, + urb->actual_length) < 0) { BT_ERR("%s corrupted event packet", hdev->name); hdev->stat.err_rx++; } @@ -348,7 +524,7 @@ static void btusb_intr_complete(struct urb *urb) * -ENODEV: device got disconnected */ if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p failed to resubmit (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } } @@ -381,8 +557,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress); usb_fill_int_urb(urb, data->udev, pipe, buf, size, - btusb_intr_complete, hdev, - data->intr_ep->bInterval); + btusb_intr_complete, hdev, data->intr_ep->bInterval); urb->transfer_flags |= URB_FREE_BUFFER; @@ -392,7 +567,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) if (err < 0) { if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p submission failed (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } @@ -407,8 +582,8 @@ static void btusb_bulk_complete(struct urb *urb) struct btusb_data *data = hci_get_drvdata(hdev); int err; - BT_DBG("%s urb %p status %d count %d", hdev->name, - urb, urb->status, urb->actual_length); + BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, + urb->actual_length); if (!test_bit(HCI_RUNNING, &hdev->flags)) return; @@ -416,9 +591,8 @@ static void btusb_bulk_complete(struct urb *urb) if (urb->status == 0) { hdev->stat.byte_rx += urb->actual_length; - if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT, - urb->transfer_buffer, - urb->actual_length) < 0) { + if (btusb_recv_bulk(data, urb->transfer_buffer, + urb->actual_length) < 0) { BT_ERR("%s corrupted ACL packet", hdev->name); hdev->stat.err_rx++; } @@ -439,7 +613,7 @@ static void btusb_bulk_complete(struct urb *urb) * -ENODEV: device got disconnected */ if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p failed to resubmit (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } } @@ -469,8 +643,8 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress); - usb_fill_bulk_urb(urb, data->udev, pipe, - buf, size, btusb_bulk_complete, hdev); + usb_fill_bulk_urb(urb, data->udev, pipe, buf, size, + btusb_bulk_complete, hdev); urb->transfer_flags |= URB_FREE_BUFFER; @@ -481,7 +655,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) if (err < 0) { if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p submission failed (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } @@ -496,8 +670,8 @@ static void btusb_isoc_complete(struct urb *urb) struct btusb_data *data = hci_get_drvdata(hdev); int i, err; - BT_DBG("%s urb %p status %d count %d", hdev->name, - urb, urb->status, urb->actual_length); + BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, + urb->actual_length); if (!test_bit(HCI_RUNNING, &hdev->flags)) return; @@ -512,9 +686,8 @@ static void btusb_isoc_complete(struct urb *urb) hdev->stat.byte_rx += length; - if (hci_recv_fragment(hdev, HCI_SCODATA_PKT, - urb->transfer_buffer + offset, - length) < 0) { + if (btusb_recv_isoc(data, urb->transfer_buffer + offset, + length) < 0) { BT_ERR("%s corrupted SCO packet", hdev->name); hdev->stat.err_rx++; } @@ -535,7 +708,7 @@ static void btusb_isoc_complete(struct urb *urb) * -ENODEV: device got disconnected */ if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p failed to resubmit (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } } @@ -590,12 +763,12 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress); usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete, - hdev, data->isoc_rx_ep->bInterval); + hdev, data->isoc_rx_ep->bInterval); - urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; + urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP; __fill_isoc_descriptor(urb, size, - le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize)); + le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize)); usb_anchor_urb(urb, &data->isoc_anchor); @@ -603,7 +776,7 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) if (err < 0) { if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p submission failed (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); usb_unanchor_urb(urb); } @@ -615,11 +788,11 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) static void btusb_tx_complete(struct urb *urb) { struct sk_buff *skb = urb->context; - struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct hci_dev *hdev = (struct hci_dev *)skb->dev; struct btusb_data *data = hci_get_drvdata(hdev); - BT_DBG("%s urb %p status %d count %d", hdev->name, - urb, urb->status, urb->actual_length); + BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, + urb->actual_length); if (!test_bit(HCI_RUNNING, &hdev->flags)) goto done; @@ -642,10 +815,10 @@ done: static void btusb_isoc_tx_complete(struct urb *urb) { struct sk_buff *skb = urb->context; - struct hci_dev *hdev = (struct hci_dev *) skb->dev; + struct hci_dev *hdev = (struct hci_dev *)skb->dev; - BT_DBG("%s urb %p status %d count %d", hdev->name, - urb, urb->status, urb->actual_length); + BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status, + urb->actual_length); if (!test_bit(HCI_RUNNING, &hdev->flags)) goto done; @@ -729,6 +902,8 @@ static int btusb_close(struct hci_dev *hdev) clear_bit(BTUSB_INTR_RUNNING, &data->flags); btusb_stop_traffic(data); + btusb_free_frags(data); + err = usb_autopm_get_interface(data->intf); if (err < 0) goto failed; @@ -748,122 +923,181 @@ static int btusb_flush(struct hci_dev *hdev) BT_DBG("%s", hdev->name); usb_kill_anchored_urbs(&data->tx_anchor); + btusb_free_frags(data); return 0; } -static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) +static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb) { struct btusb_data *data = hci_get_drvdata(hdev); struct usb_ctrlrequest *dr; struct urb *urb; unsigned int pipe; + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return ERR_PTR(-ENOMEM); + + dr = kmalloc(sizeof(*dr), GFP_KERNEL); + if (!dr) { + usb_free_urb(urb); + return ERR_PTR(-ENOMEM); + } + + dr->bRequestType = data->cmdreq_type; + dr->bRequest = 0; + dr->wIndex = 0; + dr->wValue = 0; + dr->wLength = __cpu_to_le16(skb->len); + + pipe = usb_sndctrlpipe(data->udev, 0x00); + + usb_fill_control_urb(urb, data->udev, pipe, (void *)dr, + skb->data, skb->len, btusb_tx_complete, skb); + + skb->dev = (void *)hdev; + + return urb; +} + +static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct urb *urb; + unsigned int pipe; + + if (!data->bulk_tx_ep) + return ERR_PTR(-ENODEV); + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return ERR_PTR(-ENOMEM); + + pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress); + + usb_fill_bulk_urb(urb, data->udev, pipe, + skb->data, skb->len, btusb_tx_complete, skb); + + skb->dev = (void *)hdev; + + return urb; +} + +static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + struct urb *urb; + unsigned int pipe; + + if (!data->isoc_tx_ep) + return ERR_PTR(-ENODEV); + + urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); + if (!urb) + return ERR_PTR(-ENOMEM); + + pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress); + + usb_fill_int_urb(urb, data->udev, pipe, + skb->data, skb->len, btusb_isoc_tx_complete, + skb, data->isoc_tx_ep->bInterval); + + urb->transfer_flags = URB_ISO_ASAP; + + __fill_isoc_descriptor(urb, skb->len, + le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); + + skb->dev = (void *)hdev; + + return urb; +} + +static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb) +{ + struct btusb_data *data = hci_get_drvdata(hdev); int err; - BT_DBG("%s", hdev->name); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return -EBUSY; - - skb->dev = (void *) hdev; - - switch (bt_cb(skb)->pkt_type) { - case HCI_COMMAND_PKT: - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) - return -ENOMEM; - - dr = kmalloc(sizeof(*dr), GFP_ATOMIC); - if (!dr) { - usb_free_urb(urb); - return -ENOMEM; - } - - dr->bRequestType = data->cmdreq_type; - dr->bRequest = 0; - dr->wIndex = 0; - dr->wValue = 0; - dr->wLength = __cpu_to_le16(skb->len); - - pipe = usb_sndctrlpipe(data->udev, 0x00); - - usb_fill_control_urb(urb, data->udev, pipe, (void *) dr, - skb->data, skb->len, btusb_tx_complete, skb); - - hdev->stat.cmd_tx++; - break; - - case HCI_ACLDATA_PKT: - if (!data->bulk_tx_ep) - return -ENODEV; - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) - return -ENOMEM; - - pipe = usb_sndbulkpipe(data->udev, - data->bulk_tx_ep->bEndpointAddress); - - usb_fill_bulk_urb(urb, data->udev, pipe, - skb->data, skb->len, btusb_tx_complete, skb); - - hdev->stat.acl_tx++; - break; - - case HCI_SCODATA_PKT: - if (!data->isoc_tx_ep || hci_conn_num(hdev, SCO_LINK) < 1) - return -ENODEV; - - urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC); - if (!urb) - return -ENOMEM; - - pipe = usb_sndisocpipe(data->udev, - data->isoc_tx_ep->bEndpointAddress); - - usb_fill_int_urb(urb, data->udev, pipe, - skb->data, skb->len, btusb_isoc_tx_complete, - skb, data->isoc_tx_ep->bInterval); - - urb->transfer_flags = URB_ISO_ASAP; - - __fill_isoc_descriptor(urb, skb->len, - le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize)); - - hdev->stat.sco_tx++; - goto skip_waking; - - default: - return -EILSEQ; - } - - err = inc_tx(data); - if (err) { - usb_anchor_urb(urb, &data->deferred); - schedule_work(&data->waker); - err = 0; - goto done; - } - -skip_waking: usb_anchor_urb(urb, &data->tx_anchor); - err = usb_submit_urb(urb, GFP_ATOMIC); + err = usb_submit_urb(urb, GFP_KERNEL); if (err < 0) { if (err != -EPERM && err != -ENODEV) BT_ERR("%s urb %p submission failed (%d)", - hdev->name, urb, -err); + hdev->name, urb, -err); kfree(urb->setup_packet); usb_unanchor_urb(urb); } else { usb_mark_last_busy(data->udev); } -done: usb_free_urb(urb); return err; } +static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb) +{ + struct btusb_data *data = hci_get_drvdata(hdev); + unsigned long flags; + bool suspending; + + spin_lock_irqsave(&data->txlock, flags); + suspending = test_bit(BTUSB_SUSPENDING, &data->flags); + if (!suspending) + data->tx_in_flight++; + spin_unlock_irqrestore(&data->txlock, flags); + + if (!suspending) + return submit_tx_urb(hdev, urb); + + usb_anchor_urb(urb, &data->deferred); + schedule_work(&data->waker); + + usb_free_urb(urb); + return 0; +} + +static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct urb *urb; + + BT_DBG("%s", hdev->name); + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; + + switch (bt_cb(skb)->pkt_type) { + case HCI_COMMAND_PKT: + urb = alloc_ctrl_urb(hdev, skb); + if (IS_ERR(urb)) + return PTR_ERR(urb); + + hdev->stat.cmd_tx++; + return submit_or_queue_tx_urb(hdev, urb); + + case HCI_ACLDATA_PKT: + urb = alloc_bulk_urb(hdev, skb); + if (IS_ERR(urb)) + return PTR_ERR(urb); + + hdev->stat.acl_tx++; + return submit_or_queue_tx_urb(hdev, urb); + + case HCI_SCODATA_PKT: + if (hci_conn_num(hdev, SCO_LINK) < 1) + return -ENODEV; + + urb = alloc_isoc_urb(hdev, skb); + if (IS_ERR(urb)) + return PTR_ERR(urb); + + hdev->stat.sco_tx++; + return submit_tx_urb(hdev, urb); + } + + return -EILSEQ; +} + static void btusb_notify(struct hci_dev *hdev, unsigned int evt) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -940,6 +1174,7 @@ static void btusb_work(struct work_struct *work) if (hdev->voice_setting & 0x0020) { static const int alts[3] = { 2, 4, 5 }; + new_alts = alts[data->sco_num - 1]; } else { new_alts = data->sco_num; @@ -1012,7 +1247,7 @@ static int btusb_setup_csr(struct hci_dev *hdev) return -PTR_ERR(skb); } - rp = (struct hci_rp_read_local_version *) skb->data; + rp = (struct hci_rp_read_local_version *)skb->data; if (!rp->status) { if (le16_to_cpu(rp->manufacturer) != 10) { @@ -1050,7 +1285,7 @@ struct intel_version { } __packed; static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev, - struct intel_version *ver) + struct intel_version *ver) { const struct firmware *fw; char fwname[64]; @@ -1226,7 +1461,7 @@ static int btusb_check_bdaddr_intel(struct hci_dev *hdev) return -EIO; } - rp = (struct hci_rp_read_bd_addr *) skb->data; + rp = (struct hci_rp_read_bd_addr *)skb->data; if (rp->status) { BT_ERR("%s Intel device address result failed (%02x)", hdev->name, rp->status); @@ -1356,6 +1591,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) if (skb->data[0]) { u8 evt_status = skb->data[0]; + BT_ERR("%s enable Intel manufacturer mode event failed (%02x)", hdev->name, evt_status); kfree_skb(skb); @@ -1465,7 +1701,7 @@ static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: changing Intel device address failed (%ld)", - hdev->name, ret); + hdev->name, ret); return ret; } kfree_skb(skb); @@ -1540,19 +1776,19 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", - hdev->name, ret); + hdev->name, ret); goto done; } if (skb->len != sizeof(*ver)) { BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", - hdev->name); + hdev->name); kfree_skb(skb); ret = -EIO; goto done; } - ver = (struct hci_rp_read_local_version *) skb->data; + ver = (struct hci_rp_read_local_version *)skb->data; BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x " "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, ver->lmp_ver, ver->lmp_subver); @@ -1563,7 +1799,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: BCM: Download Minidrv command failed (%ld)", - hdev->name, ret); + hdev->name, ret); goto reset_fw; } kfree_skb(skb); @@ -1575,13 +1811,13 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) fw_size = fw->size; while (fw_size >= sizeof(*cmd)) { - cmd = (struct hci_command_hdr *) fw_ptr; + cmd = (struct hci_command_hdr *)fw_ptr; fw_ptr += sizeof(*cmd); fw_size -= sizeof(*cmd); if (fw_size < cmd->plen) { BT_ERR("%s: BCM: patch %s is corrupted", - hdev->name, fw_name); + hdev->name, fw_name); ret = -EINVAL; goto reset_fw; } @@ -1597,7 +1833,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: BCM: patch command %04x failed (%ld)", - hdev->name, opcode, ret); + hdev->name, opcode, ret); goto reset_fw; } kfree_skb(skb); @@ -1622,19 +1858,19 @@ reset_fw: if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", - hdev->name, ret); + hdev->name, ret); goto done; } if (skb->len != sizeof(*ver)) { BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", - hdev->name); + hdev->name); kfree_skb(skb); ret = -EIO; goto done; } - ver = (struct hci_rp_read_local_version *) skb->data; + ver = (struct hci_rp_read_local_version *)skb->data; BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x " "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, ver->lmp_ver, ver->lmp_subver); @@ -1646,19 +1882,19 @@ reset_fw: if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: HCI_OP_READ_BD_ADDR failed (%ld)", - hdev->name, ret); + hdev->name, ret); goto done; } if (skb->len != sizeof(*bda)) { BT_ERR("%s: HCI_OP_READ_BD_ADDR event length mismatch", - hdev->name); + hdev->name); kfree_skb(skb); ret = -EIO; goto done; } - bda = (struct hci_rp_read_bd_addr *) skb->data; + bda = (struct hci_rp_read_bd_addr *)skb->data; if (bda->status) { BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)", hdev->name, bda->status); @@ -1693,7 +1929,7 @@ static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr) if (IS_ERR(skb)) { ret = PTR_ERR(skb); BT_ERR("%s: BCM: Change address command failed (%ld)", - hdev->name, ret); + hdev->name, ret); return ret; } kfree_skb(skb); @@ -1702,7 +1938,7 @@ static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr) } static int btusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) + const struct usb_device_id *id) { struct usb_endpoint_descriptor *ep_desc; struct btusb_data *data; @@ -1717,6 +1953,7 @@ static int btusb_probe(struct usb_interface *intf, if (!id->driver_info) { const struct usb_device_id *match; + match = usb_match_id(intf, blacklist_table); if (match) id = match; @@ -1769,13 +2006,14 @@ static int btusb_probe(struct usb_interface *intf, INIT_WORK(&data->work, btusb_work); INIT_WORK(&data->waker, btusb_waker); + init_usb_anchor(&data->deferred); + init_usb_anchor(&data->tx_anchor); spin_lock_init(&data->txlock); - init_usb_anchor(&data->tx_anchor); init_usb_anchor(&data->intr_anchor); init_usb_anchor(&data->bulk_anchor); init_usb_anchor(&data->isoc_anchor); - init_usb_anchor(&data->deferred); + spin_lock_init(&data->rxlock); hdev = hci_alloc_dev(); if (!hdev) @@ -1867,7 +2105,7 @@ static int btusb_probe(struct usb_interface *intf, if (data->isoc) { err = usb_driver_claim_interface(&btusb_driver, - data->isoc, data); + data->isoc, data); if (err < 0) { hci_free_dev(hdev); return err; @@ -1908,6 +2146,7 @@ static void btusb_disconnect(struct usb_interface *intf) else if (data->isoc) usb_driver_release_interface(&btusb_driver, data->isoc); + btusb_free_frags(data); hci_free_dev(hdev); } diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 9e6a124b13f2..07e0b887c350 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -323,8 +323,8 @@ static int mrf24j40_read_rx_buf(struct mrf24j40 *devrec, #ifdef DEBUG print_hex_dump(KERN_DEBUG, "mrf24j40 rx: ", DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0); - printk(KERN_DEBUG "mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n", - lqi_rssi[0], lqi_rssi[1]); + pr_debug("mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n", + lqi_rssi[0], lqi_rssi[1]); #endif out: @@ -385,7 +385,7 @@ err: static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level) { /* TODO: */ - printk(KERN_WARNING "mrf24j40: ed not implemented\n"); + pr_warn("mrf24j40: ed not implemented\n"); *level = 0; return 0; } @@ -412,6 +412,7 @@ static void mrf24j40_stop(struct ieee802154_dev *dev) struct mrf24j40 *devrec = dev->priv; u8 val; int ret; + dev_dbg(printdev(devrec), "stop\n"); ret = read_short_reg(devrec, REG_INTCON, &val); @@ -419,8 +420,6 @@ static void mrf24j40_stop(struct ieee802154_dev *dev) return; val |= 0x1|0x8; /* Set TXNIE and RXIE. Disable Interrupts */ write_short_reg(devrec, REG_INTCON, val); - - return; } static int mrf24j40_set_channel(struct ieee802154_dev *dev, @@ -465,6 +464,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, if (changed & IEEE802515_AFILT_SADDR_CHANGED) { /* Short Addr */ u8 addrh, addrl; + addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff; addrl = le16_to_cpu(filt->short_addr) & 0xff; @@ -483,16 +483,17 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, write_short_reg(devrec, REG_EADR0 + i, addr[i]); #ifdef DEBUG - printk(KERN_DEBUG "Set long addr to: "); + pr_debug("Set long addr to: "); for (i = 0; i < 8; i++) - printk("%02hhx ", addr[7 - i]); - printk(KERN_DEBUG "\n"); + pr_debug("%02hhx ", addr[7 - i]); + pr_debug("\n"); #endif } if (changed & IEEE802515_AFILT_PANID_CHANGED) { /* PAN ID */ u8 panidl, panidh; + panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff; panidl = le16_to_cpu(filt->pan_id) & 0xff; write_short_reg(devrec, REG_PANIDH, panidh); @@ -701,7 +702,7 @@ static int mrf24j40_probe(struct spi_device *spi) int ret = -ENOMEM; struct mrf24j40 *devrec; - printk(KERN_INFO "mrf24j40: probe(). IRQ: %d\n", spi->irq); + dev_info(&spi->dev, "probe(). IRQ: %d\n", spi->irq); devrec = devm_kzalloc(&spi->dev, sizeof(struct mrf24j40), GFP_KERNEL); if (!devrec) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 373000de610d..58695ffeb138 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -120,9 +120,9 @@ struct bt_voice { #define BT_RCVMTU 13 __printf(1, 2) -int bt_info(const char *fmt, ...); +void bt_info(const char *fmt, ...); __printf(1, 2) -int bt_err(const char *fmt, ...); +void bt_err(const char *fmt, ...); #define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__) #define BT_ERR(fmt, ...) bt_err(fmt "\n", ##__VA_ARGS__) @@ -284,6 +284,7 @@ struct hci_req_ctrl { struct bt_skb_cb { __u8 pkt_type; __u8 incoming; + __u16 opcode; __u16 expect; __u8 force_active; struct l2cap_chan *chan; diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 3f8547f1c6f8..6e8f24967308 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -385,6 +385,7 @@ enum { #define HCI_ERROR_AUTH_FAILURE 0x05 #define HCI_ERROR_MEMORY_EXCEEDED 0x07 #define HCI_ERROR_CONNECTION_TIMEOUT 0x08 +#define HCI_ERROR_REJ_LIMITED_RESOURCES 0x0d #define HCI_ERROR_REJ_BAD_ADDR 0x0f #define HCI_ERROR_REMOTE_USER_TERM 0x13 #define HCI_ERROR_REMOTE_LOW_RESOURCES 0x14 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 206b92bfeebb..37ff1aef0845 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -926,7 +926,6 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb); -int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count); int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count); void hci_init_sysfs(struct hci_dev *hdev); diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 4dca0299ed96..339c74ad4553 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -709,8 +709,11 @@ EXPORT_SYMBOL_GPL(bt_debugfs); static int __init bt_init(void) { + struct sk_buff *skb; int err; + BUILD_BUG_ON(sizeof(struct bt_skb_cb) > sizeof(skb->cb)); + BT_INFO("Core ver %s", VERSION); bt_debugfs = debugfs_create_dir("bluetooth", NULL); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index e3d7ae9e2edd..b9517bd17190 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -36,19 +36,25 @@ struct sco_param { u16 pkt_type; u16 max_latency; + u8 retrans_effort; +}; + +static const struct sco_param esco_param_cvsd[] = { + { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a, 0x01 }, /* S3 */ + { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007, 0x01 }, /* S2 */ + { EDR_ESCO_MASK | ESCO_EV3, 0x0007, 0x01 }, /* S1 */ + { EDR_ESCO_MASK | ESCO_HV3, 0xffff, 0x01 }, /* D1 */ + { EDR_ESCO_MASK | ESCO_HV1, 0xffff, 0x01 }, /* D0 */ }; static const struct sco_param sco_param_cvsd[] = { - { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a }, /* S3 */ - { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007 }, /* S2 */ - { EDR_ESCO_MASK | ESCO_EV3, 0x0007 }, /* S1 */ - { EDR_ESCO_MASK | ESCO_HV3, 0xffff }, /* D1 */ - { EDR_ESCO_MASK | ESCO_HV1, 0xffff }, /* D0 */ + { EDR_ESCO_MASK | ESCO_HV3, 0xffff, 0xff }, /* D1 */ + { EDR_ESCO_MASK | ESCO_HV1, 0xffff, 0xff }, /* D0 */ }; -static const struct sco_param sco_param_wideband[] = { - { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d }, /* T2 */ - { EDR_ESCO_MASK | ESCO_EV3, 0x0008 }, /* T1 */ +static const struct sco_param esco_param_msbc[] = { + { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d, 0x02 }, /* T2 */ + { EDR_ESCO_MASK | ESCO_EV3, 0x0008, 0x02 }, /* T1 */ }; static void hci_le_create_connection_cancel(struct hci_conn *conn) @@ -116,7 +122,7 @@ static void hci_reject_sco(struct hci_conn *conn) { struct hci_cp_reject_sync_conn_req cp; - cp.reason = HCI_ERROR_REMOTE_USER_TERM; + cp.reason = HCI_ERROR_REJ_LIMITED_RESOURCES; bacpy(&cp.bdaddr, &conn->dst); hci_send_cmd(conn->hdev, HCI_OP_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp); @@ -201,21 +207,26 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle) switch (conn->setting & SCO_AIRMODE_MASK) { case SCO_AIRMODE_TRANSP: - if (conn->attempt > ARRAY_SIZE(sco_param_wideband)) + if (conn->attempt > ARRAY_SIZE(esco_param_msbc)) return false; - cp.retrans_effort = 0x02; - param = &sco_param_wideband[conn->attempt - 1]; + param = &esco_param_msbc[conn->attempt - 1]; break; case SCO_AIRMODE_CVSD: - if (conn->attempt > ARRAY_SIZE(sco_param_cvsd)) - return false; - cp.retrans_effort = 0x01; - param = &sco_param_cvsd[conn->attempt - 1]; + if (lmp_esco_capable(conn->link)) { + if (conn->attempt > ARRAY_SIZE(esco_param_cvsd)) + return false; + param = &esco_param_cvsd[conn->attempt - 1]; + } else { + if (conn->attempt > ARRAY_SIZE(sco_param_cvsd)) + return false; + param = &sco_param_cvsd[conn->attempt - 1]; + } break; default: return false; } + cp.retrans_effort = param->retrans_effort; cp.pkt_type = __cpu_to_le16(param->pkt_type); cp.max_latency = __cpu_to_le16(param->max_latency); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 067526d9680d..cb05d7f16a34 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -4374,26 +4374,6 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, return remain; } -int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) -{ - int rem = 0; - - if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) - return -EILSEQ; - - while (count) { - rem = hci_reassembly(hdev, type, data, count, type - 1); - if (rem < 0) - return rem; - - data += (count - rem); - count = rem; - } - - return rem; -} -EXPORT_SYMBOL(hci_recv_fragment); - #define STREAM_REASSEMBLY 0 int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count) @@ -4547,6 +4527,7 @@ static struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode, BT_DBG("skb len %d", skb->len); bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; + bt_cb(skb)->opcode = opcode; return skb; } diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index 941ad7530eda..b36bc0415854 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -135,40 +135,34 @@ int bt_to_errno(__u16 code) } EXPORT_SYMBOL(bt_to_errno); -int bt_info(const char *format, ...) +void bt_info(const char *format, ...) { struct va_format vaf; va_list args; - int r; va_start(args, format); vaf.fmt = format; vaf.va = &args; - r = pr_info("%pV", &vaf); + pr_info("%pV", &vaf); va_end(args); - - return r; } EXPORT_SYMBOL(bt_info); -int bt_err(const char *format, ...) +void bt_err(const char *format, ...) { struct va_format vaf; va_list args; - int r; va_start(args, format); vaf.fmt = format; vaf.va = &args; - r = pr_err("%pV", &vaf); + pr_err("%pV", &vaf); va_end(args); - - return r; } EXPORT_SYMBOL(bt_err); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 51fc7db2d84e..f09b6b65cf6b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -494,8 +494,11 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, } /* Not Just Works/Confirm results in MITM Authentication */ - if (method != JUST_CFM) + if (method != JUST_CFM) { set_bit(SMP_FLAG_MITM_AUTH, &smp->flags); + if (hcon->pending_sec_level < BT_SECURITY_HIGH) + hcon->pending_sec_level = BT_SECURITY_HIGH; + } /* If both devices have Keyoard-Display I/O, the master * Confirms and the slave Enters the passkey. diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 5e788cdc499a..44136297b673 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c @@ -71,20 +71,42 @@ struct lowpan_dev_record { struct list_head list; }; +/* don't save pan id, it's intra pan */ +struct lowpan_addr { + u8 mode; + union { + /* IPv6 needs big endian here */ + __be64 extended_addr; + __be16 short_addr; + } u; +}; + +struct lowpan_addr_info { + struct lowpan_addr daddr; + struct lowpan_addr saddr; +}; + static inline struct lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) { return netdev_priv(dev); } +static inline struct +lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb) +{ + WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct lowpan_addr_info)); + return (struct lowpan_addr_info *)(skb->data - + sizeof(struct lowpan_addr_info)); +} + static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *_daddr, const void *_saddr, unsigned int len) { const u8 *saddr = _saddr; const u8 *daddr = _daddr; - struct ieee802154_addr sa, da; - struct ieee802154_mac_cb *cb = mac_cb_init(skb); + struct lowpan_addr_info *info; /* TODO: * if this package isn't ipv6 one, where should it be routed? @@ -98,41 +120,17 @@ static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev, raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8); raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8); - lowpan_header_compress(skb, dev, type, daddr, saddr, len); + info = lowpan_skb_priv(skb); - /* NOTE1: I'm still unsure about the fact that compression and WPAN - * header are created here and not later in the xmit. So wait for - * an opinion of net maintainers. - */ - /* NOTE2: to be absolutely correct, we must derive PANid information - * from MAC subif of the 'dev' and 'real_dev' network devices, but - * this isn't implemented in mainline yet, so currently we assign 0xff - */ - cb->type = IEEE802154_FC_TYPE_DATA; + /* TODO: Currently we only support extended_addr */ + info->daddr.mode = IEEE802154_ADDR_LONG; + memcpy(&info->daddr.u.extended_addr, daddr, + sizeof(info->daddr.u.extended_addr)); + info->saddr.mode = IEEE802154_ADDR_LONG; + memcpy(&info->saddr.u.extended_addr, saddr, + sizeof(info->daddr.u.extended_addr)); - /* prepare wpan address data */ - sa.mode = IEEE802154_ADDR_LONG; - sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); - sa.extended_addr = ieee802154_devaddr_from_raw(saddr); - - /* intra-PAN communications */ - da.pan_id = sa.pan_id; - - /* if the destination address is the broadcast address, use the - * corresponding short address - */ - if (lowpan_is_addr_broadcast(daddr)) { - da.mode = IEEE802154_ADDR_SHORT; - da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST); - } else { - da.mode = IEEE802154_ADDR_LONG; - da.extended_addr = ieee802154_devaddr_from_raw(daddr); - } - - cb->ackreq = !lowpan_is_addr_broadcast(daddr); - - return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, - type, (void *)&da, (void *)&sa, 0); + return 0; } static int lowpan_give_skb_to_devices(struct sk_buff *skb, @@ -330,13 +328,68 @@ err: return rc; } +static int lowpan_header(struct sk_buff *skb, struct net_device *dev) +{ + struct ieee802154_addr sa, da; + struct ieee802154_mac_cb *cb = mac_cb_init(skb); + struct lowpan_addr_info info; + void *daddr, *saddr; + + memcpy(&info, lowpan_skb_priv(skb), sizeof(info)); + + /* TODO: Currently we only support extended_addr */ + daddr = &info.daddr.u.extended_addr; + saddr = &info.saddr.u.extended_addr; + + lowpan_header_compress(skb, dev, ETH_P_IPV6, daddr, saddr, skb->len); + + cb->type = IEEE802154_FC_TYPE_DATA; + + /* prepare wpan address data */ + sa.mode = IEEE802154_ADDR_LONG; + sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); + sa.extended_addr = ieee802154_devaddr_from_raw(saddr); + + /* intra-PAN communications */ + da.pan_id = sa.pan_id; + + /* if the destination address is the broadcast address, use the + * corresponding short address + */ + if (lowpan_is_addr_broadcast((const u8 *)daddr)) { + da.mode = IEEE802154_ADDR_SHORT; + da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST); + cb->ackreq = false; + } else { + da.mode = IEEE802154_ADDR_LONG; + da.extended_addr = ieee802154_devaddr_from_raw(daddr); + cb->ackreq = true; + } + + return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, + ETH_P_IPV6, (void *)&da, (void *)&sa, 0); +} + static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee802154_hdr wpan_hdr; - int max_single; + int max_single, ret; pr_debug("package xmit\n"); + /* We must take a copy of the skb before we modify/replace the ipv6 + * header as the header could be used elsewhere + */ + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) + return NET_XMIT_DROP; + + ret = lowpan_header(skb, dev); + if (ret < 0) { + kfree_skb(skb); + return NET_XMIT_DROP; + } + if (ieee802154_hdr_peek(skb, &wpan_hdr) < 0) { kfree_skb(skb); return NET_XMIT_DROP;