Commit | Line | Data |
---|---|---|
1802d0be | 1 | // SPDX-License-Identifier: GPL-2.0-only |
5b641ebe | 2 | /* |
3 | * Copyright 2007-2012 Siemens AG | |
4 | * | |
5b641ebe | 5 | * Written by: |
6 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | |
7 | * Sergey Lapin <slapin@ossfans.org> | |
8 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> | |
9 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | |
10 | */ | |
11 | ||
12 | #include <linux/netdevice.h> | |
13 | #include <linux/if_arp.h> | |
14 | #include <linux/crc-ccitt.h> | |
061ef8f9 | 15 | #include <asm/unaligned.h> |
5b641ebe | 16 | |
6001d522 | 17 | #include <net/rtnetlink.h> |
b5992fe9 | 18 | #include <net/ieee802154_netdev.h> |
5b641ebe | 19 | #include <net/mac802154.h> |
5ad60d36 | 20 | #include <net/cfg802154.h> |
5b641ebe | 21 | |
0f1556bc | 22 | #include "ieee802154_i.h" |
59cb300f | 23 | #include "driver-ops.h" |
5b641ebe | 24 | |
c22ff7b4 | 25 | void ieee802154_xmit_worker(struct work_struct *work) |
5b641ebe | 26 | { |
c22ff7b4 LB |
27 | struct ieee802154_local *local = |
28 | container_of(work, struct ieee802154_local, tx_work); | |
29 | struct sk_buff *skb = local->tx_skb; | |
409c3b0c | 30 | struct net_device *dev = skb->dev; |
5b641ebe | 31 | int res; |
32 | ||
59cb300f | 33 | res = drv_xmit_sync(local, skb); |
6001d522 AA |
34 | if (res) |
35 | goto err_tx; | |
36 | ||
409c3b0c AA |
37 | dev->stats.tx_packets++; |
38 | dev->stats.tx_bytes += skb->len; | |
39 | ||
0ff4628f ED |
40 | ieee802154_xmit_complete(&local->hw, skb, false); |
41 | ||
6001d522 AA |
42 | return; |
43 | ||
44 | err_tx: | |
45 | /* Restart the netif queue on each sub_if_data object. */ | |
46 | ieee802154_wake_queue(&local->hw); | |
6001d522 | 47 | kfree_skb(skb); |
409c3b0c | 48 | netdev_dbg(dev, "transmission failed\n"); |
5b641ebe | 49 | } |
50 | ||
dc67c6b3 | 51 | static netdev_tx_t |
e5e584fc | 52 | ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb) |
5b641ebe | 53 | { |
409c3b0c | 54 | struct net_device *dev = skb->dev; |
ed0a5dce | 55 | int ret; |
5b641ebe | 56 | |
90386a7e | 57 | if (!(local->hw.flags & IEEE802154_HW_TX_OMIT_CKSUM)) { |
f9c52831 AA |
58 | struct sk_buff *nskb; |
59 | u16 crc; | |
4710d806 | 60 | |
f9c52831 AA |
61 | if (unlikely(skb_tailroom(skb) < IEEE802154_FCS_LEN)) { |
62 | nskb = skb_copy_expand(skb, 0, IEEE802154_FCS_LEN, | |
63 | GFP_ATOMIC); | |
64 | if (likely(nskb)) { | |
65 | consume_skb(skb); | |
66 | skb = nskb; | |
67 | } else { | |
68 | goto err_tx; | |
69 | } | |
70 | } | |
71 | ||
72 | crc = crc_ccitt(0, skb->data, skb->len); | |
061ef8f9 | 73 | put_unaligned_le16(crc, skb_put(skb, 2)); |
5b641ebe | 74 | } |
75 | ||
b5992fe9 | 76 | /* Stop the netif queue on each sub_if_data object. */ |
18d60a0d | 77 | ieee802154_stop_queue(&local->hw); |
b5992fe9 | 78 | |
ed0a5dce AA |
79 | /* async is priority, otherwise sync is fallback */ |
80 | if (local->ops->xmit_async) { | |
0ff4628f ED |
81 | unsigned int len = skb->len; |
82 | ||
59cb300f | 83 | ret = drv_xmit_async(local, skb); |
ed0a5dce AA |
84 | if (ret) { |
85 | ieee802154_wake_queue(&local->hw); | |
86 | goto err_tx; | |
87 | } | |
409c3b0c AA |
88 | |
89 | dev->stats.tx_packets++; | |
0ff4628f | 90 | dev->stats.tx_bytes += len; |
ed0a5dce | 91 | } else { |
c22ff7b4 LB |
92 | local->tx_skb = skb; |
93 | queue_work(local->workqueue, &local->tx_work); | |
ed0a5dce | 94 | } |
5b641ebe | 95 | |
96 | return NETDEV_TX_OK; | |
f5588912 VB |
97 | |
98 | err_tx: | |
99 | kfree_skb(skb); | |
100 | return NETDEV_TX_OK; | |
5b641ebe | 101 | } |
50c6fb99 | 102 | |
e5e584fc AA |
103 | netdev_tx_t |
104 | ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev) | |
50c6fb99 AA |
105 | { |
106 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | |
50c6fb99 AA |
107 | |
108 | skb->skb_iif = dev->ifindex; | |
50c6fb99 | 109 | |
e5e584fc | 110 | return ieee802154_tx(sdata->local, skb); |
50c6fb99 AA |
111 | } |
112 | ||
e5e584fc AA |
113 | netdev_tx_t |
114 | ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev) | |
50c6fb99 AA |
115 | { |
116 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | |
50c6fb99 AA |
117 | int rc; |
118 | ||
d58a2fa9 AA |
119 | /* TODO we should move it to wpan_dev_hard_header and dev_hard_header |
120 | * functions. The reason is wireshark will show a mac header which is | |
121 | * with security fields but the payload is not encrypted. | |
122 | */ | |
50c6fb99 AA |
123 | rc = mac802154_llsec_encrypt(&sdata->sec, skb); |
124 | if (rc) { | |
cfa626cb | 125 | netdev_warn(dev, "encryption failed: %i\n", rc); |
50c6fb99 AA |
126 | kfree_skb(skb); |
127 | return NETDEV_TX_OK; | |
128 | } | |
129 | ||
130 | skb->skb_iif = dev->ifindex; | |
50c6fb99 | 131 | |
e5e584fc | 132 | return ieee802154_tx(sdata->local, skb); |
50c6fb99 | 133 | } |