diff options
Diffstat (limited to 'net')
83 files changed, 4065 insertions, 2176 deletions
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index 142eef55c9e2..73a7065f0c6b 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c | |||
@@ -171,37 +171,6 @@ static int uncompress_context_based_src_addr(struct sk_buff *skb, | |||
171 | return 0; | 171 | return 0; |
172 | } | 172 | } |
173 | 173 | ||
174 | static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, | ||
175 | struct net_device *dev, skb_delivery_cb deliver_skb) | ||
176 | { | ||
177 | struct sk_buff *new; | ||
178 | int stat; | ||
179 | |||
180 | new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), | ||
181 | GFP_ATOMIC); | ||
182 | kfree_skb(skb); | ||
183 | |||
184 | if (!new) | ||
185 | return -ENOMEM; | ||
186 | |||
187 | skb_push(new, sizeof(struct ipv6hdr)); | ||
188 | skb_reset_network_header(new); | ||
189 | skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); | ||
190 | |||
191 | new->protocol = htons(ETH_P_IPV6); | ||
192 | new->pkt_type = PACKET_HOST; | ||
193 | new->dev = dev; | ||
194 | |||
195 | raw_dump_table(__func__, "raw skb data dump before receiving", | ||
196 | new->data, new->len); | ||
197 | |||
198 | stat = deliver_skb(new, dev); | ||
199 | |||
200 | kfree_skb(new); | ||
201 | |||
202 | return stat; | ||
203 | } | ||
204 | |||
205 | /* Uncompress function for multicast destination address, | 174 | /* Uncompress function for multicast destination address, |
206 | * when M bit is set. | 175 | * when M bit is set. |
207 | */ | 176 | */ |
@@ -332,10 +301,12 @@ err: | |||
332 | /* TTL uncompression values */ | 301 | /* TTL uncompression values */ |
333 | static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; | 302 | static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; |
334 | 303 | ||
335 | int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | 304 | int |
336 | const u8 *saddr, const u8 saddr_type, const u8 saddr_len, | 305 | lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, |
337 | const u8 *daddr, const u8 daddr_type, const u8 daddr_len, | 306 | const u8 *saddr, const u8 saddr_type, |
338 | u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb) | 307 | const u8 saddr_len, const u8 *daddr, |
308 | const u8 daddr_type, const u8 daddr_len, | ||
309 | u8 iphc0, u8 iphc1) | ||
339 | { | 310 | { |
340 | struct ipv6hdr hdr = {}; | 311 | struct ipv6hdr hdr = {}; |
341 | u8 tmp, num_context = 0; | 312 | u8 tmp, num_context = 0; |
@@ -460,7 +431,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
460 | /* UDP data uncompression */ | 431 | /* UDP data uncompression */ |
461 | if (iphc0 & LOWPAN_IPHC_NH_C) { | 432 | if (iphc0 & LOWPAN_IPHC_NH_C) { |
462 | struct udphdr uh; | 433 | struct udphdr uh; |
463 | struct sk_buff *new; | 434 | const int needed = sizeof(struct udphdr) + sizeof(hdr); |
464 | 435 | ||
465 | if (uncompress_udp_header(skb, &uh)) | 436 | if (uncompress_udp_header(skb, &uh)) |
466 | goto drop; | 437 | goto drop; |
@@ -468,14 +439,11 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
468 | /* replace the compressed UDP head by the uncompressed UDP | 439 | /* replace the compressed UDP head by the uncompressed UDP |
469 | * header | 440 | * header |
470 | */ | 441 | */ |
471 | new = skb_copy_expand(skb, sizeof(struct udphdr), | 442 | err = skb_cow(skb, needed); |
472 | skb_tailroom(skb), GFP_ATOMIC); | 443 | if (unlikely(err)) { |
473 | kfree_skb(skb); | 444 | kfree_skb(skb); |
474 | 445 | return err; | |
475 | if (!new) | 446 | } |
476 | return -ENOMEM; | ||
477 | |||
478 | skb = new; | ||
479 | 447 | ||
480 | skb_push(skb, sizeof(struct udphdr)); | 448 | skb_push(skb, sizeof(struct udphdr)); |
481 | skb_reset_transport_header(skb); | 449 | skb_reset_transport_header(skb); |
@@ -485,6 +453,12 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
485 | (u8 *)&uh, sizeof(uh)); | 453 | (u8 *)&uh, sizeof(uh)); |
486 | 454 | ||
487 | hdr.nexthdr = UIP_PROTO_UDP; | 455 | hdr.nexthdr = UIP_PROTO_UDP; |
456 | } else { | ||
457 | err = skb_cow(skb, sizeof(hdr)); | ||
458 | if (unlikely(err)) { | ||
459 | kfree_skb(skb); | ||
460 | return err; | ||
461 | } | ||
488 | } | 462 | } |
489 | 463 | ||
490 | hdr.payload_len = htons(skb->len); | 464 | hdr.payload_len = htons(skb->len); |
@@ -497,15 +471,18 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
497 | hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, | 471 | hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, |
498 | hdr.hop_limit, &hdr.daddr); | 472 | hdr.hop_limit, &hdr.daddr); |
499 | 473 | ||
500 | raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr)); | 474 | skb_push(skb, sizeof(hdr)); |
475 | skb_reset_network_header(skb); | ||
476 | skb_copy_to_linear_data(skb, &hdr, sizeof(hdr)); | ||
501 | 477 | ||
502 | return skb_deliver(skb, &hdr, dev, deliver_skb); | 478 | raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr)); |
503 | 479 | ||
480 | return 0; | ||
504 | drop: | 481 | drop: |
505 | kfree_skb(skb); | 482 | kfree_skb(skb); |
506 | return -EINVAL; | 483 | return -EINVAL; |
507 | } | 484 | } |
508 | EXPORT_SYMBOL_GPL(lowpan_process_data); | 485 | EXPORT_SYMBOL_GPL(lowpan_header_decompress); |
509 | 486 | ||
510 | static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift, | 487 | static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift, |
511 | const struct in6_addr *ipaddr, | 488 | const struct in6_addr *ipaddr, |
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index c2e0d14433df..eef298d17452 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c | |||
@@ -53,7 +53,7 @@ struct skb_cb { | |||
53 | * The list contains struct lowpan_dev elements. | 53 | * The list contains struct lowpan_dev elements. |
54 | */ | 54 | */ |
55 | static LIST_HEAD(bt_6lowpan_devices); | 55 | static LIST_HEAD(bt_6lowpan_devices); |
56 | static DEFINE_RWLOCK(devices_lock); | 56 | static DEFINE_SPINLOCK(devices_lock); |
57 | 57 | ||
58 | /* If psm is set to 0 (default value), then 6lowpan is disabled. | 58 | /* If psm is set to 0 (default value), then 6lowpan is disabled. |
59 | * Other values are used to indicate a Protocol Service Multiplexer | 59 | * Other values are used to indicate a Protocol Service Multiplexer |
@@ -67,6 +67,7 @@ static struct l2cap_chan *listen_chan; | |||
67 | 67 | ||
68 | struct lowpan_peer { | 68 | struct lowpan_peer { |
69 | struct list_head list; | 69 | struct list_head list; |
70 | struct rcu_head rcu; | ||
70 | struct l2cap_chan *chan; | 71 | struct l2cap_chan *chan; |
71 | 72 | ||
72 | /* peer addresses in various formats */ | 73 | /* peer addresses in various formats */ |
@@ -86,6 +87,13 @@ struct lowpan_dev { | |||
86 | struct delayed_work notify_peers; | 87 | struct delayed_work notify_peers; |
87 | }; | 88 | }; |
88 | 89 | ||
90 | static inline void peer_free(struct rcu_head *head) | ||
91 | { | ||
92 | struct lowpan_peer *e = container_of(head, struct lowpan_peer, rcu); | ||
93 | |||
94 | kfree(e); | ||
95 | } | ||
96 | |||
89 | static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev) | 97 | static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev) |
90 | { | 98 | { |
91 | return netdev_priv(netdev); | 99 | return netdev_priv(netdev); |
@@ -93,13 +101,14 @@ static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev) | |||
93 | 101 | ||
94 | static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer) | 102 | static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer) |
95 | { | 103 | { |
96 | list_add(&peer->list, &dev->peers); | 104 | list_add_rcu(&peer->list, &dev->peers); |
97 | atomic_inc(&dev->peer_count); | 105 | atomic_inc(&dev->peer_count); |
98 | } | 106 | } |
99 | 107 | ||
100 | static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer) | 108 | static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer) |
101 | { | 109 | { |
102 | list_del(&peer->list); | 110 | list_del_rcu(&peer->list); |
111 | call_rcu(&peer->rcu, peer_free); | ||
103 | 112 | ||
104 | module_put(THIS_MODULE); | 113 | module_put(THIS_MODULE); |
105 | 114 | ||
@@ -114,31 +123,37 @@ static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer) | |||
114 | static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev, | 123 | static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev, |
115 | bdaddr_t *ba, __u8 type) | 124 | bdaddr_t *ba, __u8 type) |
116 | { | 125 | { |
117 | struct lowpan_peer *peer, *tmp; | 126 | struct lowpan_peer *peer; |
118 | 127 | ||
119 | BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count), | 128 | BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count), |
120 | ba, type); | 129 | ba, type); |
121 | 130 | ||
122 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { | 131 | rcu_read_lock(); |
132 | |||
133 | list_for_each_entry_rcu(peer, &dev->peers, list) { | ||
123 | BT_DBG("dst addr %pMR dst type %d", | 134 | BT_DBG("dst addr %pMR dst type %d", |
124 | &peer->chan->dst, peer->chan->dst_type); | 135 | &peer->chan->dst, peer->chan->dst_type); |
125 | 136 | ||
126 | if (bacmp(&peer->chan->dst, ba)) | 137 | if (bacmp(&peer->chan->dst, ba)) |
127 | continue; | 138 | continue; |
128 | 139 | ||
129 | if (type == peer->chan->dst_type) | 140 | if (type == peer->chan->dst_type) { |
141 | rcu_read_unlock(); | ||
130 | return peer; | 142 | return peer; |
143 | } | ||
131 | } | 144 | } |
132 | 145 | ||
146 | rcu_read_unlock(); | ||
147 | |||
133 | return NULL; | 148 | return NULL; |
134 | } | 149 | } |
135 | 150 | ||
136 | static inline struct lowpan_peer *peer_lookup_chan(struct lowpan_dev *dev, | 151 | static inline struct lowpan_peer *__peer_lookup_chan(struct lowpan_dev *dev, |
137 | struct l2cap_chan *chan) | 152 | struct l2cap_chan *chan) |
138 | { | 153 | { |
139 | struct lowpan_peer *peer, *tmp; | 154 | struct lowpan_peer *peer; |
140 | 155 | ||
141 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { | 156 | list_for_each_entry_rcu(peer, &dev->peers, list) { |
142 | if (peer->chan == chan) | 157 | if (peer->chan == chan) |
143 | return peer; | 158 | return peer; |
144 | } | 159 | } |
@@ -146,12 +161,12 @@ static inline struct lowpan_peer *peer_lookup_chan(struct lowpan_dev *dev, | |||
146 | return NULL; | 161 | return NULL; |
147 | } | 162 | } |
148 | 163 | ||
149 | static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev, | 164 | static inline struct lowpan_peer *__peer_lookup_conn(struct lowpan_dev *dev, |
150 | struct l2cap_conn *conn) | 165 | struct l2cap_conn *conn) |
151 | { | 166 | { |
152 | struct lowpan_peer *peer, *tmp; | 167 | struct lowpan_peer *peer; |
153 | 168 | ||
154 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { | 169 | list_for_each_entry_rcu(peer, &dev->peers, list) { |
155 | if (peer->chan->conn == conn) | 170 | if (peer->chan->conn == conn) |
156 | return peer; | 171 | return peer; |
157 | } | 172 | } |
@@ -163,7 +178,7 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev, | |||
163 | struct in6_addr *daddr, | 178 | struct in6_addr *daddr, |
164 | struct sk_buff *skb) | 179 | struct sk_buff *skb) |
165 | { | 180 | { |
166 | struct lowpan_peer *peer, *tmp; | 181 | struct lowpan_peer *peer; |
167 | struct in6_addr *nexthop; | 182 | struct in6_addr *nexthop; |
168 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); | 183 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); |
169 | int count = atomic_read(&dev->peer_count); | 184 | int count = atomic_read(&dev->peer_count); |
@@ -174,9 +189,13 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev, | |||
174 | * send the packet. If only one peer exists, then we can send the | 189 | * send the packet. If only one peer exists, then we can send the |
175 | * packet right away. | 190 | * packet right away. |
176 | */ | 191 | */ |
177 | if (count == 1) | 192 | if (count == 1) { |
178 | return list_first_entry(&dev->peers, struct lowpan_peer, | 193 | rcu_read_lock(); |
179 | list); | 194 | peer = list_first_or_null_rcu(&dev->peers, struct lowpan_peer, |
195 | list); | ||
196 | rcu_read_unlock(); | ||
197 | return peer; | ||
198 | } | ||
180 | 199 | ||
181 | if (!rt) { | 200 | if (!rt) { |
182 | nexthop = &lowpan_cb(skb)->gw; | 201 | nexthop = &lowpan_cb(skb)->gw; |
@@ -195,53 +214,57 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev, | |||
195 | 214 | ||
196 | BT_DBG("gw %pI6c", nexthop); | 215 | BT_DBG("gw %pI6c", nexthop); |
197 | 216 | ||
198 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { | 217 | rcu_read_lock(); |
218 | |||
219 | list_for_each_entry_rcu(peer, &dev->peers, list) { | ||
199 | BT_DBG("dst addr %pMR dst type %d ip %pI6c", | 220 | BT_DBG("dst addr %pMR dst type %d ip %pI6c", |
200 | &peer->chan->dst, peer->chan->dst_type, | 221 | &peer->chan->dst, peer->chan->dst_type, |
201 | &peer->peer_addr); | 222 | &peer->peer_addr); |
202 | 223 | ||
203 | if (!ipv6_addr_cmp(&peer->peer_addr, nexthop)) | 224 | if (!ipv6_addr_cmp(&peer->peer_addr, nexthop)) { |
225 | rcu_read_unlock(); | ||
204 | return peer; | 226 | return peer; |
227 | } | ||
205 | } | 228 | } |
206 | 229 | ||
230 | rcu_read_unlock(); | ||
231 | |||
207 | return NULL; | 232 | return NULL; |
208 | } | 233 | } |
209 | 234 | ||
210 | static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn) | 235 | static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn) |
211 | { | 236 | { |
212 | struct lowpan_dev *entry, *tmp; | 237 | struct lowpan_dev *entry; |
213 | struct lowpan_peer *peer = NULL; | 238 | struct lowpan_peer *peer = NULL; |
214 | unsigned long flags; | ||
215 | 239 | ||
216 | read_lock_irqsave(&devices_lock, flags); | 240 | rcu_read_lock(); |
217 | 241 | ||
218 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | 242 | list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) { |
219 | peer = peer_lookup_conn(entry, conn); | 243 | peer = __peer_lookup_conn(entry, conn); |
220 | if (peer) | 244 | if (peer) |
221 | break; | 245 | break; |
222 | } | 246 | } |
223 | 247 | ||
224 | read_unlock_irqrestore(&devices_lock, flags); | 248 | rcu_read_unlock(); |
225 | 249 | ||
226 | return peer; | 250 | return peer; |
227 | } | 251 | } |
228 | 252 | ||
229 | static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn) | 253 | static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn) |
230 | { | 254 | { |
231 | struct lowpan_dev *entry, *tmp; | 255 | struct lowpan_dev *entry; |
232 | struct lowpan_dev *dev = NULL; | 256 | struct lowpan_dev *dev = NULL; |
233 | unsigned long flags; | ||
234 | 257 | ||
235 | read_lock_irqsave(&devices_lock, flags); | 258 | rcu_read_lock(); |
236 | 259 | ||
237 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | 260 | list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) { |
238 | if (conn->hcon->hdev == entry->hdev) { | 261 | if (conn->hcon->hdev == entry->hdev) { |
239 | dev = entry; | 262 | dev = entry; |
240 | break; | 263 | break; |
241 | } | 264 | } |
242 | } | 265 | } |
243 | 266 | ||
244 | read_unlock_irqrestore(&devices_lock, flags); | 267 | rcu_read_unlock(); |
245 | 268 | ||
246 | return dev; | 269 | return dev; |
247 | } | 270 | } |
@@ -249,35 +272,27 @@ static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn) | |||
249 | static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev) | 272 | static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev) |
250 | { | 273 | { |
251 | struct sk_buff *skb_cp; | 274 | struct sk_buff *skb_cp; |
252 | int ret; | ||
253 | 275 | ||
254 | skb_cp = skb_copy(skb, GFP_ATOMIC); | 276 | skb_cp = skb_copy(skb, GFP_ATOMIC); |
255 | if (!skb_cp) | 277 | if (!skb_cp) |
256 | return -ENOMEM; | ||
257 | |||
258 | ret = netif_rx(skb_cp); | ||
259 | if (ret < 0) { | ||
260 | BT_DBG("receive skb %d", ret); | ||
261 | return NET_RX_DROP; | 278 | return NET_RX_DROP; |
262 | } | ||
263 | 279 | ||
264 | return ret; | 280 | return netif_rx(skb_cp); |
265 | } | 281 | } |
266 | 282 | ||
267 | static int process_data(struct sk_buff *skb, struct net_device *netdev, | 283 | static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev, |
268 | struct l2cap_chan *chan) | 284 | struct l2cap_chan *chan) |
269 | { | 285 | { |
270 | const u8 *saddr, *daddr; | 286 | const u8 *saddr, *daddr; |
271 | u8 iphc0, iphc1; | 287 | u8 iphc0, iphc1; |
272 | struct lowpan_dev *dev; | 288 | struct lowpan_dev *dev; |
273 | struct lowpan_peer *peer; | 289 | struct lowpan_peer *peer; |
274 | unsigned long flags; | ||
275 | 290 | ||
276 | dev = lowpan_dev(netdev); | 291 | dev = lowpan_dev(netdev); |
277 | 292 | ||
278 | read_lock_irqsave(&devices_lock, flags); | 293 | rcu_read_lock(); |
279 | peer = peer_lookup_chan(dev, chan); | 294 | peer = __peer_lookup_chan(dev, chan); |
280 | read_unlock_irqrestore(&devices_lock, flags); | 295 | rcu_read_unlock(); |
281 | if (!peer) | 296 | if (!peer) |
282 | goto drop; | 297 | goto drop; |
283 | 298 | ||
@@ -294,10 +309,11 @@ static int process_data(struct sk_buff *skb, struct net_device *netdev, | |||
294 | if (lowpan_fetch_skb_u8(skb, &iphc1)) | 309 | if (lowpan_fetch_skb_u8(skb, &iphc1)) |
295 | goto drop; | 310 | goto drop; |
296 | 311 | ||
297 | return lowpan_process_data(skb, netdev, | 312 | return lowpan_header_decompress(skb, netdev, |
298 | saddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN, | 313 | saddr, IEEE802154_ADDR_LONG, |
299 | daddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN, | 314 | EUI64_ADDR_LEN, daddr, |
300 | iphc0, iphc1, give_skb_to_upper); | 315 | IEEE802154_ADDR_LONG, EUI64_ADDR_LEN, |
316 | iphc0, iphc1); | ||
301 | 317 | ||
302 | drop: | 318 | drop: |
303 | kfree_skb(skb); | 319 | kfree_skb(skb); |
@@ -316,6 +332,10 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, | |||
316 | if (dev->type != ARPHRD_6LOWPAN) | 332 | if (dev->type != ARPHRD_6LOWPAN) |
317 | goto drop; | 333 | goto drop; |
318 | 334 | ||
335 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
336 | if (!skb) | ||
337 | goto drop; | ||
338 | |||
319 | /* check that it's our buffer */ | 339 | /* check that it's our buffer */ |
320 | if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { | 340 | if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { |
321 | /* Copy the packet so that the IPv6 header is | 341 | /* Copy the packet so that the IPv6 header is |
@@ -340,8 +360,8 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, | |||
340 | dev->stats.rx_bytes += skb->len; | 360 | dev->stats.rx_bytes += skb->len; |
341 | dev->stats.rx_packets++; | 361 | dev->stats.rx_packets++; |
342 | 362 | ||
343 | kfree_skb(local_skb); | 363 | consume_skb(local_skb); |
344 | kfree_skb(skb); | 364 | consume_skb(skb); |
345 | } else { | 365 | } else { |
346 | switch (skb->data[0] & 0xe0) { | 366 | switch (skb->data[0] & 0xe0) { |
347 | case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ | 367 | case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ |
@@ -349,14 +369,25 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, | |||
349 | if (!local_skb) | 369 | if (!local_skb) |
350 | goto drop; | 370 | goto drop; |
351 | 371 | ||
352 | ret = process_data(local_skb, dev, chan); | 372 | ret = iphc_decompress(local_skb, dev, chan); |
353 | if (ret != NET_RX_SUCCESS) | 373 | if (ret < 0) |
354 | goto drop; | 374 | goto drop; |
355 | 375 | ||
376 | local_skb->protocol = htons(ETH_P_IPV6); | ||
377 | local_skb->pkt_type = PACKET_HOST; | ||
378 | local_skb->dev = dev; | ||
379 | |||
380 | if (give_skb_to_upper(local_skb, dev) | ||
381 | != NET_RX_SUCCESS) { | ||
382 | kfree_skb(local_skb); | ||
383 | goto drop; | ||
384 | } | ||
385 | |||
356 | dev->stats.rx_bytes += skb->len; | 386 | dev->stats.rx_bytes += skb->len; |
357 | dev->stats.rx_packets++; | 387 | dev->stats.rx_packets++; |
358 | 388 | ||
359 | kfree_skb(skb); | 389 | consume_skb(local_skb); |
390 | consume_skb(skb); | ||
360 | break; | 391 | break; |
361 | default: | 392 | default: |
362 | break; | 393 | break; |
@@ -443,7 +474,6 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev, | |||
443 | if (ipv6_addr_is_multicast(&ipv6_daddr)) { | 474 | if (ipv6_addr_is_multicast(&ipv6_daddr)) { |
444 | lowpan_cb(skb)->chan = NULL; | 475 | lowpan_cb(skb)->chan = NULL; |
445 | } else { | 476 | } else { |
446 | unsigned long flags; | ||
447 | u8 addr_type; | 477 | u8 addr_type; |
448 | 478 | ||
449 | /* Get destination BT device from skb. | 479 | /* Get destination BT device from skb. |
@@ -454,19 +484,14 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev, | |||
454 | BT_DBG("dest addr %pMR type %d IP %pI6c", &addr, | 484 | BT_DBG("dest addr %pMR type %d IP %pI6c", &addr, |
455 | addr_type, &ipv6_daddr); | 485 | addr_type, &ipv6_daddr); |
456 | 486 | ||
457 | read_lock_irqsave(&devices_lock, flags); | ||
458 | peer = peer_lookup_ba(dev, &addr, addr_type); | 487 | peer = peer_lookup_ba(dev, &addr, addr_type); |
459 | read_unlock_irqrestore(&devices_lock, flags); | ||
460 | |||
461 | if (!peer) { | 488 | if (!peer) { |
462 | /* The packet might be sent to 6lowpan interface | 489 | /* The packet might be sent to 6lowpan interface |
463 | * because of routing (either via default route | 490 | * because of routing (either via default route |
464 | * or user set route) so get peer according to | 491 | * or user set route) so get peer according to |
465 | * the destination address. | 492 | * the destination address. |
466 | */ | 493 | */ |
467 | read_lock_irqsave(&devices_lock, flags); | ||
468 | peer = peer_lookup_dst(dev, &ipv6_daddr, skb); | 494 | peer = peer_lookup_dst(dev, &ipv6_daddr, skb); |
469 | read_unlock_irqrestore(&devices_lock, flags); | ||
470 | if (!peer) { | 495 | if (!peer) { |
471 | BT_DBG("no such peer %pMR found", &addr); | 496 | BT_DBG("no such peer %pMR found", &addr); |
472 | return -ENOENT; | 497 | return -ENOENT; |
@@ -549,14 +574,13 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb, | |||
549 | static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) | 574 | static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) |
550 | { | 575 | { |
551 | struct sk_buff *local_skb; | 576 | struct sk_buff *local_skb; |
552 | struct lowpan_dev *entry, *tmp; | 577 | struct lowpan_dev *entry; |
553 | unsigned long flags; | ||
554 | int err = 0; | 578 | int err = 0; |
555 | 579 | ||
556 | read_lock_irqsave(&devices_lock, flags); | 580 | rcu_read_lock(); |
557 | 581 | ||
558 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | 582 | list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) { |
559 | struct lowpan_peer *pentry, *ptmp; | 583 | struct lowpan_peer *pentry; |
560 | struct lowpan_dev *dev; | 584 | struct lowpan_dev *dev; |
561 | 585 | ||
562 | if (entry->netdev != netdev) | 586 | if (entry->netdev != netdev) |
@@ -564,7 +588,7 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) | |||
564 | 588 | ||
565 | dev = lowpan_dev(entry->netdev); | 589 | dev = lowpan_dev(entry->netdev); |
566 | 590 | ||
567 | list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) { | 591 | list_for_each_entry_rcu(pentry, &dev->peers, list) { |
568 | int ret; | 592 | int ret; |
569 | 593 | ||
570 | local_skb = skb_clone(skb, GFP_ATOMIC); | 594 | local_skb = skb_clone(skb, GFP_ATOMIC); |
@@ -581,7 +605,7 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev) | |||
581 | } | 605 | } |
582 | } | 606 | } |
583 | 607 | ||
584 | read_unlock_irqrestore(&devices_lock, flags); | 608 | rcu_read_unlock(); |
585 | 609 | ||
586 | return err; | 610 | return err; |
587 | } | 611 | } |
@@ -638,7 +662,26 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
638 | return err < 0 ? NET_XMIT_DROP : err; | 662 | return err < 0 ? NET_XMIT_DROP : err; |
639 | } | 663 | } |
640 | 664 | ||
665 | static struct lock_class_key bt_tx_busylock; | ||
666 | static struct lock_class_key bt_netdev_xmit_lock_key; | ||
667 | |||
668 | static void bt_set_lockdep_class_one(struct net_device *dev, | ||
669 | struct netdev_queue *txq, | ||
670 | void *_unused) | ||
671 | { | ||
672 | lockdep_set_class(&txq->_xmit_lock, &bt_netdev_xmit_lock_key); | ||
673 | } | ||
674 | |||
675 | static int bt_dev_init(struct net_device *dev) | ||
676 | { | ||
677 | netdev_for_each_tx_queue(dev, bt_set_lockdep_class_one, NULL); | ||
678 | dev->qdisc_tx_busylock = &bt_tx_busylock; | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
641 | static const struct net_device_ops netdev_ops = { | 683 | static const struct net_device_ops netdev_ops = { |
684 | .ndo_init = bt_dev_init, | ||
642 | .ndo_start_xmit = bt_xmit, | 685 | .ndo_start_xmit = bt_xmit, |
643 | }; | 686 | }; |
644 | 687 | ||
@@ -783,7 +826,6 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan, | |||
783 | struct lowpan_dev *dev) | 826 | struct lowpan_dev *dev) |
784 | { | 827 | { |
785 | struct lowpan_peer *peer; | 828 | struct lowpan_peer *peer; |
786 | unsigned long flags; | ||
787 | 829 | ||
788 | peer = kzalloc(sizeof(*peer), GFP_ATOMIC); | 830 | peer = kzalloc(sizeof(*peer), GFP_ATOMIC); |
789 | if (!peer) | 831 | if (!peer) |
@@ -806,10 +848,10 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan, | |||
806 | */ | 848 | */ |
807 | set_ip_addr_bits(chan->dst_type, (u8 *)&peer->peer_addr.s6_addr + 8); | 849 | set_ip_addr_bits(chan->dst_type, (u8 *)&peer->peer_addr.s6_addr + 8); |
808 | 850 | ||
809 | write_lock_irqsave(&devices_lock, flags); | 851 | spin_lock(&devices_lock); |
810 | INIT_LIST_HEAD(&peer->list); | 852 | INIT_LIST_HEAD(&peer->list); |
811 | peer_add(dev, peer); | 853 | peer_add(dev, peer); |
812 | write_unlock_irqrestore(&devices_lock, flags); | 854 | spin_unlock(&devices_lock); |
813 | 855 | ||
814 | /* Notifying peers about us needs to be done without locks held */ | 856 | /* Notifying peers about us needs to be done without locks held */ |
815 | INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers); | 857 | INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers); |
@@ -822,7 +864,6 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) | |||
822 | { | 864 | { |
823 | struct net_device *netdev; | 865 | struct net_device *netdev; |
824 | int err = 0; | 866 | int err = 0; |
825 | unsigned long flags; | ||
826 | 867 | ||
827 | netdev = alloc_netdev(sizeof(struct lowpan_dev), IFACE_NAME_TEMPLATE, | 868 | netdev = alloc_netdev(sizeof(struct lowpan_dev), IFACE_NAME_TEMPLATE, |
828 | NET_NAME_UNKNOWN, netdev_setup); | 869 | NET_NAME_UNKNOWN, netdev_setup); |
@@ -852,10 +893,10 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) | |||
852 | (*dev)->hdev = chan->conn->hcon->hdev; | 893 | (*dev)->hdev = chan->conn->hcon->hdev; |
853 | INIT_LIST_HEAD(&(*dev)->peers); | 894 | INIT_LIST_HEAD(&(*dev)->peers); |
854 | 895 | ||
855 | write_lock_irqsave(&devices_lock, flags); | 896 | spin_lock(&devices_lock); |
856 | INIT_LIST_HEAD(&(*dev)->list); | 897 | INIT_LIST_HEAD(&(*dev)->list); |
857 | list_add(&(*dev)->list, &bt_6lowpan_devices); | 898 | list_add_rcu(&(*dev)->list, &bt_6lowpan_devices); |
858 | write_unlock_irqrestore(&devices_lock, flags); | 899 | spin_unlock(&devices_lock); |
859 | 900 | ||
860 | return 0; | 901 | return 0; |
861 | 902 | ||
@@ -909,11 +950,10 @@ static void delete_netdev(struct work_struct *work) | |||
909 | 950 | ||
910 | static void chan_close_cb(struct l2cap_chan *chan) | 951 | static void chan_close_cb(struct l2cap_chan *chan) |
911 | { | 952 | { |
912 | struct lowpan_dev *entry, *tmp; | 953 | struct lowpan_dev *entry; |
913 | struct lowpan_dev *dev = NULL; | 954 | struct lowpan_dev *dev = NULL; |
914 | struct lowpan_peer *peer; | 955 | struct lowpan_peer *peer; |
915 | int err = -ENOENT; | 956 | int err = -ENOENT; |
916 | unsigned long flags; | ||
917 | bool last = false, removed = true; | 957 | bool last = false, removed = true; |
918 | 958 | ||
919 | BT_DBG("chan %p conn %p", chan, chan->conn); | 959 | BT_DBG("chan %p conn %p", chan, chan->conn); |
@@ -928,11 +968,11 @@ static void chan_close_cb(struct l2cap_chan *chan) | |||
928 | removed = false; | 968 | removed = false; |
929 | } | 969 | } |
930 | 970 | ||
931 | write_lock_irqsave(&devices_lock, flags); | 971 | spin_lock(&devices_lock); |
932 | 972 | ||
933 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | 973 | list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) { |
934 | dev = lowpan_dev(entry->netdev); | 974 | dev = lowpan_dev(entry->netdev); |
935 | peer = peer_lookup_chan(dev, chan); | 975 | peer = __peer_lookup_chan(dev, chan); |
936 | if (peer) { | 976 | if (peer) { |
937 | last = peer_del(dev, peer); | 977 | last = peer_del(dev, peer); |
938 | err = 0; | 978 | err = 0; |
@@ -943,13 +983,12 @@ static void chan_close_cb(struct l2cap_chan *chan) | |||
943 | atomic_read(&chan->kref.refcount)); | 983 | atomic_read(&chan->kref.refcount)); |
944 | 984 | ||
945 | l2cap_chan_put(chan); | 985 | l2cap_chan_put(chan); |
946 | kfree(peer); | ||
947 | break; | 986 | break; |
948 | } | 987 | } |
949 | } | 988 | } |
950 | 989 | ||
951 | if (!err && last && dev && !atomic_read(&dev->peer_count)) { | 990 | if (!err && last && dev && !atomic_read(&dev->peer_count)) { |
952 | write_unlock_irqrestore(&devices_lock, flags); | 991 | spin_unlock(&devices_lock); |
953 | 992 | ||
954 | cancel_delayed_work_sync(&dev->notify_peers); | 993 | cancel_delayed_work_sync(&dev->notify_peers); |
955 | 994 | ||
@@ -960,7 +999,7 @@ static void chan_close_cb(struct l2cap_chan *chan) | |||
960 | schedule_work(&entry->delete_netdev); | 999 | schedule_work(&entry->delete_netdev); |
961 | } | 1000 | } |
962 | } else { | 1001 | } else { |
963 | write_unlock_irqrestore(&devices_lock, flags); | 1002 | spin_unlock(&devices_lock); |
964 | } | 1003 | } |
965 | 1004 | ||
966 | return; | 1005 | return; |
@@ -1152,10 +1191,9 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type, | |||
1152 | 1191 | ||
1153 | static void disconnect_all_peers(void) | 1192 | static void disconnect_all_peers(void) |
1154 | { | 1193 | { |
1155 | struct lowpan_dev *entry, *tmp_dev; | 1194 | struct lowpan_dev *entry; |
1156 | struct lowpan_peer *peer, *tmp_peer, *new_peer; | 1195 | struct lowpan_peer *peer, *tmp_peer, *new_peer; |
1157 | struct list_head peers; | 1196 | struct list_head peers; |
1158 | unsigned long flags; | ||
1159 | 1197 | ||
1160 | INIT_LIST_HEAD(&peers); | 1198 | INIT_LIST_HEAD(&peers); |
1161 | 1199 | ||
@@ -1164,10 +1202,10 @@ static void disconnect_all_peers(void) | |||
1164 | * with the same list at the same time. | 1202 | * with the same list at the same time. |
1165 | */ | 1203 | */ |
1166 | 1204 | ||
1167 | read_lock_irqsave(&devices_lock, flags); | 1205 | rcu_read_lock(); |
1168 | 1206 | ||
1169 | list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) { | 1207 | list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) { |
1170 | list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list) { | 1208 | list_for_each_entry_rcu(peer, &entry->peers, list) { |
1171 | new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC); | 1209 | new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC); |
1172 | if (!new_peer) | 1210 | if (!new_peer) |
1173 | break; | 1211 | break; |
@@ -1179,26 +1217,36 @@ static void disconnect_all_peers(void) | |||
1179 | } | 1217 | } |
1180 | } | 1218 | } |
1181 | 1219 | ||
1182 | read_unlock_irqrestore(&devices_lock, flags); | 1220 | rcu_read_unlock(); |
1183 | 1221 | ||
1222 | spin_lock(&devices_lock); | ||
1184 | list_for_each_entry_safe(peer, tmp_peer, &peers, list) { | 1223 | list_for_each_entry_safe(peer, tmp_peer, &peers, list) { |
1185 | l2cap_chan_close(peer->chan, ENOENT); | 1224 | l2cap_chan_close(peer->chan, ENOENT); |
1186 | kfree(peer); | 1225 | |
1226 | list_del_rcu(&peer->list); | ||
1227 | call_rcu(&peer->rcu, peer_free); | ||
1228 | |||
1229 | module_put(THIS_MODULE); | ||
1187 | } | 1230 | } |
1231 | spin_unlock(&devices_lock); | ||
1188 | } | 1232 | } |
1189 | 1233 | ||
1190 | static int lowpan_psm_set(void *data, u64 val) | 1234 | struct set_psm { |
1191 | { | 1235 | struct work_struct work; |
1192 | u16 psm; | 1236 | u16 psm; |
1237 | }; | ||
1238 | |||
1239 | static void do_psm_set(struct work_struct *work) | ||
1240 | { | ||
1241 | struct set_psm *set_psm = container_of(work, struct set_psm, work); | ||
1193 | 1242 | ||
1194 | psm = val; | 1243 | if (set_psm->psm == 0 || psm_6lowpan != set_psm->psm) |
1195 | if (psm == 0 || psm_6lowpan != psm) | ||
1196 | /* Disconnect existing connections if 6lowpan is | 1244 | /* Disconnect existing connections if 6lowpan is |
1197 | * disabled (psm = 0), or if psm changes. | 1245 | * disabled (psm = 0), or if psm changes. |
1198 | */ | 1246 | */ |
1199 | disconnect_all_peers(); | 1247 | disconnect_all_peers(); |
1200 | 1248 | ||
1201 | psm_6lowpan = psm; | 1249 | psm_6lowpan = set_psm->psm; |
1202 | 1250 | ||
1203 | if (listen_chan) { | 1251 | if (listen_chan) { |
1204 | l2cap_chan_close(listen_chan, 0); | 1252 | l2cap_chan_close(listen_chan, 0); |
@@ -1207,6 +1255,22 @@ static int lowpan_psm_set(void *data, u64 val) | |||
1207 | 1255 | ||
1208 | listen_chan = bt_6lowpan_listen(); | 1256 | listen_chan = bt_6lowpan_listen(); |
1209 | 1257 | ||
1258 | kfree(set_psm); | ||
1259 | } | ||
1260 | |||
1261 | static int lowpan_psm_set(void *data, u64 val) | ||
1262 | { | ||
1263 | struct set_psm *set_psm; | ||
1264 | |||
1265 | set_psm = kzalloc(sizeof(*set_psm), GFP_KERNEL); | ||
1266 | if (!set_psm) | ||
1267 | return -ENOMEM; | ||
1268 | |||
1269 | set_psm->psm = val; | ||
1270 | INIT_WORK(&set_psm->work, do_psm_set); | ||
1271 | |||
1272 | schedule_work(&set_psm->work); | ||
1273 | |||
1210 | return 0; | 1274 | return 0; |
1211 | } | 1275 | } |
1212 | 1276 | ||
@@ -1288,19 +1352,18 @@ static ssize_t lowpan_control_write(struct file *fp, | |||
1288 | 1352 | ||
1289 | static int lowpan_control_show(struct seq_file *f, void *ptr) | 1353 | static int lowpan_control_show(struct seq_file *f, void *ptr) |
1290 | { | 1354 | { |
1291 | struct lowpan_dev *entry, *tmp_dev; | 1355 | struct lowpan_dev *entry; |
1292 | struct lowpan_peer *peer, *tmp_peer; | 1356 | struct lowpan_peer *peer; |
1293 | unsigned long flags; | ||
1294 | 1357 | ||
1295 | read_lock_irqsave(&devices_lock, flags); | 1358 | spin_lock(&devices_lock); |
1296 | 1359 | ||
1297 | list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) { | 1360 | list_for_each_entry(entry, &bt_6lowpan_devices, list) { |
1298 | list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list) | 1361 | list_for_each_entry(peer, &entry->peers, list) |
1299 | seq_printf(f, "%pMR (type %u)\n", | 1362 | seq_printf(f, "%pMR (type %u)\n", |
1300 | &peer->chan->dst, peer->chan->dst_type); | 1363 | &peer->chan->dst, peer->chan->dst_type); |
1301 | } | 1364 | } |
1302 | 1365 | ||
1303 | read_unlock_irqrestore(&devices_lock, flags); | 1366 | spin_unlock(&devices_lock); |
1304 | 1367 | ||
1305 | return 0; | 1368 | return 0; |
1306 | } | 1369 | } |
@@ -1322,7 +1385,6 @@ static void disconnect_devices(void) | |||
1322 | { | 1385 | { |
1323 | struct lowpan_dev *entry, *tmp, *new_dev; | 1386 | struct lowpan_dev *entry, *tmp, *new_dev; |
1324 | struct list_head devices; | 1387 | struct list_head devices; |
1325 | unsigned long flags; | ||
1326 | 1388 | ||
1327 | INIT_LIST_HEAD(&devices); | 1389 | INIT_LIST_HEAD(&devices); |
1328 | 1390 | ||
@@ -1331,9 +1393,9 @@ static void disconnect_devices(void) | |||
1331 | * devices list. | 1393 | * devices list. |
1332 | */ | 1394 | */ |
1333 | 1395 | ||
1334 | read_lock_irqsave(&devices_lock, flags); | 1396 | rcu_read_lock(); |
1335 | 1397 | ||
1336 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) { | 1398 | list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) { |
1337 | new_dev = kmalloc(sizeof(*new_dev), GFP_ATOMIC); | 1399 | new_dev = kmalloc(sizeof(*new_dev), GFP_ATOMIC); |
1338 | if (!new_dev) | 1400 | if (!new_dev) |
1339 | break; | 1401 | break; |
@@ -1341,10 +1403,10 @@ static void disconnect_devices(void) | |||
1341 | new_dev->netdev = entry->netdev; | 1403 | new_dev->netdev = entry->netdev; |
1342 | INIT_LIST_HEAD(&new_dev->list); | 1404 | INIT_LIST_HEAD(&new_dev->list); |
1343 | 1405 | ||
1344 | list_add(&new_dev->list, &devices); | 1406 | list_add_rcu(&new_dev->list, &devices); |
1345 | } | 1407 | } |
1346 | 1408 | ||
1347 | read_unlock_irqrestore(&devices_lock, flags); | 1409 | rcu_read_unlock(); |
1348 | 1410 | ||
1349 | list_for_each_entry_safe(entry, tmp, &devices, list) { | 1411 | list_for_each_entry_safe(entry, tmp, &devices, list) { |
1350 | ifdown(entry->netdev); | 1412 | ifdown(entry->netdev); |
@@ -1359,17 +1421,15 @@ static int device_event(struct notifier_block *unused, | |||
1359 | unsigned long event, void *ptr) | 1421 | unsigned long event, void *ptr) |
1360 | { | 1422 | { |
1361 | struct net_device *netdev = netdev_notifier_info_to_dev(ptr); | 1423 | struct net_device *netdev = netdev_notifier_info_to_dev(ptr); |
1362 | struct lowpan_dev *entry, *tmp; | 1424 | struct lowpan_dev *entry; |
1363 | unsigned long flags; | ||
1364 | 1425 | ||
1365 | if (netdev->type != ARPHRD_6LOWPAN) | 1426 | if (netdev->type != ARPHRD_6LOWPAN) |
1366 | return NOTIFY_DONE; | 1427 | return NOTIFY_DONE; |
1367 | 1428 | ||
1368 | switch (event) { | 1429 | switch (event) { |
1369 | case NETDEV_UNREGISTER: | 1430 | case NETDEV_UNREGISTER: |
1370 | write_lock_irqsave(&devices_lock, flags); | 1431 | spin_lock(&devices_lock); |
1371 | list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, | 1432 | list_for_each_entry(entry, &bt_6lowpan_devices, list) { |
1372 | list) { | ||
1373 | if (entry->netdev == netdev) { | 1433 | if (entry->netdev == netdev) { |
1374 | BT_DBG("Unregistered netdev %s %p", | 1434 | BT_DBG("Unregistered netdev %s %p", |
1375 | netdev->name, netdev); | 1435 | netdev->name, netdev); |
@@ -1378,7 +1438,7 @@ static int device_event(struct notifier_block *unused, | |||
1378 | break; | 1438 | break; |
1379 | } | 1439 | } |
1380 | } | 1440 | } |
1381 | write_unlock_irqrestore(&devices_lock, flags); | 1441 | spin_unlock(&devices_lock); |
1382 | break; | 1442 | break; |
1383 | } | 1443 | } |
1384 | 1444 | ||
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b9517bd17190..96887ae8375b 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -141,10 +141,11 @@ int hci_disconnect(struct hci_conn *conn, __u8 reason) | |||
141 | */ | 141 | */ |
142 | if (conn->type == ACL_LINK && conn->role == HCI_ROLE_MASTER) { | 142 | if (conn->type == ACL_LINK && conn->role == HCI_ROLE_MASTER) { |
143 | struct hci_dev *hdev = conn->hdev; | 143 | struct hci_dev *hdev = conn->hdev; |
144 | struct hci_cp_read_clock_offset cp; | 144 | struct hci_cp_read_clock_offset clkoff_cp; |
145 | 145 | ||
146 | cp.handle = cpu_to_le16(conn->handle); | 146 | clkoff_cp.handle = cpu_to_le16(conn->handle); |
147 | hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, sizeof(cp), &cp); | 147 | hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, sizeof(clkoff_cp), |
148 | &clkoff_cp); | ||
148 | } | 149 | } |
149 | 150 | ||
150 | conn->state = BT_DISCONN; | 151 | conn->state = BT_DISCONN; |
@@ -415,7 +416,7 @@ static void le_conn_timeout(struct work_struct *work) | |||
415 | * happen with broken hardware or if low duty cycle was used | 416 | * happen with broken hardware or if low duty cycle was used |
416 | * (which doesn't have a timeout of its own). | 417 | * (which doesn't have a timeout of its own). |
417 | */ | 418 | */ |
418 | if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { | 419 | if (conn->role == HCI_ROLE_SLAVE) { |
419 | u8 enable = 0x00; | 420 | u8 enable = 0x00; |
420 | hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), | 421 | hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), |
421 | &enable); | 422 | &enable); |
@@ -517,7 +518,7 @@ int hci_conn_del(struct hci_conn *conn) | |||
517 | /* Unacked frames */ | 518 | /* Unacked frames */ |
518 | hdev->acl_cnt += conn->sent; | 519 | hdev->acl_cnt += conn->sent; |
519 | } else if (conn->type == LE_LINK) { | 520 | } else if (conn->type == LE_LINK) { |
520 | cancel_delayed_work_sync(&conn->le_conn_timeout); | 521 | cancel_delayed_work(&conn->le_conn_timeout); |
521 | 522 | ||
522 | if (hdev->le_pkts) | 523 | if (hdev->le_pkts) |
523 | hdev->le_cnt += conn->sent; | 524 | hdev->le_cnt += conn->sent; |
@@ -544,6 +545,9 @@ int hci_conn_del(struct hci_conn *conn) | |||
544 | 545 | ||
545 | hci_conn_del_sysfs(conn); | 546 | hci_conn_del_sysfs(conn); |
546 | 547 | ||
548 | if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags)) | ||
549 | hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type); | ||
550 | |||
547 | hci_dev_put(hdev); | 551 | hci_dev_put(hdev); |
548 | 552 | ||
549 | hci_conn_put(conn); | 553 | hci_conn_put(conn); |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index cb05d7f16a34..91995f8ab0a0 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -4477,7 +4477,7 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete) | |||
4477 | 4477 | ||
4478 | BT_DBG("length %u", skb_queue_len(&req->cmd_q)); | 4478 | BT_DBG("length %u", skb_queue_len(&req->cmd_q)); |
4479 | 4479 | ||
4480 | /* If an error occured during request building, remove all HCI | 4480 | /* If an error occurred during request building, remove all HCI |
4481 | * commands queued on the HCI request queue. | 4481 | * commands queued on the HCI request queue. |
4482 | */ | 4482 | */ |
4483 | if (req->err) { | 4483 | if (req->err) { |
@@ -4546,7 +4546,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, | |||
4546 | return -ENOMEM; | 4546 | return -ENOMEM; |
4547 | } | 4547 | } |
4548 | 4548 | ||
4549 | /* Stand-alone HCI commands must be flaged as | 4549 | /* Stand-alone HCI commands must be flagged as |
4550 | * single-command requests. | 4550 | * single-command requests. |
4551 | */ | 4551 | */ |
4552 | bt_cb(skb)->req.start = true; | 4552 | bt_cb(skb)->req.start = true; |
@@ -4566,7 +4566,7 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen, | |||
4566 | 4566 | ||
4567 | BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen); | 4567 | BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen); |
4568 | 4568 | ||
4569 | /* If an error occured during request building, there is no point in | 4569 | /* If an error occurred during request building, there is no point in |
4570 | * queueing the HCI command. We can simply return. | 4570 | * queueing the HCI command. We can simply return. |
4571 | */ | 4571 | */ |
4572 | if (req->err) | 4572 | if (req->err) |
@@ -4661,8 +4661,12 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue, | |||
4661 | 4661 | ||
4662 | skb_shinfo(skb)->frag_list = NULL; | 4662 | skb_shinfo(skb)->frag_list = NULL; |
4663 | 4663 | ||
4664 | /* Queue all fragments atomically */ | 4664 | /* Queue all fragments atomically. We need to use spin_lock_bh |
4665 | spin_lock(&queue->lock); | 4665 | * here because of 6LoWPAN links, as there this function is |
4666 | * called from softirq and using normal spin lock could cause | ||
4667 | * deadlocks. | ||
4668 | */ | ||
4669 | spin_lock_bh(&queue->lock); | ||
4666 | 4670 | ||
4667 | __skb_queue_tail(queue, skb); | 4671 | __skb_queue_tail(queue, skb); |
4668 | 4672 | ||
@@ -4679,7 +4683,7 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue, | |||
4679 | __skb_queue_tail(queue, skb); | 4683 | __skb_queue_tail(queue, skb); |
4680 | } while (list); | 4684 | } while (list); |
4681 | 4685 | ||
4682 | spin_unlock(&queue->lock); | 4686 | spin_unlock_bh(&queue->lock); |
4683 | } | 4687 | } |
4684 | } | 4688 | } |
4685 | 4689 | ||
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8b0a2a6de419..aa152140c3e2 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -205,6 +205,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) | |||
205 | hdev->le_scan_type = LE_SCAN_PASSIVE; | 205 | hdev->le_scan_type = LE_SCAN_PASSIVE; |
206 | 206 | ||
207 | hdev->ssp_debug_mode = 0; | 207 | hdev->ssp_debug_mode = 0; |
208 | |||
209 | hci_bdaddr_list_clear(&hdev->le_white_list); | ||
208 | } | 210 | } |
209 | 211 | ||
210 | static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) | 212 | static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -1045,7 +1047,7 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) | |||
1045 | 1047 | ||
1046 | hci_dev_lock(hdev); | 1048 | hci_dev_lock(hdev); |
1047 | 1049 | ||
1048 | /* If we're doing connection initation as peripheral. Set a | 1050 | /* If we're doing connection initiation as peripheral. Set a |
1049 | * timeout in case something goes wrong. | 1051 | * timeout in case something goes wrong. |
1050 | */ | 1052 | */ |
1051 | if (*sent) { | 1053 | if (*sent) { |
@@ -1577,8 +1579,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn, | |||
1577 | struct inquiry_entry *e; | 1579 | struct inquiry_entry *e; |
1578 | 1580 | ||
1579 | if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) | 1581 | if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) |
1580 | mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name, | 1582 | mgmt_device_connected(hdev, conn, 0, name, name_len); |
1581 | name_len, conn->dev_class); | ||
1582 | 1583 | ||
1583 | if (discov->state == DISCOVERY_STOPPED) | 1584 | if (discov->state == DISCOVERY_STOPPED) |
1584 | return; | 1585 | return; |
@@ -2536,9 +2537,7 @@ static void hci_remote_features_evt(struct hci_dev *hdev, | |||
2536 | cp.pscan_rep_mode = 0x02; | 2537 | cp.pscan_rep_mode = 0x02; |
2537 | hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); | 2538 | hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); |
2538 | } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) | 2539 | } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) |
2539 | mgmt_device_connected(hdev, &conn->dst, conn->type, | 2540 | mgmt_device_connected(hdev, conn, 0, NULL, 0); |
2540 | conn->dst_type, 0, NULL, 0, | ||
2541 | conn->dev_class); | ||
2542 | 2541 | ||
2543 | if (!hci_outgoing_auth_needed(hdev, conn)) { | 2542 | if (!hci_outgoing_auth_needed(hdev, conn)) { |
2544 | conn->state = BT_CONNECTED; | 2543 | conn->state = BT_CONNECTED; |
@@ -3434,9 +3433,7 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev, | |||
3434 | cp.pscan_rep_mode = 0x02; | 3433 | cp.pscan_rep_mode = 0x02; |
3435 | hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); | 3434 | hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp); |
3436 | } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) | 3435 | } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) |
3437 | mgmt_device_connected(hdev, &conn->dst, conn->type, | 3436 | mgmt_device_connected(hdev, conn, 0, NULL, 0); |
3438 | conn->dst_type, 0, NULL, 0, | ||
3439 | conn->dev_class); | ||
3440 | 3437 | ||
3441 | if (!hci_outgoing_auth_needed(hdev, conn)) { | 3438 | if (!hci_outgoing_auth_needed(hdev, conn)) { |
3442 | conn->state = BT_CONNECTED; | 3439 | conn->state = BT_CONNECTED; |
@@ -4214,8 +4211,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | |||
4214 | } | 4211 | } |
4215 | 4212 | ||
4216 | if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) | 4213 | if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) |
4217 | mgmt_device_connected(hdev, &conn->dst, conn->type, | 4214 | mgmt_device_connected(hdev, conn, 0, NULL, 0); |
4218 | conn->dst_type, 0, NULL, 0, NULL); | ||
4219 | 4215 | ||
4220 | conn->sec_level = BT_SECURITY_LOW; | 4216 | conn->sec_level = BT_SECURITY_LOW; |
4221 | conn->handle = __le16_to_cpu(ev->handle); | 4217 | conn->handle = __le16_to_cpu(ev->handle); |
@@ -4269,25 +4265,26 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, | |||
4269 | } | 4265 | } |
4270 | 4266 | ||
4271 | /* This function requires the caller holds hdev->lock */ | 4267 | /* This function requires the caller holds hdev->lock */ |
4272 | static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, | 4268 | static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev, |
4273 | u8 addr_type, u8 adv_type) | 4269 | bdaddr_t *addr, |
4270 | u8 addr_type, u8 adv_type) | ||
4274 | { | 4271 | { |
4275 | struct hci_conn *conn; | 4272 | struct hci_conn *conn; |
4276 | struct hci_conn_params *params; | 4273 | struct hci_conn_params *params; |
4277 | 4274 | ||
4278 | /* If the event is not connectable don't proceed further */ | 4275 | /* If the event is not connectable don't proceed further */ |
4279 | if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND) | 4276 | if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND) |
4280 | return; | 4277 | return NULL; |
4281 | 4278 | ||
4282 | /* Ignore if the device is blocked */ | 4279 | /* Ignore if the device is blocked */ |
4283 | if (hci_bdaddr_list_lookup(&hdev->blacklist, addr, addr_type)) | 4280 | if (hci_bdaddr_list_lookup(&hdev->blacklist, addr, addr_type)) |
4284 | return; | 4281 | return NULL; |
4285 | 4282 | ||
4286 | /* Most controller will fail if we try to create new connections | 4283 | /* Most controller will fail if we try to create new connections |
4287 | * while we have an existing one in slave role. | 4284 | * while we have an existing one in slave role. |
4288 | */ | 4285 | */ |
4289 | if (hdev->conn_hash.le_num_slave > 0) | 4286 | if (hdev->conn_hash.le_num_slave > 0) |
4290 | return; | 4287 | return NULL; |
4291 | 4288 | ||
4292 | /* If we're not connectable only connect devices that we have in | 4289 | /* If we're not connectable only connect devices that we have in |
4293 | * our pend_le_conns list. | 4290 | * our pend_le_conns list. |
@@ -4295,7 +4292,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, | |||
4295 | params = hci_pend_le_action_lookup(&hdev->pend_le_conns, | 4292 | params = hci_pend_le_action_lookup(&hdev->pend_le_conns, |
4296 | addr, addr_type); | 4293 | addr, addr_type); |
4297 | if (!params) | 4294 | if (!params) |
4298 | return; | 4295 | return NULL; |
4299 | 4296 | ||
4300 | switch (params->auto_connect) { | 4297 | switch (params->auto_connect) { |
4301 | case HCI_AUTO_CONN_DIRECT: | 4298 | case HCI_AUTO_CONN_DIRECT: |
@@ -4304,7 +4301,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, | |||
4304 | * incoming connections from slave devices. | 4301 | * incoming connections from slave devices. |
4305 | */ | 4302 | */ |
4306 | if (adv_type != LE_ADV_DIRECT_IND) | 4303 | if (adv_type != LE_ADV_DIRECT_IND) |
4307 | return; | 4304 | return NULL; |
4308 | break; | 4305 | break; |
4309 | case HCI_AUTO_CONN_ALWAYS: | 4306 | case HCI_AUTO_CONN_ALWAYS: |
4310 | /* Devices advertising with ADV_IND or ADV_DIRECT_IND | 4307 | /* Devices advertising with ADV_IND or ADV_DIRECT_IND |
@@ -4315,7 +4312,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, | |||
4315 | */ | 4312 | */ |
4316 | break; | 4313 | break; |
4317 | default: | 4314 | default: |
4318 | return; | 4315 | return NULL; |
4319 | } | 4316 | } |
4320 | 4317 | ||
4321 | conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, | 4318 | conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, |
@@ -4328,7 +4325,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, | |||
4328 | * count consistent once the connection is established. | 4325 | * count consistent once the connection is established. |
4329 | */ | 4326 | */ |
4330 | params->conn = hci_conn_get(conn); | 4327 | params->conn = hci_conn_get(conn); |
4331 | return; | 4328 | return conn; |
4332 | } | 4329 | } |
4333 | 4330 | ||
4334 | switch (PTR_ERR(conn)) { | 4331 | switch (PTR_ERR(conn)) { |
@@ -4341,7 +4338,10 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, | |||
4341 | break; | 4338 | break; |
4342 | default: | 4339 | default: |
4343 | BT_DBG("Failed to connect: err %ld", PTR_ERR(conn)); | 4340 | BT_DBG("Failed to connect: err %ld", PTR_ERR(conn)); |
4341 | return NULL; | ||
4344 | } | 4342 | } |
4343 | |||
4344 | return NULL; | ||
4345 | } | 4345 | } |
4346 | 4346 | ||
4347 | static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, | 4347 | static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, |
@@ -4349,6 +4349,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, | |||
4349 | { | 4349 | { |
4350 | struct discovery_state *d = &hdev->discovery; | 4350 | struct discovery_state *d = &hdev->discovery; |
4351 | struct smp_irk *irk; | 4351 | struct smp_irk *irk; |
4352 | struct hci_conn *conn; | ||
4352 | bool match; | 4353 | bool match; |
4353 | u32 flags; | 4354 | u32 flags; |
4354 | 4355 | ||
@@ -4360,7 +4361,14 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, | |||
4360 | } | 4361 | } |
4361 | 4362 | ||
4362 | /* Check if we have been requested to connect to this device */ | 4363 | /* Check if we have been requested to connect to this device */ |
4363 | check_pending_le_conn(hdev, bdaddr, bdaddr_type, type); | 4364 | conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type); |
4365 | if (conn && type == LE_ADV_IND) { | ||
4366 | /* Store report for later inclusion by | ||
4367 | * mgmt_device_connected | ||
4368 | */ | ||
4369 | memcpy(conn->le_adv_data, data, len); | ||
4370 | conn->le_adv_data_len = len; | ||
4371 | } | ||
4364 | 4372 | ||
4365 | /* Passive scanning shouldn't trigger any device found events, | 4373 | /* Passive scanning shouldn't trigger any device found events, |
4366 | * except for devices marked as CONN_REPORT for which we do send | 4374 | * except for devices marked as CONN_REPORT for which we do send |
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 29e1ec7189bd..5e2cd2535978 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c | |||
@@ -987,7 +987,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
987 | skb_queue_tail(&hdev->raw_q, skb); | 987 | skb_queue_tail(&hdev->raw_q, skb); |
988 | queue_work(hdev->workqueue, &hdev->tx_work); | 988 | queue_work(hdev->workqueue, &hdev->tx_work); |
989 | } else { | 989 | } else { |
990 | /* Stand-alone HCI commands must be flaged as | 990 | /* Stand-alone HCI commands must be flagged as |
991 | * single-command requests. | 991 | * single-command requests. |
992 | */ | 992 | */ |
993 | bt_cb(skb)->req.start = true; | 993 | bt_cb(skb)->req.start = true; |
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b6f9777e057d..fc15174c612c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -3873,9 +3873,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn, | |||
3873 | hci_dev_lock(hdev); | 3873 | hci_dev_lock(hdev); |
3874 | if (test_bit(HCI_MGMT, &hdev->dev_flags) && | 3874 | if (test_bit(HCI_MGMT, &hdev->dev_flags) && |
3875 | !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags)) | 3875 | !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags)) |
3876 | mgmt_device_connected(hdev, &hcon->dst, hcon->type, | 3876 | mgmt_device_connected(hdev, hcon, 0, NULL, 0); |
3877 | hcon->dst_type, 0, NULL, 0, | ||
3878 | hcon->dev_class); | ||
3879 | hci_dev_unlock(hdev); | 3877 | hci_dev_unlock(hdev); |
3880 | 3878 | ||
3881 | l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0); | 3879 | l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0); |
@@ -4084,7 +4082,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, | |||
4084 | chan->num_conf_req++; | 4082 | chan->num_conf_req++; |
4085 | } | 4083 | } |
4086 | 4084 | ||
4087 | /* Got Conf Rsp PENDING from remote side and asume we sent | 4085 | /* Got Conf Rsp PENDING from remote side and assume we sent |
4088 | Conf Rsp PENDING in the code above */ | 4086 | Conf Rsp PENDING in the code above */ |
4089 | if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) && | 4087 | if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) && |
4090 | test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) { | 4088 | test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) { |
@@ -5494,6 +5492,7 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn, | |||
5494 | if (credits > max_credits) { | 5492 | if (credits > max_credits) { |
5495 | BT_ERR("LE credits overflow"); | 5493 | BT_ERR("LE credits overflow"); |
5496 | l2cap_send_disconn_req(chan, ECONNRESET); | 5494 | l2cap_send_disconn_req(chan, ECONNRESET); |
5495 | l2cap_chan_unlock(chan); | ||
5497 | 5496 | ||
5498 | /* Return 0 so that we don't trigger an unnecessary | 5497 | /* Return 0 so that we don't trigger an unnecessary |
5499 | * command reject packet. | 5498 | * command reject packet. |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index efb71b022ab6..9c4daf715cf8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -2725,10 +2725,40 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
2725 | } | 2725 | } |
2726 | 2726 | ||
2727 | if (cp->addr.type == BDADDR_BREDR) { | 2727 | if (cp->addr.type == BDADDR_BREDR) { |
2728 | /* If disconnection is requested, then look up the | ||
2729 | * connection. If the remote device is connected, it | ||
2730 | * will be later used to terminate the link. | ||
2731 | * | ||
2732 | * Setting it to NULL explicitly will cause no | ||
2733 | * termination of the link. | ||
2734 | */ | ||
2735 | if (cp->disconnect) | ||
2736 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, | ||
2737 | &cp->addr.bdaddr); | ||
2738 | else | ||
2739 | conn = NULL; | ||
2740 | |||
2728 | err = hci_remove_link_key(hdev, &cp->addr.bdaddr); | 2741 | err = hci_remove_link_key(hdev, &cp->addr.bdaddr); |
2729 | } else { | 2742 | } else { |
2730 | u8 addr_type; | 2743 | u8 addr_type; |
2731 | 2744 | ||
2745 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, | ||
2746 | &cp->addr.bdaddr); | ||
2747 | if (conn) { | ||
2748 | /* Defer clearing up the connection parameters | ||
2749 | * until closing to give a chance of keeping | ||
2750 | * them if a repairing happens. | ||
2751 | */ | ||
2752 | set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags); | ||
2753 | |||
2754 | /* If disconnection is not requested, then | ||
2755 | * clear the connection variable so that the | ||
2756 | * link is not terminated. | ||
2757 | */ | ||
2758 | if (!cp->disconnect) | ||
2759 | conn = NULL; | ||
2760 | } | ||
2761 | |||
2732 | if (cp->addr.type == BDADDR_LE_PUBLIC) | 2762 | if (cp->addr.type == BDADDR_LE_PUBLIC) |
2733 | addr_type = ADDR_LE_DEV_PUBLIC; | 2763 | addr_type = ADDR_LE_DEV_PUBLIC; |
2734 | else | 2764 | else |
@@ -2736,8 +2766,6 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
2736 | 2766 | ||
2737 | hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type); | 2767 | hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type); |
2738 | 2768 | ||
2739 | hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type); | ||
2740 | |||
2741 | err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type); | 2769 | err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type); |
2742 | } | 2770 | } |
2743 | 2771 | ||
@@ -2747,17 +2775,9 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, | |||
2747 | goto unlock; | 2775 | goto unlock; |
2748 | } | 2776 | } |
2749 | 2777 | ||
2750 | if (cp->disconnect) { | 2778 | /* If the connection variable is set, then termination of the |
2751 | if (cp->addr.type == BDADDR_BREDR) | 2779 | * link is requested. |
2752 | conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, | 2780 | */ |
2753 | &cp->addr.bdaddr); | ||
2754 | else | ||
2755 | conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, | ||
2756 | &cp->addr.bdaddr); | ||
2757 | } else { | ||
2758 | conn = NULL; | ||
2759 | } | ||
2760 | |||
2761 | if (!conn) { | 2781 | if (!conn) { |
2762 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0, | 2782 | err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0, |
2763 | &rp, sizeof(rp)); | 2783 | &rp, sizeof(rp)); |
@@ -3062,6 +3082,11 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) | |||
3062 | hci_conn_put(conn); | 3082 | hci_conn_put(conn); |
3063 | 3083 | ||
3064 | mgmt_pending_remove(cmd); | 3084 | mgmt_pending_remove(cmd); |
3085 | |||
3086 | /* The device is paired so there is no need to remove | ||
3087 | * its connection parameters anymore. | ||
3088 | */ | ||
3089 | clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags); | ||
3065 | } | 3090 | } |
3066 | 3091 | ||
3067 | void mgmt_smp_complete(struct hci_conn *conn, bool complete) | 3092 | void mgmt_smp_complete(struct hci_conn *conn, bool complete) |
@@ -6171,26 +6196,36 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, | |||
6171 | return eir_len; | 6196 | return eir_len; |
6172 | } | 6197 | } |
6173 | 6198 | ||
6174 | void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, | 6199 | void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn, |
6175 | u8 addr_type, u32 flags, u8 *name, u8 name_len, | 6200 | u32 flags, u8 *name, u8 name_len) |
6176 | u8 *dev_class) | ||
6177 | { | 6201 | { |
6178 | char buf[512]; | 6202 | char buf[512]; |
6179 | struct mgmt_ev_device_connected *ev = (void *) buf; | 6203 | struct mgmt_ev_device_connected *ev = (void *) buf; |
6180 | u16 eir_len = 0; | 6204 | u16 eir_len = 0; |
6181 | 6205 | ||
6182 | bacpy(&ev->addr.bdaddr, bdaddr); | 6206 | bacpy(&ev->addr.bdaddr, &conn->dst); |
6183 | ev->addr.type = link_to_bdaddr(link_type, addr_type); | 6207 | ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type); |
6184 | 6208 | ||
6185 | ev->flags = __cpu_to_le32(flags); | 6209 | ev->flags = __cpu_to_le32(flags); |
6186 | 6210 | ||
6187 | if (name_len > 0) | 6211 | /* We must ensure that the EIR Data fields are ordered and |
6188 | eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, | 6212 | * unique. Keep it simple for now and avoid the problem by not |
6189 | name, name_len); | 6213 | * adding any BR/EDR data to the LE adv. |
6214 | */ | ||
6215 | if (conn->le_adv_data_len > 0) { | ||
6216 | memcpy(&ev->eir[eir_len], | ||
6217 | conn->le_adv_data, conn->le_adv_data_len); | ||
6218 | eir_len = conn->le_adv_data_len; | ||
6219 | } else { | ||
6220 | if (name_len > 0) | ||
6221 | eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, | ||
6222 | name, name_len); | ||
6190 | 6223 | ||
6191 | if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0) | 6224 | if (memcmp(conn->dev_class, "\0\0\0", 3) != 0) |
6192 | eir_len = eir_append_data(ev->eir, eir_len, | 6225 | eir_len = eir_append_data(ev->eir, eir_len, |
6193 | EIR_CLASS_OF_DEV, dev_class, 3); | 6226 | EIR_CLASS_OF_DEV, |
6227 | conn->dev_class, 3); | ||
6228 | } | ||
6194 | 6229 | ||
6195 | ev->eir_len = cpu_to_le16(eir_len); | 6230 | ev->eir_len = cpu_to_le16(eir_len); |
6196 | 6231 | ||
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index af73bc3acb40..bce9c3d39324 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c | |||
@@ -78,8 +78,8 @@ static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s); | |||
78 | #define __get_type(b) ((b & 0xef)) | 78 | #define __get_type(b) ((b & 0xef)) |
79 | 79 | ||
80 | #define __test_ea(b) ((b & 0x01)) | 80 | #define __test_ea(b) ((b & 0x01)) |
81 | #define __test_cr(b) ((b & 0x02)) | 81 | #define __test_cr(b) (!!(b & 0x02)) |
82 | #define __test_pf(b) ((b & 0x10)) | 82 | #define __test_pf(b) (!!(b & 0x10)) |
83 | 83 | ||
84 | #define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01) | 84 | #define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01) |
85 | #define __ctrl(type, pf) (((type & 0xef) | (pf << 4))) | 85 | #define __ctrl(type, pf) (((type & 0xef) | (pf << 4))) |
@@ -904,7 +904,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type) | |||
904 | hdr->len = __len8(sizeof(*mcc) + 1); | 904 | hdr->len = __len8(sizeof(*mcc) + 1); |
905 | 905 | ||
906 | mcc = (void *) ptr; ptr += sizeof(*mcc); | 906 | mcc = (void *) ptr; ptr += sizeof(*mcc); |
907 | mcc->type = __mcc_type(cr, RFCOMM_NSC); | 907 | mcc->type = __mcc_type(0, RFCOMM_NSC); |
908 | mcc->len = __len8(1); | 908 | mcc->len = __len8(1); |
909 | 909 | ||
910 | /* Type that we didn't like */ | 910 | /* Type that we didn't like */ |
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f09b6b65cf6b..3ebf65b50881 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c | |||
@@ -191,16 +191,13 @@ int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa) | |||
191 | return 0; | 191 | return 0; |
192 | } | 192 | } |
193 | 193 | ||
194 | static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7], | 194 | static int smp_c1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r[16], |
195 | u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat, bdaddr_t *ra, | 195 | u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat, |
196 | u8 res[16]) | 196 | bdaddr_t *ra, u8 res[16]) |
197 | { | 197 | { |
198 | struct hci_dev *hdev = smp->conn->hcon->hdev; | ||
199 | u8 p1[16], p2[16]; | 198 | u8 p1[16], p2[16]; |
200 | int err; | 199 | int err; |
201 | 200 | ||
202 | BT_DBG("%s", hdev->name); | ||
203 | |||
204 | memset(p1, 0, 16); | 201 | memset(p1, 0, 16); |
205 | 202 | ||
206 | /* p1 = pres || preq || _rat || _iat */ | 203 | /* p1 = pres || preq || _rat || _iat */ |
@@ -218,7 +215,7 @@ static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7], | |||
218 | u128_xor((u128 *) res, (u128 *) r, (u128 *) p1); | 215 | u128_xor((u128 *) res, (u128 *) r, (u128 *) p1); |
219 | 216 | ||
220 | /* res = e(k, res) */ | 217 | /* res = e(k, res) */ |
221 | err = smp_e(smp->tfm_aes, k, res); | 218 | err = smp_e(tfm_aes, k, res); |
222 | if (err) { | 219 | if (err) { |
223 | BT_ERR("Encrypt data error"); | 220 | BT_ERR("Encrypt data error"); |
224 | return err; | 221 | return err; |
@@ -228,26 +225,23 @@ static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7], | |||
228 | u128_xor((u128 *) res, (u128 *) res, (u128 *) p2); | 225 | u128_xor((u128 *) res, (u128 *) res, (u128 *) p2); |
229 | 226 | ||
230 | /* res = e(k, res) */ | 227 | /* res = e(k, res) */ |
231 | err = smp_e(smp->tfm_aes, k, res); | 228 | err = smp_e(tfm_aes, k, res); |
232 | if (err) | 229 | if (err) |
233 | BT_ERR("Encrypt data error"); | 230 | BT_ERR("Encrypt data error"); |
234 | 231 | ||
235 | return err; | 232 | return err; |
236 | } | 233 | } |
237 | 234 | ||
238 | static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16], | 235 | static int smp_s1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r1[16], |
239 | u8 _r[16]) | 236 | u8 r2[16], u8 _r[16]) |
240 | { | 237 | { |
241 | struct hci_dev *hdev = smp->conn->hcon->hdev; | ||
242 | int err; | 238 | int err; |
243 | 239 | ||
244 | BT_DBG("%s", hdev->name); | ||
245 | |||
246 | /* Just least significant octets from r1 and r2 are considered */ | 240 | /* Just least significant octets from r1 and r2 are considered */ |
247 | memcpy(_r, r2, 8); | 241 | memcpy(_r, r2, 8); |
248 | memcpy(_r + 8, r1, 8); | 242 | memcpy(_r + 8, r1, 8); |
249 | 243 | ||
250 | err = smp_e(smp->tfm_aes, k, _r); | 244 | err = smp_e(tfm_aes, k, _r); |
251 | if (err) | 245 | if (err) |
252 | BT_ERR("Encrypt data error"); | 246 | BT_ERR("Encrypt data error"); |
253 | 247 | ||
@@ -547,7 +541,7 @@ static u8 smp_confirm(struct smp_chan *smp) | |||
547 | 541 | ||
548 | BT_DBG("conn %p", conn); | 542 | BT_DBG("conn %p", conn); |
549 | 543 | ||
550 | ret = smp_c1(smp, smp->tk, smp->prnd, smp->preq, smp->prsp, | 544 | ret = smp_c1(smp->tfm_aes, smp->tk, smp->prnd, smp->preq, smp->prsp, |
551 | conn->hcon->init_addr_type, &conn->hcon->init_addr, | 545 | conn->hcon->init_addr_type, &conn->hcon->init_addr, |
552 | conn->hcon->resp_addr_type, &conn->hcon->resp_addr, | 546 | conn->hcon->resp_addr_type, &conn->hcon->resp_addr, |
553 | cp.confirm_val); | 547 | cp.confirm_val); |
@@ -578,7 +572,7 @@ static u8 smp_random(struct smp_chan *smp) | |||
578 | 572 | ||
579 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); | 573 | BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave"); |
580 | 574 | ||
581 | ret = smp_c1(smp, smp->tk, smp->rrnd, smp->preq, smp->prsp, | 575 | ret = smp_c1(smp->tfm_aes, smp->tk, smp->rrnd, smp->preq, smp->prsp, |
582 | hcon->init_addr_type, &hcon->init_addr, | 576 | hcon->init_addr_type, &hcon->init_addr, |
583 | hcon->resp_addr_type, &hcon->resp_addr, confirm); | 577 | hcon->resp_addr_type, &hcon->resp_addr, confirm); |
584 | if (ret) | 578 | if (ret) |
@@ -594,7 +588,7 @@ static u8 smp_random(struct smp_chan *smp) | |||
594 | __le64 rand = 0; | 588 | __le64 rand = 0; |
595 | __le16 ediv = 0; | 589 | __le16 ediv = 0; |
596 | 590 | ||
597 | smp_s1(smp, smp->tk, smp->rrnd, smp->prnd, stk); | 591 | smp_s1(smp->tfm_aes, smp->tk, smp->rrnd, smp->prnd, stk); |
598 | 592 | ||
599 | memset(stk + smp->enc_key_size, 0, | 593 | memset(stk + smp->enc_key_size, 0, |
600 | SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); | 594 | SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); |
@@ -613,7 +607,7 @@ static u8 smp_random(struct smp_chan *smp) | |||
613 | smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), | 607 | smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), |
614 | smp->prnd); | 608 | smp->prnd); |
615 | 609 | ||
616 | smp_s1(smp, smp->tk, smp->prnd, smp->rrnd, stk); | 610 | smp_s1(smp->tfm_aes, smp->tk, smp->prnd, smp->rrnd, stk); |
617 | 611 | ||
618 | memset(stk + smp->enc_key_size, 0, | 612 | memset(stk + smp->enc_key_size, 0, |
619 | SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); | 613 | SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); |
@@ -970,7 +964,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) | |||
970 | if (sec_level > conn->hcon->pending_sec_level) | 964 | if (sec_level > conn->hcon->pending_sec_level) |
971 | conn->hcon->pending_sec_level = sec_level; | 965 | conn->hcon->pending_sec_level = sec_level; |
972 | 966 | ||
973 | /* If we need MITM check that it can be acheived */ | 967 | /* If we need MITM check that it can be achieved */ |
974 | if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) { | 968 | if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) { |
975 | u8 method; | 969 | u8 method; |
976 | 970 | ||
@@ -1028,7 +1022,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) | |||
1028 | 1022 | ||
1029 | auth = rsp->auth_req & AUTH_REQ_MASK; | 1023 | auth = rsp->auth_req & AUTH_REQ_MASK; |
1030 | 1024 | ||
1031 | /* If we need MITM check that it can be acheived */ | 1025 | /* If we need MITM check that it can be achieved */ |
1032 | if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) { | 1026 | if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) { |
1033 | u8 method; | 1027 | u8 method; |
1034 | 1028 | ||
diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c index 44136297b673..519a65452d90 100644 --- a/net/ieee802154/6lowpan_rtnl.c +++ b/net/ieee802154/6lowpan_rtnl.c | |||
@@ -49,8 +49,8 @@ | |||
49 | #include <linux/module.h> | 49 | #include <linux/module.h> |
50 | #include <linux/moduleparam.h> | 50 | #include <linux/moduleparam.h> |
51 | #include <linux/netdevice.h> | 51 | #include <linux/netdevice.h> |
52 | #include <linux/ieee802154.h> | ||
52 | #include <net/af_ieee802154.h> | 53 | #include <net/af_ieee802154.h> |
53 | #include <net/ieee802154.h> | ||
54 | #include <net/ieee802154_netdev.h> | 54 | #include <net/ieee802154_netdev.h> |
55 | #include <net/6lowpan.h> | 55 | #include <net/6lowpan.h> |
56 | #include <net/ipv6.h> | 56 | #include <net/ipv6.h> |
@@ -58,12 +58,13 @@ | |||
58 | #include "reassembly.h" | 58 | #include "reassembly.h" |
59 | 59 | ||
60 | static LIST_HEAD(lowpan_devices); | 60 | static LIST_HEAD(lowpan_devices); |
61 | static int lowpan_open_count; | ||
61 | 62 | ||
62 | /* private device info */ | 63 | /* private device info */ |
63 | struct lowpan_dev_info { | 64 | struct lowpan_dev_info { |
64 | struct net_device *real_dev; /* real WPAN device ptr */ | 65 | struct net_device *real_dev; /* real WPAN device ptr */ |
65 | struct mutex dev_list_mtx; /* mutex for list ops */ | 66 | struct mutex dev_list_mtx; /* mutex for list ops */ |
66 | __be16 fragment_tag; | 67 | u16 fragment_tag; |
67 | }; | 68 | }; |
68 | 69 | ||
69 | struct lowpan_dev_record { | 70 | struct lowpan_dev_record { |
@@ -140,24 +141,33 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb, | |||
140 | struct sk_buff *skb_cp; | 141 | struct sk_buff *skb_cp; |
141 | int stat = NET_RX_SUCCESS; | 142 | int stat = NET_RX_SUCCESS; |
142 | 143 | ||
144 | skb->protocol = htons(ETH_P_IPV6); | ||
145 | skb->pkt_type = PACKET_HOST; | ||
146 | |||
143 | rcu_read_lock(); | 147 | rcu_read_lock(); |
144 | list_for_each_entry_rcu(entry, &lowpan_devices, list) | 148 | list_for_each_entry_rcu(entry, &lowpan_devices, list) |
145 | if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) { | 149 | if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) { |
146 | skb_cp = skb_copy(skb, GFP_ATOMIC); | 150 | skb_cp = skb_copy(skb, GFP_ATOMIC); |
147 | if (!skb_cp) { | 151 | if (!skb_cp) { |
148 | stat = -ENOMEM; | 152 | kfree_skb(skb); |
149 | break; | 153 | rcu_read_unlock(); |
154 | return NET_RX_DROP; | ||
150 | } | 155 | } |
151 | 156 | ||
152 | skb_cp->dev = entry->ldev; | 157 | skb_cp->dev = entry->ldev; |
153 | stat = netif_rx(skb_cp); | 158 | stat = netif_rx(skb_cp); |
159 | if (stat == NET_RX_DROP) | ||
160 | break; | ||
154 | } | 161 | } |
155 | rcu_read_unlock(); | 162 | rcu_read_unlock(); |
156 | 163 | ||
164 | consume_skb(skb); | ||
165 | |||
157 | return stat; | 166 | return stat; |
158 | } | 167 | } |
159 | 168 | ||
160 | static int process_data(struct sk_buff *skb, const struct ieee802154_hdr *hdr) | 169 | static int |
170 | iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr) | ||
161 | { | 171 | { |
162 | u8 iphc0, iphc1; | 172 | u8 iphc0, iphc1; |
163 | struct ieee802154_addr_sa sa, da; | 173 | struct ieee802154_addr_sa sa, da; |
@@ -187,10 +197,9 @@ static int process_data(struct sk_buff *skb, const struct ieee802154_hdr *hdr) | |||
187 | else | 197 | else |
188 | dap = &da.hwaddr; | 198 | dap = &da.hwaddr; |
189 | 199 | ||
190 | return lowpan_process_data(skb, skb->dev, sap, sa.addr_type, | 200 | return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type, |
191 | IEEE802154_ADDR_LEN, dap, da.addr_type, | 201 | IEEE802154_ADDR_LEN, dap, da.addr_type, |
192 | IEEE802154_ADDR_LEN, iphc0, iphc1, | 202 | IEEE802154_ADDR_LEN, iphc0, iphc1); |
193 | lowpan_give_skb_to_devices); | ||
194 | 203 | ||
195 | drop: | 204 | drop: |
196 | kfree_skb(skb); | 205 | kfree_skb(skb); |
@@ -233,7 +242,7 @@ lowpan_alloc_frag(struct sk_buff *skb, int size, | |||
233 | &master_hdr->source, size); | 242 | &master_hdr->source, size); |
234 | if (rc < 0) { | 243 | if (rc < 0) { |
235 | kfree_skb(frag); | 244 | kfree_skb(frag); |
236 | return ERR_PTR(-rc); | 245 | return ERR_PTR(rc); |
237 | } | 246 | } |
238 | } else { | 247 | } else { |
239 | frag = ERR_PTR(-ENOMEM); | 248 | frag = ERR_PTR(-ENOMEM); |
@@ -275,7 +284,8 @@ lowpan_xmit_fragmented(struct sk_buff *skb, struct net_device *dev, | |||
275 | 284 | ||
276 | dgram_size = lowpan_uncompress_size(skb, &dgram_offset) - | 285 | dgram_size = lowpan_uncompress_size(skb, &dgram_offset) - |
277 | skb->mac_len; | 286 | skb->mac_len; |
278 | frag_tag = lowpan_dev_info(dev)->fragment_tag++; | 287 | frag_tag = htons(lowpan_dev_info(dev)->fragment_tag); |
288 | lowpan_dev_info(dev)->fragment_tag++; | ||
279 | 289 | ||
280 | frag_hdr[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x07); | 290 | frag_hdr[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x07); |
281 | frag_hdr[1] = dgram_size & 0xff; | 291 | frag_hdr[1] = dgram_size & 0xff; |
@@ -294,7 +304,7 @@ lowpan_xmit_fragmented(struct sk_buff *skb, struct net_device *dev, | |||
294 | frag_len + skb_network_header_len(skb)); | 304 | frag_len + skb_network_header_len(skb)); |
295 | if (rc) { | 305 | if (rc) { |
296 | pr_debug("%s unable to send FRAG1 packet (tag: %d)", | 306 | pr_debug("%s unable to send FRAG1 packet (tag: %d)", |
297 | __func__, frag_tag); | 307 | __func__, ntohs(frag_tag)); |
298 | goto err; | 308 | goto err; |
299 | } | 309 | } |
300 | 310 | ||
@@ -315,7 +325,7 @@ lowpan_xmit_fragmented(struct sk_buff *skb, struct net_device *dev, | |||
315 | frag_len); | 325 | frag_len); |
316 | if (rc) { | 326 | if (rc) { |
317 | pr_debug("%s unable to send a FRAGN packet. (tag: %d, offset: %d)\n", | 327 | pr_debug("%s unable to send a FRAGN packet. (tag: %d, offset: %d)\n", |
318 | __func__, frag_tag, skb_offset); | 328 | __func__, ntohs(frag_tag), skb_offset); |
319 | goto err; | 329 | goto err; |
320 | } | 330 | } |
321 | } while (skb_unprocessed > frag_cap); | 331 | } while (skb_unprocessed > frag_cap); |
@@ -515,6 +525,9 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, | |||
515 | if (!netif_running(dev)) | 525 | if (!netif_running(dev)) |
516 | goto drop_skb; | 526 | goto drop_skb; |
517 | 527 | ||
528 | if (skb->pkt_type == PACKET_OTHERHOST) | ||
529 | goto drop_skb; | ||
530 | |||
518 | if (dev->type != ARPHRD_IEEE802154) | 531 | if (dev->type != ARPHRD_IEEE802154) |
519 | goto drop_skb; | 532 | goto drop_skb; |
520 | 533 | ||
@@ -523,55 +536,67 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, | |||
523 | 536 | ||
524 | /* check that it's our buffer */ | 537 | /* check that it's our buffer */ |
525 | if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { | 538 | if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { |
526 | skb->protocol = htons(ETH_P_IPV6); | ||
527 | skb->pkt_type = PACKET_HOST; | ||
528 | |||
529 | /* Pull off the 1-byte of 6lowpan header. */ | 539 | /* Pull off the 1-byte of 6lowpan header. */ |
530 | skb_pull(skb, 1); | 540 | skb_pull(skb, 1); |
531 | 541 | return lowpan_give_skb_to_devices(skb, NULL); | |
532 | ret = lowpan_give_skb_to_devices(skb, NULL); | ||
533 | if (ret == NET_RX_DROP) | ||
534 | goto drop; | ||
535 | } else { | 542 | } else { |
536 | switch (skb->data[0] & 0xe0) { | 543 | switch (skb->data[0] & 0xe0) { |
537 | case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ | 544 | case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ |
538 | ret = process_data(skb, &hdr); | 545 | ret = iphc_decompress(skb, &hdr); |
539 | if (ret == NET_RX_DROP) | 546 | if (ret < 0) |
540 | goto drop; | 547 | goto drop; |
541 | break; | 548 | |
549 | return lowpan_give_skb_to_devices(skb, NULL); | ||
542 | case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ | 550 | case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ |
543 | ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1); | 551 | ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1); |
544 | if (ret == 1) { | 552 | if (ret == 1) { |
545 | ret = process_data(skb, &hdr); | 553 | ret = iphc_decompress(skb, &hdr); |
546 | if (ret == NET_RX_DROP) | 554 | if (ret < 0) |
547 | goto drop; | 555 | goto drop; |
556 | |||
557 | return lowpan_give_skb_to_devices(skb, NULL); | ||
558 | } else if (ret == -1) { | ||
559 | return NET_RX_DROP; | ||
560 | } else { | ||
561 | return NET_RX_SUCCESS; | ||
548 | } | 562 | } |
549 | break; | ||
550 | case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ | 563 | case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ |
551 | ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN); | 564 | ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN); |
552 | if (ret == 1) { | 565 | if (ret == 1) { |
553 | ret = process_data(skb, &hdr); | 566 | ret = iphc_decompress(skb, &hdr); |
554 | if (ret == NET_RX_DROP) | 567 | if (ret < 0) |
555 | goto drop; | 568 | goto drop; |
569 | |||
570 | return lowpan_give_skb_to_devices(skb, NULL); | ||
571 | } else if (ret == -1) { | ||
572 | return NET_RX_DROP; | ||
573 | } else { | ||
574 | return NET_RX_SUCCESS; | ||
556 | } | 575 | } |
557 | break; | ||
558 | default: | 576 | default: |
559 | break; | 577 | break; |
560 | } | 578 | } |
561 | } | 579 | } |
562 | 580 | ||
563 | return NET_RX_SUCCESS; | ||
564 | drop_skb: | 581 | drop_skb: |
565 | kfree_skb(skb); | 582 | kfree_skb(skb); |
566 | drop: | 583 | drop: |
567 | return NET_RX_DROP; | 584 | return NET_RX_DROP; |
568 | } | 585 | } |
569 | 586 | ||
587 | static struct packet_type lowpan_packet_type = { | ||
588 | .type = htons(ETH_P_IEEE802154), | ||
589 | .func = lowpan_rcv, | ||
590 | }; | ||
591 | |||
570 | static int lowpan_newlink(struct net *src_net, struct net_device *dev, | 592 | static int lowpan_newlink(struct net *src_net, struct net_device *dev, |
571 | struct nlattr *tb[], struct nlattr *data[]) | 593 | struct nlattr *tb[], struct nlattr *data[]) |
572 | { | 594 | { |
573 | struct net_device *real_dev; | 595 | struct net_device *real_dev; |
574 | struct lowpan_dev_record *entry; | 596 | struct lowpan_dev_record *entry; |
597 | int ret; | ||
598 | |||
599 | ASSERT_RTNL(); | ||
575 | 600 | ||
576 | pr_debug("adding new link\n"); | 601 | pr_debug("adding new link\n"); |
577 | 602 | ||
@@ -606,9 +631,14 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev, | |||
606 | list_add_tail(&entry->list, &lowpan_devices); | 631 | list_add_tail(&entry->list, &lowpan_devices); |
607 | mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx); | 632 | mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx); |
608 | 633 | ||
609 | register_netdevice(dev); | 634 | ret = register_netdevice(dev); |
635 | if (ret >= 0) { | ||
636 | if (!lowpan_open_count) | ||
637 | dev_add_pack(&lowpan_packet_type); | ||
638 | lowpan_open_count++; | ||
639 | } | ||
610 | 640 | ||
611 | return 0; | 641 | return ret; |
612 | } | 642 | } |
613 | 643 | ||
614 | static void lowpan_dellink(struct net_device *dev, struct list_head *head) | 644 | static void lowpan_dellink(struct net_device *dev, struct list_head *head) |
@@ -619,6 +649,10 @@ static void lowpan_dellink(struct net_device *dev, struct list_head *head) | |||
619 | 649 | ||
620 | ASSERT_RTNL(); | 650 | ASSERT_RTNL(); |
621 | 651 | ||
652 | lowpan_open_count--; | ||
653 | if (!lowpan_open_count) | ||
654 | dev_remove_pack(&lowpan_packet_type); | ||
655 | |||
622 | mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx); | 656 | mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx); |
623 | list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) { | 657 | list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) { |
624 | if (entry->ldev == dev) { | 658 | if (entry->ldev == dev) { |
@@ -681,11 +715,6 @@ static struct notifier_block lowpan_dev_notifier = { | |||
681 | .notifier_call = lowpan_device_event, | 715 | .notifier_call = lowpan_device_event, |
682 | }; | 716 | }; |
683 | 717 | ||
684 | static struct packet_type lowpan_packet_type = { | ||
685 | .type = htons(ETH_P_IEEE802154), | ||
686 | .func = lowpan_rcv, | ||
687 | }; | ||
688 | |||
689 | static int __init lowpan_init_module(void) | 718 | static int __init lowpan_init_module(void) |
690 | { | 719 | { |
691 | int err = 0; | 720 | int err = 0; |
@@ -698,8 +727,6 @@ static int __init lowpan_init_module(void) | |||
698 | if (err < 0) | 727 | if (err < 0) |
699 | goto out_frag; | 728 | goto out_frag; |
700 | 729 | ||
701 | dev_add_pack(&lowpan_packet_type); | ||
702 | |||
703 | err = register_netdevice_notifier(&lowpan_dev_notifier); | 730 | err = register_netdevice_notifier(&lowpan_dev_notifier); |
704 | if (err < 0) | 731 | if (err < 0) |
705 | goto out_pack; | 732 | goto out_pack; |
@@ -707,7 +734,6 @@ static int __init lowpan_init_module(void) | |||
707 | return 0; | 734 | return 0; |
708 | 735 | ||
709 | out_pack: | 736 | out_pack: |
710 | dev_remove_pack(&lowpan_packet_type); | ||
711 | lowpan_netlink_fini(); | 737 | lowpan_netlink_fini(); |
712 | out_frag: | 738 | out_frag: |
713 | lowpan_net_frag_exit(); | 739 | lowpan_net_frag_exit(); |
@@ -719,8 +745,6 @@ static void __exit lowpan_cleanup_module(void) | |||
719 | { | 745 | { |
720 | lowpan_netlink_fini(); | 746 | lowpan_netlink_fini(); |
721 | 747 | ||
722 | dev_remove_pack(&lowpan_packet_type); | ||
723 | |||
724 | lowpan_net_frag_exit(); | 748 | lowpan_net_frag_exit(); |
725 | 749 | ||
726 | unregister_netdevice_notifier(&lowpan_dev_notifier); | 750 | unregister_netdevice_notifier(&lowpan_dev_notifier); |
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index 3914b1ed4274..38354d4a70cb 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile | |||
@@ -2,8 +2,8 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o | |||
2 | obj-$(CONFIG_IEEE802154_6LOWPAN) += ieee802154_6lowpan.o | 2 | obj-$(CONFIG_IEEE802154_6LOWPAN) += ieee802154_6lowpan.o |
3 | 3 | ||
4 | ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o | 4 | ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o |
5 | ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \ | 5 | ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \ |
6 | header_ops.o | 6 | header_ops.o sysfs.o |
7 | af_802154-y := af_ieee802154.o raw.o dgram.o | 7 | af_802154-y := af_ieee802154.o raw.o dgram.o |
8 | 8 | ||
9 | ccflags-y += -D__CHECK_ENDIAN__ | 9 | ccflags-y += -D__CHECK_ENDIAN__ |
diff --git a/net/ieee802154/af802154.h b/net/ieee802154/af802154.h index 8330a09bfc95..343b63e6f953 100644 --- a/net/ieee802154/af802154.h +++ b/net/ieee802154/af802154.h | |||
@@ -12,10 +12,6 @@ | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * Written by: | 15 | * Written by: |
20 | * Sergey Lapin <slapin@ossfans.org> | 16 | * Sergey Lapin <slapin@ossfans.org> |
21 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 17 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c index 29e0de63001b..26da1e179737 100644 --- a/net/ieee802154/af_ieee802154.c +++ b/net/ieee802154/af_ieee802154.c | |||
@@ -12,10 +12,6 @@ | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * Written by: | 15 | * Written by: |
20 | * Sergey Lapin <slapin@ossfans.org> | 16 | * Sergey Lapin <slapin@ossfans.org> |
21 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> | 17 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> |
diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/core.c index 4955e0fe5883..620abc2ba5fc 100644 --- a/net/ieee802154/wpan-class.c +++ b/net/ieee802154/core.c | |||
@@ -10,10 +10,6 @@ | |||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | */ | 13 | */ |
18 | 14 | ||
19 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
@@ -21,75 +17,10 @@ | |||
21 | #include <linux/module.h> | 17 | #include <linux/module.h> |
22 | #include <linux/device.h> | 18 | #include <linux/device.h> |
23 | 19 | ||
24 | #include <net/wpan-phy.h> | 20 | #include <net/cfg802154.h> |
25 | 21 | ||
26 | #include "ieee802154.h" | 22 | #include "ieee802154.h" |
27 | 23 | #include "sysfs.h" | |
28 | #define MASTER_SHOW_COMPLEX(name, format_string, args...) \ | ||
29 | static ssize_t name ## _show(struct device *dev, \ | ||
30 | struct device_attribute *attr, char *buf) \ | ||
31 | { \ | ||
32 | struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); \ | ||
33 | int ret; \ | ||
34 | \ | ||
35 | mutex_lock(&phy->pib_lock); \ | ||
36 | ret = snprintf(buf, PAGE_SIZE, format_string "\n", args); \ | ||
37 | mutex_unlock(&phy->pib_lock); \ | ||
38 | return ret; \ | ||
39 | } \ | ||
40 | static DEVICE_ATTR_RO(name); | ||
41 | |||
42 | #define MASTER_SHOW(field, format_string) \ | ||
43 | MASTER_SHOW_COMPLEX(field, format_string, phy->field) | ||
44 | |||
45 | MASTER_SHOW(current_channel, "%d"); | ||
46 | MASTER_SHOW(current_page, "%d"); | ||
47 | MASTER_SHOW(transmit_power, "%d +- 1 dB"); | ||
48 | MASTER_SHOW(cca_mode, "%d"); | ||
49 | |||
50 | static ssize_t channels_supported_show(struct device *dev, | ||
51 | struct device_attribute *attr, | ||
52 | char *buf) | ||
53 | { | ||
54 | struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); | ||
55 | int ret; | ||
56 | int i, len = 0; | ||
57 | |||
58 | mutex_lock(&phy->pib_lock); | ||
59 | for (i = 0; i < 32; i++) { | ||
60 | ret = snprintf(buf + len, PAGE_SIZE - len, | ||
61 | "%#09x\n", phy->channels_supported[i]); | ||
62 | if (ret < 0) | ||
63 | break; | ||
64 | len += ret; | ||
65 | } | ||
66 | mutex_unlock(&phy->pib_lock); | ||
67 | return len; | ||
68 | } | ||
69 | static DEVICE_ATTR_RO(channels_supported); | ||
70 | |||
71 | static struct attribute *pmib_attrs[] = { | ||
72 | &dev_attr_current_channel.attr, | ||
73 | &dev_attr_current_page.attr, | ||
74 | &dev_attr_channels_supported.attr, | ||
75 | &dev_attr_transmit_power.attr, | ||
76 | &dev_attr_cca_mode.attr, | ||
77 | NULL, | ||
78 | }; | ||
79 | ATTRIBUTE_GROUPS(pmib); | ||
80 | |||
81 | static void wpan_phy_release(struct device *d) | ||
82 | { | ||
83 | struct wpan_phy *phy = container_of(d, struct wpan_phy, dev); | ||
84 | |||
85 | kfree(phy); | ||
86 | } | ||
87 | |||
88 | static struct class wpan_phy_class = { | ||
89 | .name = "ieee802154", | ||
90 | .dev_release = wpan_phy_release, | ||
91 | .dev_groups = pmib_groups, | ||
92 | }; | ||
93 | 24 | ||
94 | static DEFINE_MUTEX(wpan_phy_mutex); | 25 | static DEFINE_MUTEX(wpan_phy_mutex); |
95 | static int wpan_phy_idx; | 26 | static int wpan_phy_idx; |
@@ -201,7 +132,7 @@ static int __init wpan_phy_class_init(void) | |||
201 | { | 132 | { |
202 | int rc; | 133 | int rc; |
203 | 134 | ||
204 | rc = class_register(&wpan_phy_class); | 135 | rc = wpan_phy_sysfs_init(); |
205 | if (rc) | 136 | if (rc) |
206 | goto err; | 137 | goto err; |
207 | 138 | ||
@@ -211,7 +142,7 @@ static int __init wpan_phy_class_init(void) | |||
211 | 142 | ||
212 | return 0; | 143 | return 0; |
213 | err_nl: | 144 | err_nl: |
214 | class_unregister(&wpan_phy_class); | 145 | wpan_phy_sysfs_exit(); |
215 | err: | 146 | err: |
216 | return rc; | 147 | return rc; |
217 | } | 148 | } |
@@ -220,7 +151,7 @@ subsys_initcall(wpan_phy_class_init); | |||
220 | static void __exit wpan_phy_class_exit(void) | 151 | static void __exit wpan_phy_class_exit(void) |
221 | { | 152 | { |
222 | ieee802154_nl_exit(); | 153 | ieee802154_nl_exit(); |
223 | class_unregister(&wpan_phy_class); | 154 | wpan_phy_sysfs_exit(); |
224 | } | 155 | } |
225 | module_exit(wpan_phy_class_exit); | 156 | module_exit(wpan_phy_class_exit); |
226 | 157 | ||
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index fc9193eabd41..b8555ec71387 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c | |||
@@ -12,10 +12,6 @@ | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * Written by: | 15 | * Written by: |
20 | * Sergey Lapin <slapin@ossfans.org> | 16 | * Sergey Lapin <slapin@ossfans.org> |
21 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 17 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
@@ -27,9 +23,9 @@ | |||
27 | #include <linux/if_arp.h> | 23 | #include <linux/if_arp.h> |
28 | #include <linux/list.h> | 24 | #include <linux/list.h> |
29 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/ieee802154.h> | ||
30 | #include <net/sock.h> | 27 | #include <net/sock.h> |
31 | #include <net/af_ieee802154.h> | 28 | #include <net/af_ieee802154.h> |
32 | #include <net/ieee802154.h> | ||
33 | #include <net/ieee802154_netdev.h> | 29 | #include <net/ieee802154_netdev.h> |
34 | 30 | ||
35 | #include <asm/ioctls.h> | 31 | #include <asm/ioctls.h> |
diff --git a/net/ieee802154/header_ops.c b/net/ieee802154/header_ops.c index c09294e39ca6..a051b6993177 100644 --- a/net/ieee802154/header_ops.c +++ b/net/ieee802154/header_ops.c | |||
@@ -14,8 +14,9 @@ | |||
14 | * Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de> | 14 | * Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de> |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/ieee802154.h> | ||
18 | |||
17 | #include <net/mac802154.h> | 19 | #include <net/mac802154.h> |
18 | #include <net/ieee802154.h> | ||
19 | #include <net/ieee802154_netdev.h> | 20 | #include <net/ieee802154_netdev.h> |
20 | 21 | ||
21 | static int | 22 | static int |
diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h index 5d352f86979e..42ae63a345ab 100644 --- a/net/ieee802154/ieee802154.h +++ b/net/ieee802154/ieee802154.h | |||
@@ -10,10 +10,6 @@ | |||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | */ | 13 | */ |
18 | #ifndef IEEE_802154_LOCAL_H | 14 | #ifndef IEEE_802154_LOCAL_H |
19 | #define IEEE_802154_LOCAL_H | 15 | #define IEEE_802154_LOCAL_H |
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c index 9222966f5e6d..6c3c2595a201 100644 --- a/net/ieee802154/netlink.c +++ b/net/ieee802154/netlink.c | |||
@@ -12,10 +12,6 @@ | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * Written by: | 15 | * Written by: |
20 | * Sergey Lapin <slapin@ossfans.org> | 16 | * Sergey Lapin <slapin@ossfans.org> |
21 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 17 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c index c6bfe22bfa5e..abd0f31bdc66 100644 --- a/net/ieee802154/nl-mac.c +++ b/net/ieee802154/nl-mac.c | |||
@@ -12,10 +12,6 @@ | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * Written by: | 15 | * Written by: |
20 | * Sergey Lapin <slapin@ossfans.org> | 16 | * Sergey Lapin <slapin@ossfans.org> |
21 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 17 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
@@ -26,6 +22,7 @@ | |||
26 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
27 | #include <linux/if_arp.h> | 23 | #include <linux/if_arp.h> |
28 | #include <linux/netdevice.h> | 24 | #include <linux/netdevice.h> |
25 | #include <linux/ieee802154.h> | ||
29 | #include <net/netlink.h> | 26 | #include <net/netlink.h> |
30 | #include <net/genetlink.h> | 27 | #include <net/genetlink.h> |
31 | #include <net/sock.h> | 28 | #include <net/sock.h> |
@@ -33,9 +30,8 @@ | |||
33 | #include <linux/export.h> | 30 | #include <linux/export.h> |
34 | #include <net/af_ieee802154.h> | 31 | #include <net/af_ieee802154.h> |
35 | #include <net/nl802154.h> | 32 | #include <net/nl802154.h> |
36 | #include <net/ieee802154.h> | ||
37 | #include <net/ieee802154_netdev.h> | 33 | #include <net/ieee802154_netdev.h> |
38 | #include <net/wpan-phy.h> | 34 | #include <net/cfg802154.h> |
39 | 35 | ||
40 | #include "ieee802154.h" | 36 | #include "ieee802154.h" |
41 | 37 | ||
@@ -668,20 +664,6 @@ int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info) | |||
668 | 664 | ||
669 | phy = ops->get_phy(dev); | 665 | phy = ops->get_phy(dev); |
670 | 666 | ||
671 | if ((!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) || | ||
672 | (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]) || | ||
673 | (!phy->set_cca_ed_level && | ||
674 | info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) || | ||
675 | (!phy->set_csma_params && | ||
676 | (info->attrs[IEEE802154_ATTR_CSMA_RETRIES] || | ||
677 | info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] || | ||
678 | info->attrs[IEEE802154_ATTR_CSMA_MAX_BE])) || | ||
679 | (!phy->set_frame_retries && | ||
680 | info->attrs[IEEE802154_ATTR_FRAME_RETRIES])) { | ||
681 | rc = -EOPNOTSUPP; | ||
682 | goto out_phy; | ||
683 | } | ||
684 | |||
685 | ops->get_mac_params(dev, ¶ms); | 667 | ops->get_mac_params(dev, ¶ms); |
686 | 668 | ||
687 | if (info->attrs[IEEE802154_ATTR_TXPOWER]) | 669 | if (info->attrs[IEEE802154_ATTR_TXPOWER]) |
@@ -712,10 +694,9 @@ int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info) | |||
712 | 694 | ||
713 | wpan_phy_put(phy); | 695 | wpan_phy_put(phy); |
714 | dev_put(dev); | 696 | dev_put(dev); |
715 | return rc; | ||
716 | 697 | ||
717 | out_phy: | 698 | return 0; |
718 | wpan_phy_put(phy); | 699 | |
719 | out: | 700 | out: |
720 | dev_put(dev); | 701 | dev_put(dev); |
721 | return rc; | 702 | return rc; |
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 972baf83411a..0afe760ff512 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c | |||
@@ -12,10 +12,6 @@ | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * Written by: | 15 | * Written by: |
20 | * Sergey Lapin <slapin@ossfans.org> | 16 | * Sergey Lapin <slapin@ossfans.org> |
21 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 17 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
@@ -27,7 +23,7 @@ | |||
27 | #include <linux/if_arp.h> | 23 | #include <linux/if_arp.h> |
28 | #include <net/netlink.h> | 24 | #include <net/netlink.h> |
29 | #include <net/genetlink.h> | 25 | #include <net/genetlink.h> |
30 | #include <net/wpan-phy.h> | 26 | #include <net/cfg802154.h> |
31 | #include <net/af_ieee802154.h> | 27 | #include <net/af_ieee802154.h> |
32 | #include <net/ieee802154_netdev.h> | 28 | #include <net/ieee802154_netdev.h> |
33 | #include <net/rtnetlink.h> /* for rtnl_{un,}lock */ | 29 | #include <net/rtnetlink.h> /* for rtnl_{un,}lock */ |
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c index 3a703ab88348..35c432668454 100644 --- a/net/ieee802154/nl_policy.c +++ b/net/ieee802154/nl_policy.c | |||
@@ -12,10 +12,6 @@ | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | */ | 15 | */ |
20 | 16 | ||
21 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index 73a4d53463de..21c38945ab8b 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c | |||
@@ -12,10 +12,6 @@ | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * Written by: | 15 | * Written by: |
20 | * Sergey Lapin <slapin@ossfans.org> | 16 | * Sergey Lapin <slapin@ossfans.org> |
21 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 17 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c index 7cfcd6885225..9d980ed3ffe2 100644 --- a/net/ieee802154/reassembly.c +++ b/net/ieee802154/reassembly.c | |||
@@ -33,7 +33,7 @@ | |||
33 | static const char lowpan_frags_cache_name[] = "lowpan-frags"; | 33 | static const char lowpan_frags_cache_name[] = "lowpan-frags"; |
34 | 34 | ||
35 | struct lowpan_frag_info { | 35 | struct lowpan_frag_info { |
36 | __be16 d_tag; | 36 | u16 d_tag; |
37 | u16 d_size; | 37 | u16 d_size; |
38 | u8 d_offset; | 38 | u8 d_offset; |
39 | }; | 39 | }; |
@@ -48,7 +48,7 @@ static struct inet_frags lowpan_frags; | |||
48 | static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, | 48 | static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, |
49 | struct sk_buff *prev, struct net_device *dev); | 49 | struct sk_buff *prev, struct net_device *dev); |
50 | 50 | ||
51 | static unsigned int lowpan_hash_frag(__be16 tag, u16 d_size, | 51 | static unsigned int lowpan_hash_frag(u16 tag, u16 d_size, |
52 | const struct ieee802154_addr *saddr, | 52 | const struct ieee802154_addr *saddr, |
53 | const struct ieee802154_addr *daddr) | 53 | const struct ieee802154_addr *daddr) |
54 | { | 54 | { |
@@ -330,11 +330,13 @@ static int lowpan_get_frag_info(struct sk_buff *skb, const u8 frag_type, | |||
330 | { | 330 | { |
331 | bool fail; | 331 | bool fail; |
332 | u8 pattern = 0, low = 0; | 332 | u8 pattern = 0, low = 0; |
333 | __be16 d_tag = 0; | ||
333 | 334 | ||
334 | fail = lowpan_fetch_skb(skb, &pattern, 1); | 335 | fail = lowpan_fetch_skb(skb, &pattern, 1); |
335 | fail |= lowpan_fetch_skb(skb, &low, 1); | 336 | fail |= lowpan_fetch_skb(skb, &low, 1); |
336 | frag_info->d_size = (pattern & 7) << 8 | low; | 337 | frag_info->d_size = (pattern & 7) << 8 | low; |
337 | fail |= lowpan_fetch_skb(skb, &frag_info->d_tag, 2); | 338 | fail |= lowpan_fetch_skb(skb, &d_tag, 2); |
339 | frag_info->d_tag = ntohs(d_tag); | ||
338 | 340 | ||
339 | if (frag_type == LOWPAN_DISPATCH_FRAGN) { | 341 | if (frag_type == LOWPAN_DISPATCH_FRAGN) { |
340 | fail |= lowpan_fetch_skb(skb, &frag_info->d_offset, 1); | 342 | fail |= lowpan_fetch_skb(skb, &frag_info->d_offset, 1); |
diff --git a/net/ieee802154/reassembly.h b/net/ieee802154/reassembly.h index 74e4a7c98191..836b16fa001f 100644 --- a/net/ieee802154/reassembly.h +++ b/net/ieee802154/reassembly.h | |||
@@ -4,7 +4,7 @@ | |||
4 | #include <net/inet_frag.h> | 4 | #include <net/inet_frag.h> |
5 | 5 | ||
6 | struct lowpan_create_arg { | 6 | struct lowpan_create_arg { |
7 | __be16 tag; | 7 | u16 tag; |
8 | u16 d_size; | 8 | u16 d_size; |
9 | const struct ieee802154_addr *src; | 9 | const struct ieee802154_addr *src; |
10 | const struct ieee802154_addr *dst; | 10 | const struct ieee802154_addr *dst; |
@@ -15,7 +15,7 @@ struct lowpan_create_arg { | |||
15 | struct lowpan_frag_queue { | 15 | struct lowpan_frag_queue { |
16 | struct inet_frag_queue q; | 16 | struct inet_frag_queue q; |
17 | 17 | ||
18 | __be16 tag; | 18 | u16 tag; |
19 | u16 d_size; | 19 | u16 d_size; |
20 | struct ieee802154_addr saddr; | 20 | struct ieee802154_addr saddr; |
21 | struct ieee802154_addr daddr; | 21 | struct ieee802154_addr daddr; |
diff --git a/net/ieee802154/sysfs.c b/net/ieee802154/sysfs.c new file mode 100644 index 000000000000..eb9ca6f99122 --- /dev/null +++ b/net/ieee802154/sysfs.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* This program is free software; you can redistribute it and/or modify | ||
2 | * it under the terms of the GNU General Public License version 2 | ||
3 | * as published by the Free Software Foundation. | ||
4 | * | ||
5 | * This program is distributed in the hope that it will be useful, | ||
6 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
7 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
8 | * GNU General Public License for more details. | ||
9 | * | ||
10 | * Authors: | ||
11 | * Alexander Aring <aar@pengutronix.de> | ||
12 | * | ||
13 | * Based on: net/wireless/sysfs.c | ||
14 | */ | ||
15 | |||
16 | #include <linux/device.h> | ||
17 | |||
18 | #include <net/cfg802154.h> | ||
19 | |||
20 | #define MASTER_SHOW_COMPLEX(name, format_string, args...) \ | ||
21 | static ssize_t name ## _show(struct device *dev, \ | ||
22 | struct device_attribute *attr, char *buf) \ | ||
23 | { \ | ||
24 | struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); \ | ||
25 | int ret; \ | ||
26 | \ | ||
27 | mutex_lock(&phy->pib_lock); \ | ||
28 | ret = snprintf(buf, PAGE_SIZE, format_string "\n", args); \ | ||
29 | mutex_unlock(&phy->pib_lock); \ | ||
30 | return ret; \ | ||
31 | } \ | ||
32 | static DEVICE_ATTR_RO(name) | ||
33 | |||
34 | #define MASTER_SHOW(field, format_string) \ | ||
35 | MASTER_SHOW_COMPLEX(field, format_string, phy->field) | ||
36 | |||
37 | MASTER_SHOW(current_channel, "%d"); | ||
38 | MASTER_SHOW(current_page, "%d"); | ||
39 | MASTER_SHOW(transmit_power, "%d +- 1 dB"); | ||
40 | MASTER_SHOW(cca_mode, "%d"); | ||
41 | |||
42 | static ssize_t channels_supported_show(struct device *dev, | ||
43 | struct device_attribute *attr, | ||
44 | char *buf) | ||
45 | { | ||
46 | struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); | ||
47 | int ret; | ||
48 | int i, len = 0; | ||
49 | |||
50 | mutex_lock(&phy->pib_lock); | ||
51 | for (i = 0; i < 32; i++) { | ||
52 | ret = snprintf(buf + len, PAGE_SIZE - len, | ||
53 | "%#09x\n", phy->channels_supported[i]); | ||
54 | if (ret < 0) | ||
55 | break; | ||
56 | len += ret; | ||
57 | } | ||
58 | mutex_unlock(&phy->pib_lock); | ||
59 | return len; | ||
60 | } | ||
61 | static DEVICE_ATTR_RO(channels_supported); | ||
62 | |||
63 | static void wpan_phy_release(struct device *d) | ||
64 | { | ||
65 | struct wpan_phy *phy = container_of(d, struct wpan_phy, dev); | ||
66 | |||
67 | kfree(phy); | ||
68 | } | ||
69 | |||
70 | static struct attribute *pmib_attrs[] = { | ||
71 | &dev_attr_current_channel.attr, | ||
72 | &dev_attr_current_page.attr, | ||
73 | &dev_attr_channels_supported.attr, | ||
74 | &dev_attr_transmit_power.attr, | ||
75 | &dev_attr_cca_mode.attr, | ||
76 | NULL, | ||
77 | }; | ||
78 | ATTRIBUTE_GROUPS(pmib); | ||
79 | |||
80 | struct class wpan_phy_class = { | ||
81 | .name = "ieee802154", | ||
82 | .dev_release = wpan_phy_release, | ||
83 | .dev_groups = pmib_groups, | ||
84 | }; | ||
85 | |||
86 | int wpan_phy_sysfs_init(void) | ||
87 | { | ||
88 | return class_register(&wpan_phy_class); | ||
89 | } | ||
90 | |||
91 | void wpan_phy_sysfs_exit(void) | ||
92 | { | ||
93 | class_unregister(&wpan_phy_class); | ||
94 | } | ||
diff --git a/net/ieee802154/sysfs.h b/net/ieee802154/sysfs.h new file mode 100644 index 000000000000..aa42e39ecbec --- /dev/null +++ b/net/ieee802154/sysfs.h | |||
@@ -0,0 +1,9 @@ | |||
1 | #ifndef __IEEE802154_SYSFS_H | ||
2 | #define __IEEE802154_SYSFS_H | ||
3 | |||
4 | int wpan_phy_sysfs_init(void); | ||
5 | void wpan_phy_sysfs_exit(void); | ||
6 | |||
7 | extern struct class wpan_phy_class; | ||
8 | |||
9 | #endif /* __IEEE802154_SYSFS_H */ | ||
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index aeb6a483b3bc..75cc6801a431 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -33,6 +33,13 @@ config MAC80211_RC_MINSTREL_HT | |||
33 | ---help--- | 33 | ---help--- |
34 | This option enables the 'minstrel_ht' TX rate control algorithm | 34 | This option enables the 'minstrel_ht' TX rate control algorithm |
35 | 35 | ||
36 | config MAC80211_RC_MINSTREL_VHT | ||
37 | bool "Minstrel 802.11ac support" if EXPERT | ||
38 | depends on MAC80211_RC_MINSTREL_HT | ||
39 | default n | ||
40 | ---help--- | ||
41 | This option enables VHT in the 'minstrel_ht' TX rate control algorithm | ||
42 | |||
36 | choice | 43 | choice |
37 | prompt "Default rate control algorithm" | 44 | prompt "Default rate control algorithm" |
38 | depends on MAC80211_HAS_RC | 45 | depends on MAC80211_HAS_RC |
@@ -169,6 +176,17 @@ config MAC80211_HT_DEBUG | |||
169 | 176 | ||
170 | Do not select this option. | 177 | Do not select this option. |
171 | 178 | ||
179 | config MAC80211_OCB_DEBUG | ||
180 | bool "Verbose OCB debugging" | ||
181 | depends on MAC80211_DEBUG_MENU | ||
182 | ---help--- | ||
183 | Selecting this option causes mac80211 to print out | ||
184 | very verbose OCB debugging messages. It should not | ||
185 | be selected on production systems as those messages | ||
186 | are remotely triggerable. | ||
187 | |||
188 | Do not select this option. | ||
189 | |||
172 | config MAC80211_IBSS_DEBUG | 190 | config MAC80211_IBSS_DEBUG |
173 | bool "Verbose IBSS debugging" | 191 | bool "Verbose IBSS debugging" |
174 | depends on MAC80211_DEBUG_MENU | 192 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 7273d2796dd1..e53671b1105e 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -27,7 +27,8 @@ mac80211-y := \ | |||
27 | event.o \ | 27 | event.o \ |
28 | chan.o \ | 28 | chan.o \ |
29 | trace.o mlme.o \ | 29 | trace.o mlme.o \ |
30 | tdls.o | 30 | tdls.o \ |
31 | ocb.o | ||
31 | 32 | ||
32 | mac80211-$(CONFIG_MAC80211_LEDS) += led.o | 33 | mac80211-$(CONFIG_MAC80211_LEDS) += led.o |
33 | mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ | 34 | mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index d6986f3aa5c4..9242c60048cf 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -149,11 +149,6 @@ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, | |||
149 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | 149 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); |
150 | } | 150 | } |
151 | 151 | ||
152 | static inline int ieee80211_ac_from_tid(int tid) | ||
153 | { | ||
154 | return ieee802_1d_to_ac[tid & 7]; | ||
155 | } | ||
156 | |||
157 | /* | 152 | /* |
158 | * When multiple aggregation sessions on multiple stations | 153 | * When multiple aggregation sessions on multiple stations |
159 | * are being created/destroyed simultaneously, we need to | 154 | * are being created/destroyed simultaneously, we need to |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 343da1e35025..06185940cbb6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "cfg.h" | 20 | #include "cfg.h" |
21 | #include "rate.h" | 21 | #include "rate.h" |
22 | #include "mesh.h" | 22 | #include "mesh.h" |
23 | #include "wme.h" | ||
23 | 24 | ||
24 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, | 25 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, |
25 | const char *name, | 26 | const char *name, |
@@ -190,7 +191,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
190 | * receive the key. When wpa_supplicant has roamed | 191 | * receive the key. When wpa_supplicant has roamed |
191 | * using FT, it attempts to set the key before | 192 | * using FT, it attempts to set the key before |
192 | * association has completed, this rejects that attempt | 193 | * association has completed, this rejects that attempt |
193 | * so it will set the key again after assocation. | 194 | * so it will set the key again after association. |
194 | * | 195 | * |
195 | * TODO: accept the key if we have a station entry and | 196 | * TODO: accept the key if we have a station entry and |
196 | * add it to the device after the station. | 197 | * add it to the device after the station. |
@@ -229,6 +230,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
229 | case NUM_NL80211_IFTYPES: | 230 | case NUM_NL80211_IFTYPES: |
230 | case NL80211_IFTYPE_P2P_CLIENT: | 231 | case NL80211_IFTYPE_P2P_CLIENT: |
231 | case NL80211_IFTYPE_P2P_GO: | 232 | case NL80211_IFTYPE_P2P_GO: |
233 | case NL80211_IFTYPE_OCB: | ||
232 | /* shouldn't happen */ | 234 | /* shouldn't happen */ |
233 | WARN_ON_ONCE(1); | 235 | WARN_ON_ONCE(1); |
234 | break; | 236 | break; |
@@ -1225,14 +1227,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
1225 | } | 1227 | } |
1226 | 1228 | ||
1227 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | 1229 | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, |
1228 | const u8 *mac) | 1230 | struct station_del_parameters *params) |
1229 | { | 1231 | { |
1230 | struct ieee80211_sub_if_data *sdata; | 1232 | struct ieee80211_sub_if_data *sdata; |
1231 | 1233 | ||
1232 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1234 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1233 | 1235 | ||
1234 | if (mac) | 1236 | if (params->mac) |
1235 | return sta_info_destroy_addr_bss(sdata, mac); | 1237 | return sta_info_destroy_addr_bss(sdata, params->mac); |
1236 | 1238 | ||
1237 | sta_info_flush(sdata); | 1239 | sta_info_flush(sdata); |
1238 | return 0; | 1240 | return 0; |
@@ -1516,6 +1518,57 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
1516 | return 0; | 1518 | return 0; |
1517 | } | 1519 | } |
1518 | 1520 | ||
1521 | static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp, | ||
1522 | struct mpath_info *pinfo) | ||
1523 | { | ||
1524 | memset(pinfo, 0, sizeof(*pinfo)); | ||
1525 | memcpy(mpp, mpath->mpp, ETH_ALEN); | ||
1526 | |||
1527 | pinfo->generation = mpp_paths_generation; | ||
1528 | } | ||
1529 | |||
1530 | static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev, | ||
1531 | u8 *dst, u8 *mpp, struct mpath_info *pinfo) | ||
1532 | |||
1533 | { | ||
1534 | struct ieee80211_sub_if_data *sdata; | ||
1535 | struct mesh_path *mpath; | ||
1536 | |||
1537 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1538 | |||
1539 | rcu_read_lock(); | ||
1540 | mpath = mpp_path_lookup(sdata, dst); | ||
1541 | if (!mpath) { | ||
1542 | rcu_read_unlock(); | ||
1543 | return -ENOENT; | ||
1544 | } | ||
1545 | memcpy(dst, mpath->dst, ETH_ALEN); | ||
1546 | mpp_set_pinfo(mpath, mpp, pinfo); | ||
1547 | rcu_read_unlock(); | ||
1548 | return 0; | ||
1549 | } | ||
1550 | |||
1551 | static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev, | ||
1552 | int idx, u8 *dst, u8 *mpp, | ||
1553 | struct mpath_info *pinfo) | ||
1554 | { | ||
1555 | struct ieee80211_sub_if_data *sdata; | ||
1556 | struct mesh_path *mpath; | ||
1557 | |||
1558 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1559 | |||
1560 | rcu_read_lock(); | ||
1561 | mpath = mpp_path_lookup_by_idx(sdata, idx); | ||
1562 | if (!mpath) { | ||
1563 | rcu_read_unlock(); | ||
1564 | return -ENOENT; | ||
1565 | } | ||
1566 | memcpy(dst, mpath->dst, ETH_ALEN); | ||
1567 | mpp_set_pinfo(mpath, mpp, pinfo); | ||
1568 | rcu_read_unlock(); | ||
1569 | return 0; | ||
1570 | } | ||
1571 | |||
1519 | static int ieee80211_get_mesh_config(struct wiphy *wiphy, | 1572 | static int ieee80211_get_mesh_config(struct wiphy *wiphy, |
1520 | struct net_device *dev, | 1573 | struct net_device *dev, |
1521 | struct mesh_config *conf) | 1574 | struct mesh_config *conf) |
@@ -1966,6 +2019,17 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | |||
1966 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); | 2019 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); |
1967 | } | 2020 | } |
1968 | 2021 | ||
2022 | static int ieee80211_join_ocb(struct wiphy *wiphy, struct net_device *dev, | ||
2023 | struct ocb_setup *setup) | ||
2024 | { | ||
2025 | return ieee80211_ocb_join(IEEE80211_DEV_TO_SUB_IF(dev), setup); | ||
2026 | } | ||
2027 | |||
2028 | static int ieee80211_leave_ocb(struct wiphy *wiphy, struct net_device *dev) | ||
2029 | { | ||
2030 | return ieee80211_ocb_leave(IEEE80211_DEV_TO_SUB_IF(dev)); | ||
2031 | } | ||
2032 | |||
1969 | static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, | 2033 | static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, |
1970 | int rate[IEEE80211_NUM_BANDS]) | 2034 | int rate[IEEE80211_NUM_BANDS]) |
1971 | { | 2035 | { |
@@ -2081,6 +2145,9 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, | |||
2081 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2145 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2082 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 2146 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
2083 | 2147 | ||
2148 | if (local->ops->get_txpower) | ||
2149 | return drv_get_txpower(local, sdata, dbm); | ||
2150 | |||
2084 | if (!local->use_chanctx) | 2151 | if (!local->use_chanctx) |
2085 | *dbm = local->hw.conf.power_level; | 2152 | *dbm = local->hw.conf.power_level; |
2086 | else | 2153 | else |
@@ -2850,11 +2917,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
2850 | if (sdata->reserved_ready) | 2917 | if (sdata->reserved_ready) |
2851 | return 0; | 2918 | return 0; |
2852 | 2919 | ||
2853 | err = ieee80211_vif_use_reserved_context(sdata); | 2920 | return ieee80211_vif_use_reserved_context(sdata); |
2854 | if (err) | ||
2855 | return err; | ||
2856 | |||
2857 | return 0; | ||
2858 | } | 2921 | } |
2859 | 2922 | ||
2860 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, | 2923 | if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef, |
@@ -2868,7 +2931,6 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
2868 | return err; | 2931 | return err; |
2869 | 2932 | ||
2870 | ieee80211_bss_info_change_notify(sdata, changed); | 2933 | ieee80211_bss_info_change_notify(sdata, changed); |
2871 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); | ||
2872 | 2934 | ||
2873 | if (sdata->csa_block_tx) { | 2935 | if (sdata->csa_block_tx) { |
2874 | ieee80211_wake_vif_queues(local, sdata, | 2936 | ieee80211_wake_vif_queues(local, sdata, |
@@ -2876,6 +2938,12 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) | |||
2876 | sdata->csa_block_tx = false; | 2938 | sdata->csa_block_tx = false; |
2877 | } | 2939 | } |
2878 | 2940 | ||
2941 | err = drv_post_channel_switch(sdata); | ||
2942 | if (err) | ||
2943 | return err; | ||
2944 | |||
2945 | cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); | ||
2946 | |||
2879 | return 0; | 2947 | return 0; |
2880 | } | 2948 | } |
2881 | 2949 | ||
@@ -3053,9 +3121,11 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3053 | { | 3121 | { |
3054 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 3122 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
3055 | struct ieee80211_local *local = sdata->local; | 3123 | struct ieee80211_local *local = sdata->local; |
3124 | struct ieee80211_channel_switch ch_switch; | ||
3056 | struct ieee80211_chanctx_conf *conf; | 3125 | struct ieee80211_chanctx_conf *conf; |
3057 | struct ieee80211_chanctx *chanctx; | 3126 | struct ieee80211_chanctx *chanctx; |
3058 | int err, changed = 0; | 3127 | u32 changed = 0; |
3128 | int err; | ||
3059 | 3129 | ||
3060 | sdata_assert_lock(sdata); | 3130 | sdata_assert_lock(sdata); |
3061 | lockdep_assert_held(&local->mtx); | 3131 | lockdep_assert_held(&local->mtx); |
@@ -3088,6 +3158,10 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3088 | goto out; | 3158 | goto out; |
3089 | } | 3159 | } |
3090 | 3160 | ||
3161 | err = drv_pre_channel_switch(sdata, &ch_switch); | ||
3162 | if (err) | ||
3163 | goto out; | ||
3164 | |||
3091 | err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, | 3165 | err = ieee80211_vif_reserve_chanctx(sdata, ¶ms->chandef, |
3092 | chanctx->mode, | 3166 | chanctx->mode, |
3093 | params->radar_required); | 3167 | params->radar_required); |
@@ -3101,6 +3175,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, | |||
3101 | goto out; | 3175 | goto out; |
3102 | } | 3176 | } |
3103 | 3177 | ||
3178 | ch_switch.timestamp = 0; | ||
3179 | ch_switch.device_timestamp = 0; | ||
3180 | ch_switch.block_tx = params->block_tx; | ||
3181 | ch_switch.chandef = params->chandef; | ||
3182 | ch_switch.count = params->count; | ||
3183 | |||
3104 | err = ieee80211_set_csa_beacon(sdata, params, &changed); | 3184 | err = ieee80211_set_csa_beacon(sdata, params, &changed); |
3105 | if (err) { | 3185 | if (err) { |
3106 | ieee80211_vif_unreserve_chanctx(sdata); | 3186 | ieee80211_vif_unreserve_chanctx(sdata); |
@@ -3521,6 +3601,76 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy, | |||
3521 | return ret; | 3601 | return ret; |
3522 | } | 3602 | } |
3523 | 3603 | ||
3604 | static int ieee80211_add_tx_ts(struct wiphy *wiphy, struct net_device *dev, | ||
3605 | u8 tsid, const u8 *peer, u8 up, | ||
3606 | u16 admitted_time) | ||
3607 | { | ||
3608 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3609 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3610 | int ac = ieee802_1d_to_ac[up]; | ||
3611 | |||
3612 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
3613 | return -EOPNOTSUPP; | ||
3614 | |||
3615 | if (!(sdata->wmm_acm & BIT(up))) | ||
3616 | return -EINVAL; | ||
3617 | |||
3618 | if (ifmgd->tx_tspec[ac].admitted_time) | ||
3619 | return -EBUSY; | ||
3620 | |||
3621 | if (admitted_time) { | ||
3622 | ifmgd->tx_tspec[ac].admitted_time = 32 * admitted_time; | ||
3623 | ifmgd->tx_tspec[ac].tsid = tsid; | ||
3624 | ifmgd->tx_tspec[ac].up = up; | ||
3625 | } | ||
3626 | |||
3627 | return 0; | ||
3628 | } | ||
3629 | |||
3630 | static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev, | ||
3631 | u8 tsid, const u8 *peer) | ||
3632 | { | ||
3633 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
3634 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3635 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
3636 | int ac; | ||
3637 | |||
3638 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
3639 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
3640 | |||
3641 | /* skip unused entries */ | ||
3642 | if (!tx_tspec->admitted_time) | ||
3643 | continue; | ||
3644 | |||
3645 | if (tx_tspec->tsid != tsid) | ||
3646 | continue; | ||
3647 | |||
3648 | /* due to this new packets will be reassigned to non-ACM ACs */ | ||
3649 | tx_tspec->up = -1; | ||
3650 | |||
3651 | /* Make sure that all packets have been sent to avoid to | ||
3652 | * restore the QoS params on packets that are still on the | ||
3653 | * queues. | ||
3654 | */ | ||
3655 | synchronize_net(); | ||
3656 | ieee80211_flush_queues(local, sdata); | ||
3657 | |||
3658 | /* restore the normal QoS parameters | ||
3659 | * (unconditionally to avoid races) | ||
3660 | */ | ||
3661 | tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
3662 | tx_tspec->downgraded = false; | ||
3663 | ieee80211_sta_handle_tspec_ac_params(sdata); | ||
3664 | |||
3665 | /* finally clear all the data */ | ||
3666 | memset(tx_tspec, 0, sizeof(*tx_tspec)); | ||
3667 | |||
3668 | return 0; | ||
3669 | } | ||
3670 | |||
3671 | return -ENOENT; | ||
3672 | } | ||
3673 | |||
3524 | const struct cfg80211_ops mac80211_config_ops = { | 3674 | const struct cfg80211_ops mac80211_config_ops = { |
3525 | .add_virtual_intf = ieee80211_add_iface, | 3675 | .add_virtual_intf = ieee80211_add_iface, |
3526 | .del_virtual_intf = ieee80211_del_iface, | 3676 | .del_virtual_intf = ieee80211_del_iface, |
@@ -3547,11 +3697,15 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3547 | .change_mpath = ieee80211_change_mpath, | 3697 | .change_mpath = ieee80211_change_mpath, |
3548 | .get_mpath = ieee80211_get_mpath, | 3698 | .get_mpath = ieee80211_get_mpath, |
3549 | .dump_mpath = ieee80211_dump_mpath, | 3699 | .dump_mpath = ieee80211_dump_mpath, |
3700 | .get_mpp = ieee80211_get_mpp, | ||
3701 | .dump_mpp = ieee80211_dump_mpp, | ||
3550 | .update_mesh_config = ieee80211_update_mesh_config, | 3702 | .update_mesh_config = ieee80211_update_mesh_config, |
3551 | .get_mesh_config = ieee80211_get_mesh_config, | 3703 | .get_mesh_config = ieee80211_get_mesh_config, |
3552 | .join_mesh = ieee80211_join_mesh, | 3704 | .join_mesh = ieee80211_join_mesh, |
3553 | .leave_mesh = ieee80211_leave_mesh, | 3705 | .leave_mesh = ieee80211_leave_mesh, |
3554 | #endif | 3706 | #endif |
3707 | .join_ocb = ieee80211_join_ocb, | ||
3708 | .leave_ocb = ieee80211_leave_ocb, | ||
3555 | .change_bss = ieee80211_change_bss, | 3709 | .change_bss = ieee80211_change_bss, |
3556 | .set_txq_params = ieee80211_set_txq_params, | 3710 | .set_txq_params = ieee80211_set_txq_params, |
3557 | .set_monitor_channel = ieee80211_set_monitor_channel, | 3711 | .set_monitor_channel = ieee80211_set_monitor_channel, |
@@ -3597,4 +3751,6 @@ const struct cfg80211_ops mac80211_config_ops = { | |||
3597 | .channel_switch = ieee80211_channel_switch, | 3751 | .channel_switch = ieee80211_channel_switch, |
3598 | .set_qos_map = ieee80211_set_qos_map, | 3752 | .set_qos_map = ieee80211_set_qos_map, |
3599 | .set_ap_chanwidth = ieee80211_set_ap_chanwidth, | 3753 | .set_ap_chanwidth = ieee80211_set_ap_chanwidth, |
3754 | .add_tx_ts = ieee80211_add_tx_ts, | ||
3755 | .del_tx_ts = ieee80211_del_tx_ts, | ||
3600 | }; | 3756 | }; |
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 4c74e8da64b9..c7c514220298 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -270,6 +270,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, | |||
270 | case NL80211_IFTYPE_ADHOC: | 270 | case NL80211_IFTYPE_ADHOC: |
271 | case NL80211_IFTYPE_WDS: | 271 | case NL80211_IFTYPE_WDS: |
272 | case NL80211_IFTYPE_MESH_POINT: | 272 | case NL80211_IFTYPE_MESH_POINT: |
273 | case NL80211_IFTYPE_OCB: | ||
273 | width = vif->bss_conf.chandef.width; | 274 | width = vif->bss_conf.chandef.width; |
274 | break; | 275 | break; |
275 | case NL80211_IFTYPE_UNSPECIFIED: | 276 | case NL80211_IFTYPE_UNSPECIFIED: |
@@ -674,6 +675,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | |||
674 | case NL80211_IFTYPE_ADHOC: | 675 | case NL80211_IFTYPE_ADHOC: |
675 | case NL80211_IFTYPE_WDS: | 676 | case NL80211_IFTYPE_WDS: |
676 | case NL80211_IFTYPE_MESH_POINT: | 677 | case NL80211_IFTYPE_MESH_POINT: |
678 | case NL80211_IFTYPE_OCB: | ||
677 | break; | 679 | break; |
678 | default: | 680 | default: |
679 | WARN_ON_ONCE(1); | 681 | WARN_ON_ONCE(1); |
@@ -909,6 +911,7 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata) | |||
909 | case NL80211_IFTYPE_ADHOC: | 911 | case NL80211_IFTYPE_ADHOC: |
910 | case NL80211_IFTYPE_AP: | 912 | case NL80211_IFTYPE_AP: |
911 | case NL80211_IFTYPE_MESH_POINT: | 913 | case NL80211_IFTYPE_MESH_POINT: |
914 | case NL80211_IFTYPE_OCB: | ||
912 | ieee80211_queue_work(&sdata->local->hw, | 915 | ieee80211_queue_work(&sdata->local->hw, |
913 | &sdata->csa_finalize_work); | 916 | &sdata->csa_finalize_work); |
914 | break; | 917 | break; |
@@ -1634,7 +1637,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata, | |||
1634 | } | 1637 | } |
1635 | break; | 1638 | break; |
1636 | case IEEE80211_CHANCTX_WILL_BE_REPLACED: | 1639 | case IEEE80211_CHANCTX_WILL_BE_REPLACED: |
1637 | /* TODO: Perhaps the bandwith change could be treated as a | 1640 | /* TODO: Perhaps the bandwidth change could be treated as a |
1638 | * reservation itself? */ | 1641 | * reservation itself? */ |
1639 | ret = -EBUSY; | 1642 | ret = -EBUSY; |
1640 | goto out; | 1643 | goto out; |
diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h index 493d68061f0c..1956b3115dd5 100644 --- a/net/mac80211/debug.h +++ b/net/mac80211/debug.h | |||
@@ -2,6 +2,12 @@ | |||
2 | #define __MAC80211_DEBUG_H | 2 | #define __MAC80211_DEBUG_H |
3 | #include <net/cfg80211.h> | 3 | #include <net/cfg80211.h> |
4 | 4 | ||
5 | #ifdef CONFIG_MAC80211_OCB_DEBUG | ||
6 | #define MAC80211_OCB_DEBUG 1 | ||
7 | #else | ||
8 | #define MAC80211_OCB_DEBUG 0 | ||
9 | #endif | ||
10 | |||
5 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 11 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
6 | #define MAC80211_IBSS_DEBUG 1 | 12 | #define MAC80211_IBSS_DEBUG 1 |
7 | #else | 13 | #else |
@@ -131,6 +137,10 @@ do { \ | |||
131 | _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \ | 137 | _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \ |
132 | sdata, fmt, ##__VA_ARGS__) | 138 | sdata, fmt, ##__VA_ARGS__) |
133 | 139 | ||
140 | #define ocb_dbg(sdata, fmt, ...) \ | ||
141 | _sdata_dbg(MAC80211_OCB_DEBUG, \ | ||
142 | sdata, fmt, ##__VA_ARGS__) | ||
143 | |||
134 | #define ibss_dbg(sdata, fmt, ...) \ | 144 | #define ibss_dbg(sdata, fmt, ...) \ |
135 | _sdata_dbg(MAC80211_IBSS_DEBUG, \ | 145 | _sdata_dbg(MAC80211_IBSS_DEBUG, \ |
136 | sdata, fmt, ##__VA_ARGS__) | 146 | sdata, fmt, ##__VA_ARGS__) |
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 1521cabad3d6..5523b94c7c90 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -300,10 +300,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
300 | 300 | ||
301 | lockdep_assert_held(&sdata->local->key_mtx); | 301 | lockdep_assert_held(&sdata->local->key_mtx); |
302 | 302 | ||
303 | if (sdata->debugfs.default_unicast_key) { | 303 | debugfs_remove(sdata->debugfs.default_unicast_key); |
304 | debugfs_remove(sdata->debugfs.default_unicast_key); | 304 | sdata->debugfs.default_unicast_key = NULL; |
305 | sdata->debugfs.default_unicast_key = NULL; | ||
306 | } | ||
307 | 305 | ||
308 | if (sdata->default_unicast_key) { | 306 | if (sdata->default_unicast_key) { |
309 | key = key_mtx_dereference(sdata->local, | 307 | key = key_mtx_dereference(sdata->local, |
@@ -314,10 +312,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) | |||
314 | sdata->vif.debugfs_dir, buf); | 312 | sdata->vif.debugfs_dir, buf); |
315 | } | 313 | } |
316 | 314 | ||
317 | if (sdata->debugfs.default_multicast_key) { | 315 | debugfs_remove(sdata->debugfs.default_multicast_key); |
318 | debugfs_remove(sdata->debugfs.default_multicast_key); | 316 | sdata->debugfs.default_multicast_key = NULL; |
319 | sdata->debugfs.default_multicast_key = NULL; | ||
320 | } | ||
321 | 317 | ||
322 | if (sdata->default_multicast_key) { | 318 | if (sdata->default_multicast_key) { |
323 | key = key_mtx_dereference(sdata->local, | 319 | key = key_mtx_dereference(sdata->local, |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 196d48c68134..9759dd1f0734 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -214,7 +214,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | |||
214 | BSS_CHANGED_BEACON_ENABLED) && | 214 | BSS_CHANGED_BEACON_ENABLED) && |
215 | sdata->vif.type != NL80211_IFTYPE_AP && | 215 | sdata->vif.type != NL80211_IFTYPE_AP && |
216 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 216 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
217 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) | 217 | sdata->vif.type != NL80211_IFTYPE_MESH_POINT && |
218 | sdata->vif.type != NL80211_IFTYPE_OCB)) | ||
218 | return; | 219 | return; |
219 | 220 | ||
220 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || | 221 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || |
@@ -631,6 +632,12 @@ static inline int drv_conf_tx(struct ieee80211_local *local, | |||
631 | if (!check_sdata_in_driver(sdata)) | 632 | if (!check_sdata_in_driver(sdata)) |
632 | return -EIO; | 633 | return -EIO; |
633 | 634 | ||
635 | if (WARN_ONCE(params->cw_min == 0 || | ||
636 | params->cw_min > params->cw_max, | ||
637 | "%s: invalid CW_min/CW_max: %d/%d\n", | ||
638 | sdata->name, params->cw_min, params->cw_max)) | ||
639 | return -EINVAL; | ||
640 | |||
634 | trace_drv_conf_tx(local, sdata, ac, params); | 641 | trace_drv_conf_tx(local, sdata, ac, params); |
635 | if (local->ops->conf_tx) | 642 | if (local->ops->conf_tx) |
636 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, | 643 | ret = local->ops->conf_tx(&local->hw, &sdata->vif, |
@@ -764,12 +771,13 @@ static inline void drv_flush(struct ieee80211_local *local, | |||
764 | } | 771 | } |
765 | 772 | ||
766 | static inline void drv_channel_switch(struct ieee80211_local *local, | 773 | static inline void drv_channel_switch(struct ieee80211_local *local, |
767 | struct ieee80211_channel_switch *ch_switch) | 774 | struct ieee80211_sub_if_data *sdata, |
775 | struct ieee80211_channel_switch *ch_switch) | ||
768 | { | 776 | { |
769 | might_sleep(); | 777 | might_sleep(); |
770 | 778 | ||
771 | trace_drv_channel_switch(local, ch_switch); | 779 | trace_drv_channel_switch(local, sdata, ch_switch); |
772 | local->ops->channel_switch(&local->hw, ch_switch); | 780 | local->ops->channel_switch(&local->hw, &sdata->vif, ch_switch); |
773 | trace_drv_return_void(local); | 781 | trace_drv_return_void(local); |
774 | } | 782 | } |
775 | 783 | ||
@@ -1144,13 +1152,15 @@ static inline void drv_stop_ap(struct ieee80211_local *local, | |||
1144 | trace_drv_return_void(local); | 1152 | trace_drv_return_void(local); |
1145 | } | 1153 | } |
1146 | 1154 | ||
1147 | static inline void drv_restart_complete(struct ieee80211_local *local) | 1155 | static inline void |
1156 | drv_reconfig_complete(struct ieee80211_local *local, | ||
1157 | enum ieee80211_reconfig_type reconfig_type) | ||
1148 | { | 1158 | { |
1149 | might_sleep(); | 1159 | might_sleep(); |
1150 | 1160 | ||
1151 | trace_drv_restart_complete(local); | 1161 | trace_drv_reconfig_complete(local, reconfig_type); |
1152 | if (local->ops->restart_complete) | 1162 | if (local->ops->reconfig_complete) |
1153 | local->ops->restart_complete(&local->hw); | 1163 | local->ops->reconfig_complete(&local->hw, reconfig_type); |
1154 | trace_drv_return_void(local); | 1164 | trace_drv_return_void(local); |
1155 | } | 1165 | } |
1156 | 1166 | ||
@@ -1196,6 +1206,40 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata, | |||
1196 | } | 1206 | } |
1197 | } | 1207 | } |
1198 | 1208 | ||
1209 | static inline int | ||
1210 | drv_pre_channel_switch(struct ieee80211_sub_if_data *sdata, | ||
1211 | struct ieee80211_channel_switch *ch_switch) | ||
1212 | { | ||
1213 | struct ieee80211_local *local = sdata->local; | ||
1214 | int ret = 0; | ||
1215 | |||
1216 | if (!check_sdata_in_driver(sdata)) | ||
1217 | return -EIO; | ||
1218 | |||
1219 | trace_drv_pre_channel_switch(local, sdata, ch_switch); | ||
1220 | if (local->ops->pre_channel_switch) | ||
1221 | ret = local->ops->pre_channel_switch(&local->hw, &sdata->vif, | ||
1222 | ch_switch); | ||
1223 | trace_drv_return_int(local, ret); | ||
1224 | return ret; | ||
1225 | } | ||
1226 | |||
1227 | static inline int | ||
1228 | drv_post_channel_switch(struct ieee80211_sub_if_data *sdata) | ||
1229 | { | ||
1230 | struct ieee80211_local *local = sdata->local; | ||
1231 | int ret = 0; | ||
1232 | |||
1233 | if (!check_sdata_in_driver(sdata)) | ||
1234 | return -EIO; | ||
1235 | |||
1236 | trace_drv_post_channel_switch(local, sdata); | ||
1237 | if (local->ops->post_channel_switch) | ||
1238 | ret = local->ops->post_channel_switch(&local->hw, &sdata->vif); | ||
1239 | trace_drv_return_int(local, ret); | ||
1240 | return ret; | ||
1241 | } | ||
1242 | |||
1199 | static inline int drv_join_ibss(struct ieee80211_local *local, | 1243 | static inline int drv_join_ibss(struct ieee80211_local *local, |
1200 | struct ieee80211_sub_if_data *sdata) | 1244 | struct ieee80211_sub_if_data *sdata) |
1201 | { | 1245 | { |
@@ -1238,4 +1282,18 @@ static inline u32 drv_get_expected_throughput(struct ieee80211_local *local, | |||
1238 | return ret; | 1282 | return ret; |
1239 | } | 1283 | } |
1240 | 1284 | ||
1285 | static inline int drv_get_txpower(struct ieee80211_local *local, | ||
1286 | struct ieee80211_sub_if_data *sdata, int *dbm) | ||
1287 | { | ||
1288 | int ret; | ||
1289 | |||
1290 | if (!local->ops->get_txpower) | ||
1291 | return -EOPNOTSUPP; | ||
1292 | |||
1293 | ret = local->ops->get_txpower(&local->hw, &sdata->vif, dbm); | ||
1294 | trace_drv_get_txpower(local, sdata, *dbm, ret); | ||
1295 | |||
1296 | return ret; | ||
1297 | } | ||
1298 | |||
1241 | #endif /* __MAC80211_DRIVER_OPS */ | 1299 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c2aaec4dfcf0..a51c993ece73 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -131,7 +131,7 @@ enum ieee80211_bss_corrupt_data_flags { | |||
131 | * | 131 | * |
132 | * These are bss flags that are attached to a bss in the | 132 | * These are bss flags that are attached to a bss in the |
133 | * @valid_data field of &struct ieee80211_bss. They show which parts | 133 | * @valid_data field of &struct ieee80211_bss. They show which parts |
134 | * of the data structure were recieved as a result of an un-corrupted | 134 | * of the data structure were received as a result of an un-corrupted |
135 | * beacon/probe response. | 135 | * beacon/probe response. |
136 | */ | 136 | */ |
137 | enum ieee80211_bss_valid_data_flags { | 137 | enum ieee80211_bss_valid_data_flags { |
@@ -399,6 +399,24 @@ struct ieee80211_mgd_assoc_data { | |||
399 | u8 ie[]; | 399 | u8 ie[]; |
400 | }; | 400 | }; |
401 | 401 | ||
402 | struct ieee80211_sta_tx_tspec { | ||
403 | /* timestamp of the first packet in the time slice */ | ||
404 | unsigned long time_slice_start; | ||
405 | |||
406 | u32 admitted_time; /* in usecs, unlike over the air */ | ||
407 | u8 tsid; | ||
408 | s8 up; /* signed to be able to invalidate with -1 during teardown */ | ||
409 | |||
410 | /* consumed TX time in microseconds in the time slice */ | ||
411 | u32 consumed_tx_time; | ||
412 | enum { | ||
413 | TX_TSPEC_ACTION_NONE = 0, | ||
414 | TX_TSPEC_ACTION_DOWNGRADE, | ||
415 | TX_TSPEC_ACTION_STOP_DOWNGRADE, | ||
416 | } action; | ||
417 | bool downgraded; | ||
418 | }; | ||
419 | |||
402 | struct ieee80211_if_managed { | 420 | struct ieee80211_if_managed { |
403 | struct timer_list timer; | 421 | struct timer_list timer; |
404 | struct timer_list conn_mon_timer; | 422 | struct timer_list conn_mon_timer; |
@@ -434,6 +452,8 @@ struct ieee80211_if_managed { | |||
434 | 452 | ||
435 | unsigned int flags; | 453 | unsigned int flags; |
436 | 454 | ||
455 | bool csa_waiting_bcn; | ||
456 | |||
437 | bool beacon_crc_valid; | 457 | bool beacon_crc_valid; |
438 | u32 beacon_crc; | 458 | u32 beacon_crc; |
439 | 459 | ||
@@ -507,6 +527,16 @@ struct ieee80211_if_managed { | |||
507 | 527 | ||
508 | u8 tdls_peer[ETH_ALEN] __aligned(2); | 528 | u8 tdls_peer[ETH_ALEN] __aligned(2); |
509 | struct delayed_work tdls_peer_del_work; | 529 | struct delayed_work tdls_peer_del_work; |
530 | |||
531 | /* WMM-AC TSPEC support */ | ||
532 | struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS]; | ||
533 | /* Use a separate work struct so that we can do something here | ||
534 | * while the sdata->work is flushing the queues, for example. | ||
535 | * otherwise, in scenarios where we hardly get any traffic out | ||
536 | * on the BE queue, but there's a lot of VO traffic, we might | ||
537 | * get stuck in a downgraded situation and flush takes forever. | ||
538 | */ | ||
539 | struct delayed_work tx_tspec_wk; | ||
510 | }; | 540 | }; |
511 | 541 | ||
512 | struct ieee80211_if_ibss { | 542 | struct ieee80211_if_ibss { |
@@ -547,6 +577,25 @@ struct ieee80211_if_ibss { | |||
547 | }; | 577 | }; |
548 | 578 | ||
549 | /** | 579 | /** |
580 | * struct ieee80211_if_ocb - OCB mode state | ||
581 | * | ||
582 | * @housekeeping_timer: timer for periodic invocation of a housekeeping task | ||
583 | * @wrkq_flags: OCB deferred task action | ||
584 | * @incomplete_lock: delayed STA insertion lock | ||
585 | * @incomplete_stations: list of STAs waiting for delayed insertion | ||
586 | * @joined: indication if the interface is connected to an OCB network | ||
587 | */ | ||
588 | struct ieee80211_if_ocb { | ||
589 | struct timer_list housekeeping_timer; | ||
590 | unsigned long wrkq_flags; | ||
591 | |||
592 | spinlock_t incomplete_lock; | ||
593 | struct list_head incomplete_stations; | ||
594 | |||
595 | bool joined; | ||
596 | }; | ||
597 | |||
598 | /** | ||
550 | * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface | 599 | * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface |
551 | * | 600 | * |
552 | * these declarations define the interface, which enables | 601 | * these declarations define the interface, which enables |
@@ -839,6 +888,7 @@ struct ieee80211_sub_if_data { | |||
839 | struct ieee80211_if_managed mgd; | 888 | struct ieee80211_if_managed mgd; |
840 | struct ieee80211_if_ibss ibss; | 889 | struct ieee80211_if_ibss ibss; |
841 | struct ieee80211_if_mesh mesh; | 890 | struct ieee80211_if_mesh mesh; |
891 | struct ieee80211_if_ocb ocb; | ||
842 | u32 mntr_flags; | 892 | u32 mntr_flags; |
843 | } u; | 893 | } u; |
844 | 894 | ||
@@ -1307,6 +1357,9 @@ struct ieee80211_local { | |||
1307 | /* virtual monitor interface */ | 1357 | /* virtual monitor interface */ |
1308 | struct ieee80211_sub_if_data __rcu *monitor_sdata; | 1358 | struct ieee80211_sub_if_data __rcu *monitor_sdata; |
1309 | struct cfg80211_chan_def monitor_chandef; | 1359 | struct cfg80211_chan_def monitor_chandef; |
1360 | |||
1361 | /* extended capabilities provided by mac80211 */ | ||
1362 | u8 ext_capa[8]; | ||
1310 | }; | 1363 | }; |
1311 | 1364 | ||
1312 | static inline struct ieee80211_sub_if_data * | 1365 | static inline struct ieee80211_sub_if_data * |
@@ -1454,6 +1507,7 @@ void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, | |||
1454 | __le16 fc, bool acked); | 1507 | __le16 fc, bool acked); |
1455 | void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata); | 1508 | void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata); |
1456 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | 1509 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); |
1510 | void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata); | ||
1457 | 1511 | ||
1458 | /* IBSS code */ | 1512 | /* IBSS code */ |
1459 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | 1513 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); |
@@ -1471,6 +1525,15 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, | |||
1471 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); | 1525 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); |
1472 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); | 1526 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); |
1473 | 1527 | ||
1528 | /* OCB code */ | ||
1529 | void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata); | ||
1530 | void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, | ||
1531 | const u8 *bssid, const u8 *addr, u32 supp_rates); | ||
1532 | void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata); | ||
1533 | int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, | ||
1534 | struct ocb_setup *setup); | ||
1535 | int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata); | ||
1536 | |||
1474 | /* mesh code */ | 1537 | /* mesh code */ |
1475 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); | 1538 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); |
1476 | void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1539 | void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
@@ -1758,6 +1821,13 @@ static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames) | |||
1758 | return true; | 1821 | return true; |
1759 | } | 1822 | } |
1760 | 1823 | ||
1824 | extern const int ieee802_1d_to_ac[8]; | ||
1825 | |||
1826 | static inline int ieee80211_ac_from_tid(int tid) | ||
1827 | { | ||
1828 | return ieee802_1d_to_ac[tid & 7]; | ||
1829 | } | ||
1830 | |||
1761 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); | 1831 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); |
1762 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); | 1832 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); |
1763 | void ieee80211_dynamic_ps_timer(unsigned long data); | 1833 | void ieee80211_dynamic_ps_timer(unsigned long data); |
@@ -1767,7 +1837,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, | |||
1767 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 1837 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
1768 | struct ieee80211_hdr *hdr); | 1838 | struct ieee80211_hdr *hdr); |
1769 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | 1839 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, |
1770 | struct ieee80211_hdr *hdr, bool ack); | 1840 | struct ieee80211_hdr *hdr, bool ack, u16 tx_time); |
1771 | 1841 | ||
1772 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1842 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
1773 | unsigned long queues, | 1843 | unsigned long queues, |
@@ -1833,8 +1903,10 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata, | |||
1833 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); | 1903 | void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); |
1834 | void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); | 1904 | void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); |
1835 | 1905 | ||
1836 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | 1906 | size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, |
1837 | const u8 *ids, int n_ids, size_t offset); | 1907 | const u8 *ids, int n_ids, |
1908 | const u8 *after_ric, int n_after_ric, | ||
1909 | size_t offset); | ||
1838 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); | 1910 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); |
1839 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 1911 | u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
1840 | u16 cap); | 1912 | u16 cap); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index af237223a8cd..6b631c049eba 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -259,6 +259,15 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, | |||
259 | list_for_each_entry(nsdata, &local->interfaces, list) { | 259 | list_for_each_entry(nsdata, &local->interfaces, list) { |
260 | if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { | 260 | if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { |
261 | /* | 261 | /* |
262 | * Only OCB and monitor mode may coexist | ||
263 | */ | ||
264 | if ((sdata->vif.type == NL80211_IFTYPE_OCB && | ||
265 | nsdata->vif.type != NL80211_IFTYPE_MONITOR) || | ||
266 | (sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||
267 | nsdata->vif.type == NL80211_IFTYPE_OCB)) | ||
268 | return -EBUSY; | ||
269 | |||
270 | /* | ||
262 | * Allow only a single IBSS interface to be up at any | 271 | * Allow only a single IBSS interface to be up at any |
263 | * time. This is restricted because beacon distribution | 272 | * time. This is restricted because beacon distribution |
264 | * cannot work properly if both are in the same IBSS. | 273 | * cannot work properly if both are in the same IBSS. |
@@ -521,6 +530,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
521 | case NL80211_IFTYPE_MONITOR: | 530 | case NL80211_IFTYPE_MONITOR: |
522 | case NL80211_IFTYPE_ADHOC: | 531 | case NL80211_IFTYPE_ADHOC: |
523 | case NL80211_IFTYPE_P2P_DEVICE: | 532 | case NL80211_IFTYPE_P2P_DEVICE: |
533 | case NL80211_IFTYPE_OCB: | ||
524 | /* no special treatment */ | 534 | /* no special treatment */ |
525 | break; | 535 | break; |
526 | case NL80211_IFTYPE_UNSPECIFIED: | 536 | case NL80211_IFTYPE_UNSPECIFIED: |
@@ -631,6 +641,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
631 | case NL80211_IFTYPE_ADHOC: | 641 | case NL80211_IFTYPE_ADHOC: |
632 | case NL80211_IFTYPE_AP: | 642 | case NL80211_IFTYPE_AP: |
633 | case NL80211_IFTYPE_MESH_POINT: | 643 | case NL80211_IFTYPE_MESH_POINT: |
644 | case NL80211_IFTYPE_OCB: | ||
634 | netif_carrier_off(dev); | 645 | netif_carrier_off(dev); |
635 | break; | 646 | break; |
636 | case NL80211_IFTYPE_WDS: | 647 | case NL80211_IFTYPE_WDS: |
@@ -842,6 +853,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
842 | sdata_lock(sdata); | 853 | sdata_lock(sdata); |
843 | mutex_lock(&local->mtx); | 854 | mutex_lock(&local->mtx); |
844 | sdata->vif.csa_active = false; | 855 | sdata->vif.csa_active = false; |
856 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
857 | sdata->u.mgd.csa_waiting_bcn = false; | ||
845 | if (sdata->csa_block_tx) { | 858 | if (sdata->csa_block_tx) { |
846 | ieee80211_wake_vif_queues(local, sdata, | 859 | ieee80211_wake_vif_queues(local, sdata, |
847 | IEEE80211_QUEUE_STOP_REASON_CSA); | 860 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -1279,6 +1292,9 @@ static void ieee80211_iface_work(struct work_struct *work) | |||
1279 | break; | 1292 | break; |
1280 | ieee80211_mesh_work(sdata); | 1293 | ieee80211_mesh_work(sdata); |
1281 | break; | 1294 | break; |
1295 | case NL80211_IFTYPE_OCB: | ||
1296 | ieee80211_ocb_work(sdata); | ||
1297 | break; | ||
1282 | default: | 1298 | default: |
1283 | break; | 1299 | break; |
1284 | } | 1300 | } |
@@ -1298,6 +1314,9 @@ static void ieee80211_recalc_smps_work(struct work_struct *work) | |||
1298 | static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | 1314 | static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, |
1299 | enum nl80211_iftype type) | 1315 | enum nl80211_iftype type) |
1300 | { | 1316 | { |
1317 | static const u8 bssid_wildcard[ETH_ALEN] = {0xff, 0xff, 0xff, | ||
1318 | 0xff, 0xff, 0xff}; | ||
1319 | |||
1301 | /* clear type-dependent union */ | 1320 | /* clear type-dependent union */ |
1302 | memset(&sdata->u, 0, sizeof(sdata->u)); | 1321 | memset(&sdata->u, 0, sizeof(sdata->u)); |
1303 | 1322 | ||
@@ -1349,6 +1368,10 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
1349 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; | 1368 | sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid; |
1350 | ieee80211_sta_setup_sdata(sdata); | 1369 | ieee80211_sta_setup_sdata(sdata); |
1351 | break; | 1370 | break; |
1371 | case NL80211_IFTYPE_OCB: | ||
1372 | sdata->vif.bss_conf.bssid = bssid_wildcard; | ||
1373 | ieee80211_ocb_setup_sdata(sdata); | ||
1374 | break; | ||
1352 | case NL80211_IFTYPE_ADHOC: | 1375 | case NL80211_IFTYPE_ADHOC: |
1353 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; | 1376 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
1354 | ieee80211_ibss_setup_sdata(sdata); | 1377 | ieee80211_ibss_setup_sdata(sdata); |
@@ -1396,6 +1419,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | |||
1396 | case NL80211_IFTYPE_AP: | 1419 | case NL80211_IFTYPE_AP: |
1397 | case NL80211_IFTYPE_STATION: | 1420 | case NL80211_IFTYPE_STATION: |
1398 | case NL80211_IFTYPE_ADHOC: | 1421 | case NL80211_IFTYPE_ADHOC: |
1422 | case NL80211_IFTYPE_OCB: | ||
1399 | /* | 1423 | /* |
1400 | * Could maybe also all others here? | 1424 | * Could maybe also all others here? |
1401 | * Just not sure how that interacts | 1425 | * Just not sure how that interacts |
@@ -1411,6 +1435,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, | |||
1411 | case NL80211_IFTYPE_AP: | 1435 | case NL80211_IFTYPE_AP: |
1412 | case NL80211_IFTYPE_STATION: | 1436 | case NL80211_IFTYPE_STATION: |
1413 | case NL80211_IFTYPE_ADHOC: | 1437 | case NL80211_IFTYPE_ADHOC: |
1438 | case NL80211_IFTYPE_OCB: | ||
1414 | /* | 1439 | /* |
1415 | * Could probably support everything | 1440 | * Could probably support everything |
1416 | * but WDS here (WDS do_open can fail | 1441 | * but WDS here (WDS do_open can fail |
@@ -1669,7 +1694,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
1669 | } | 1694 | } |
1670 | 1695 | ||
1671 | ieee80211_assign_perm_addr(local, ndev->perm_addr, type); | 1696 | ieee80211_assign_perm_addr(local, ndev->perm_addr, type); |
1672 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); | 1697 | if (params && is_valid_ether_addr(params->macaddr)) |
1698 | memcpy(ndev->dev_addr, params->macaddr, ETH_ALEN); | ||
1699 | else | ||
1700 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); | ||
1673 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 1701 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); |
1674 | 1702 | ||
1675 | /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */ | 1703 | /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */ |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 4712150dc210..434a91ad12c8 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -94,8 +94,17 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
94 | 94 | ||
95 | might_sleep(); | 95 | might_sleep(); |
96 | 96 | ||
97 | if (key->flags & KEY_FLAG_TAINTED) | 97 | if (key->flags & KEY_FLAG_TAINTED) { |
98 | /* If we get here, it's during resume and the key is | ||
99 | * tainted so shouldn't be used/programmed any more. | ||
100 | * However, its flags may still indicate that it was | ||
101 | * programmed into the device (since we're in resume) | ||
102 | * so clear that flag now to avoid trying to remove | ||
103 | * it again later. | ||
104 | */ | ||
105 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | ||
98 | return -EINVAL; | 106 | return -EINVAL; |
107 | } | ||
99 | 108 | ||
100 | if (!key->local->ops->set_key) | 109 | if (!key->local->ops->set_key) |
101 | goto out_unsupported; | 110 | goto out_unsupported; |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0de7c93bf62b..282a4f36eb92 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -478,13 +478,9 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { | |||
478 | }, | 478 | }, |
479 | }; | 479 | }; |
480 | 480 | ||
481 | static const u8 extended_capabilities[] = { | 481 | struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, |
482 | 0, 0, 0, 0, 0, 0, 0, | 482 | const struct ieee80211_ops *ops, |
483 | WLAN_EXT_CAPA8_OPMODE_NOTIF, | 483 | const char *requested_name) |
484 | }; | ||
485 | |||
486 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | ||
487 | const struct ieee80211_ops *ops) | ||
488 | { | 484 | { |
489 | struct ieee80211_local *local; | 485 | struct ieee80211_local *local; |
490 | int priv_size, i; | 486 | int priv_size, i; |
@@ -524,7 +520,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
524 | */ | 520 | */ |
525 | priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; | 521 | priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; |
526 | 522 | ||
527 | wiphy = wiphy_new(&mac80211_config_ops, priv_size); | 523 | wiphy = wiphy_new_nm(&mac80211_config_ops, priv_size, requested_name); |
528 | 524 | ||
529 | if (!wiphy) | 525 | if (!wiphy) |
530 | return NULL; | 526 | return NULL; |
@@ -539,10 +535,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
539 | WIPHY_FLAG_REPORTS_OBSS | | 535 | WIPHY_FLAG_REPORTS_OBSS | |
540 | WIPHY_FLAG_OFFCHAN_TX; | 536 | WIPHY_FLAG_OFFCHAN_TX; |
541 | 537 | ||
542 | wiphy->extended_capabilities = extended_capabilities; | ||
543 | wiphy->extended_capabilities_mask = extended_capabilities; | ||
544 | wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities); | ||
545 | |||
546 | if (ops->remain_on_channel) | 538 | if (ops->remain_on_channel) |
547 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; | 539 | wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
548 | 540 | ||
@@ -550,6 +542,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
550 | NL80211_FEATURE_SAE | | 542 | NL80211_FEATURE_SAE | |
551 | NL80211_FEATURE_HT_IBSS | | 543 | NL80211_FEATURE_HT_IBSS | |
552 | NL80211_FEATURE_VIF_TXPOWER | | 544 | NL80211_FEATURE_VIF_TXPOWER | |
545 | NL80211_FEATURE_MAC_ON_CREATE | | ||
553 | NL80211_FEATURE_USERSPACE_MPM; | 546 | NL80211_FEATURE_USERSPACE_MPM; |
554 | 547 | ||
555 | if (!ops->hw_scan) | 548 | if (!ops->hw_scan) |
@@ -591,6 +584,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
591 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; | 584 | wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; |
592 | wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; | 585 | wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask; |
593 | 586 | ||
587 | local->ext_capa[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF; | ||
588 | |||
589 | wiphy->extended_capabilities = local->ext_capa; | ||
590 | wiphy->extended_capabilities_mask = local->ext_capa; | ||
591 | wiphy->extended_capabilities_len = | ||
592 | ARRAY_SIZE(local->ext_capa); | ||
593 | |||
594 | INIT_LIST_HEAD(&local->interfaces); | 594 | INIT_LIST_HEAD(&local->interfaces); |
595 | 595 | ||
596 | __hw_addr_init(&local->mc_list); | 596 | __hw_addr_init(&local->mc_list); |
@@ -651,7 +651,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
651 | 651 | ||
652 | return &local->hw; | 652 | return &local->hw; |
653 | } | 653 | } |
654 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 654 | EXPORT_SYMBOL(ieee80211_alloc_hw_nm); |
655 | 655 | ||
656 | static int ieee80211_init_cipher_suites(struct ieee80211_local *local) | 656 | static int ieee80211_init_cipher_suites(struct ieee80211_local *local) |
657 | { | 657 | { |
@@ -787,13 +787,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
787 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) | 787 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS)) |
788 | return -EINVAL; | 788 | return -EINVAL; |
789 | 789 | ||
790 | /* DFS currently not supported with channel context drivers */ | 790 | /* DFS is not supported with multi-channel combinations yet */ |
791 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { | 791 | for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) { |
792 | const struct ieee80211_iface_combination *comb; | 792 | const struct ieee80211_iface_combination *comb; |
793 | 793 | ||
794 | comb = &local->hw.wiphy->iface_combinations[i]; | 794 | comb = &local->hw.wiphy->iface_combinations[i]; |
795 | 795 | ||
796 | if (comb->radar_detect_widths) | 796 | if (comb->radar_detect_widths && |
797 | comb->num_different_channels > 1) | ||
797 | return -EINVAL; | 798 | return -EINVAL; |
798 | } | 799 | } |
799 | } | 800 | } |
@@ -958,6 +959,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
958 | if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) | 959 | if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) |
959 | local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; | 960 | local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; |
960 | 961 | ||
962 | /* mac80211 supports eCSA, if the driver supports STA CSA at all */ | ||
963 | if (local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA) | ||
964 | local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING; | ||
965 | |||
961 | local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM; | 966 | local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM; |
962 | 967 | ||
963 | result = wiphy_register(local->hw.wiphy); | 968 | result = wiphy_register(local->hw.wiphy); |
@@ -1019,7 +1024,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1019 | } | 1024 | } |
1020 | 1025 | ||
1021 | /* add one default STA interface if supported */ | 1026 | /* add one default STA interface if supported */ |
1022 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { | 1027 | if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && |
1028 | !(hw->flags & IEEE80211_HW_NO_AUTO_VIF)) { | ||
1023 | result = ieee80211_if_add(local, "wlan%d", NULL, | 1029 | result = ieee80211_if_add(local, "wlan%d", NULL, |
1024 | NL80211_IFTYPE_STATION, NULL); | 1030 | NL80211_IFTYPE_STATION, NULL); |
1025 | if (result) | 1031 | if (result) |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index f39a19f9090f..50c8473cf9dc 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -270,6 +270,8 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, | |||
270 | const u8 *dst, const u8 *mpp); | 270 | const u8 *dst, const u8 *mpp); |
271 | struct mesh_path * | 271 | struct mesh_path * |
272 | mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); | 272 | mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); |
273 | struct mesh_path * | ||
274 | mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx); | ||
273 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); | 275 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); |
274 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); | 276 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); |
275 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 277 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
@@ -317,6 +319,7 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata); | |||
317 | 319 | ||
318 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); | 320 | bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt); |
319 | extern int mesh_paths_generation; | 321 | extern int mesh_paths_generation; |
322 | extern int mpp_paths_generation; | ||
320 | 323 | ||
321 | #ifdef CONFIG_MAC80211_MESH | 324 | #ifdef CONFIG_MAC80211_MESH |
322 | static inline | 325 | static inline |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index a6699dceae7c..b890e225a8f1 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -44,6 +44,7 @@ static struct mesh_table __rcu *mesh_paths; | |||
44 | static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */ | 44 | static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */ |
45 | 45 | ||
46 | int mesh_paths_generation; | 46 | int mesh_paths_generation; |
47 | int mpp_paths_generation; | ||
47 | 48 | ||
48 | /* This lock will have the grow table function as writer and add / delete nodes | 49 | /* This lock will have the grow table function as writer and add / delete nodes |
49 | * as readers. RCU provides sufficient protection only when reading the table | 50 | * as readers. RCU provides sufficient protection only when reading the table |
@@ -410,6 +411,33 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx) | |||
410 | } | 411 | } |
411 | 412 | ||
412 | /** | 413 | /** |
414 | * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index | ||
415 | * @idx: index | ||
416 | * @sdata: local subif, or NULL for all entries | ||
417 | * | ||
418 | * Returns: pointer to the proxy path structure, or NULL if not found. | ||
419 | * | ||
420 | * Locking: must be called within a read rcu section. | ||
421 | */ | ||
422 | struct mesh_path * | ||
423 | mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx) | ||
424 | { | ||
425 | struct mesh_table *tbl = rcu_dereference(mpp_paths); | ||
426 | struct mpath_node *node; | ||
427 | int i; | ||
428 | int j = 0; | ||
429 | |||
430 | for_each_mesh_entry(tbl, node, i) { | ||
431 | if (sdata && node->mpath->sdata != sdata) | ||
432 | continue; | ||
433 | if (j++ == idx) | ||
434 | return node->mpath; | ||
435 | } | ||
436 | |||
437 | return NULL; | ||
438 | } | ||
439 | |||
440 | /** | ||
413 | * mesh_path_add_gate - add the given mpath to a mesh gate to our path table | 441 | * mesh_path_add_gate - add the given mpath to a mesh gate to our path table |
414 | * @mpath: gate path to add to table | 442 | * @mpath: gate path to add to table |
415 | */ | 443 | */ |
@@ -691,6 +719,9 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, | |||
691 | 719 | ||
692 | spin_unlock(&tbl->hashwlock[hash_idx]); | 720 | spin_unlock(&tbl->hashwlock[hash_idx]); |
693 | read_unlock_bh(&pathtbl_resize_lock); | 721 | read_unlock_bh(&pathtbl_resize_lock); |
722 | |||
723 | mpp_paths_generation++; | ||
724 | |||
694 | if (grow) { | 725 | if (grow) { |
695 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); | 726 | set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags); |
696 | ieee80211_queue_work(&local->hw, &sdata->work); | 727 | ieee80211_queue_work(&local->hw, &sdata->work); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2de88704278b..213a420704a6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -775,11 +775,30 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
775 | WLAN_EID_QOS_CAPA, | 775 | WLAN_EID_QOS_CAPA, |
776 | WLAN_EID_RRM_ENABLED_CAPABILITIES, | 776 | WLAN_EID_RRM_ENABLED_CAPABILITIES, |
777 | WLAN_EID_MOBILITY_DOMAIN, | 777 | WLAN_EID_MOBILITY_DOMAIN, |
778 | WLAN_EID_FAST_BSS_TRANSITION, /* reassoc only */ | ||
779 | WLAN_EID_RIC_DATA, /* reassoc only */ | ||
778 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | 780 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, |
779 | }; | 781 | }; |
780 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | 782 | static const u8 after_ric[] = { |
781 | before_ht, ARRAY_SIZE(before_ht), | 783 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, |
782 | offset); | 784 | WLAN_EID_HT_CAPABILITY, |
785 | WLAN_EID_BSS_COEX_2040, | ||
786 | WLAN_EID_EXT_CAPABILITY, | ||
787 | WLAN_EID_QOS_TRAFFIC_CAPA, | ||
788 | WLAN_EID_TIM_BCAST_REQ, | ||
789 | WLAN_EID_INTERWORKING, | ||
790 | /* 60GHz doesn't happen right now */ | ||
791 | WLAN_EID_VHT_CAPABILITY, | ||
792 | WLAN_EID_OPMODE_NOTIF, | ||
793 | }; | ||
794 | |||
795 | noffset = ieee80211_ie_split_ric(assoc_data->ie, | ||
796 | assoc_data->ie_len, | ||
797 | before_ht, | ||
798 | ARRAY_SIZE(before_ht), | ||
799 | after_ric, | ||
800 | ARRAY_SIZE(after_ric), | ||
801 | offset); | ||
783 | pos = skb_put(skb, noffset - offset); | 802 | pos = skb_put(skb, noffset - offset); |
784 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | 803 | memcpy(pos, assoc_data->ie + offset, noffset - offset); |
785 | offset = noffset; | 804 | offset = noffset; |
@@ -813,6 +832,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
813 | WLAN_EID_TIM_BCAST_REQ, | 832 | WLAN_EID_TIM_BCAST_REQ, |
814 | WLAN_EID_INTERWORKING, | 833 | WLAN_EID_INTERWORKING, |
815 | }; | 834 | }; |
835 | |||
836 | /* RIC already taken above, so no need to handle here anymore */ | ||
816 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | 837 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, |
817 | before_vht, ARRAY_SIZE(before_vht), | 838 | before_vht, ARRAY_SIZE(before_vht), |
818 | offset); | 839 | offset); |
@@ -1001,14 +1022,7 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
1001 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 1022 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
1002 | ifmgd->associated->channel = sdata->csa_chandef.chan; | 1023 | ifmgd->associated->channel = sdata->csa_chandef.chan; |
1003 | 1024 | ||
1004 | sdata->vif.csa_active = false; | 1025 | ifmgd->csa_waiting_bcn = true; |
1005 | |||
1006 | /* XXX: wait for a beacon first? */ | ||
1007 | if (sdata->csa_block_tx) { | ||
1008 | ieee80211_wake_vif_queues(local, sdata, | ||
1009 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1010 | sdata->csa_block_tx = false; | ||
1011 | } | ||
1012 | 1026 | ||
1013 | ieee80211_sta_reset_beacon_monitor(sdata); | 1027 | ieee80211_sta_reset_beacon_monitor(sdata); |
1014 | ieee80211_sta_reset_conn_monitor(sdata); | 1028 | ieee80211_sta_reset_conn_monitor(sdata); |
@@ -1019,6 +1033,35 @@ out: | |||
1019 | sdata_unlock(sdata); | 1033 | sdata_unlock(sdata); |
1020 | } | 1034 | } |
1021 | 1035 | ||
1036 | static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata) | ||
1037 | { | ||
1038 | struct ieee80211_local *local = sdata->local; | ||
1039 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1040 | int ret; | ||
1041 | |||
1042 | sdata_assert_lock(sdata); | ||
1043 | |||
1044 | WARN_ON(!sdata->vif.csa_active); | ||
1045 | |||
1046 | if (sdata->csa_block_tx) { | ||
1047 | ieee80211_wake_vif_queues(local, sdata, | ||
1048 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1049 | sdata->csa_block_tx = false; | ||
1050 | } | ||
1051 | |||
1052 | sdata->vif.csa_active = false; | ||
1053 | ifmgd->csa_waiting_bcn = false; | ||
1054 | |||
1055 | ret = drv_post_channel_switch(sdata); | ||
1056 | if (ret) { | ||
1057 | sdata_info(sdata, | ||
1058 | "driver post channel switch failed, disconnecting\n"); | ||
1059 | ieee80211_queue_work(&local->hw, | ||
1060 | &ifmgd->csa_connection_drop_work); | ||
1061 | return; | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1022 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | 1065 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) |
1023 | { | 1066 | { |
1024 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | 1067 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); |
@@ -1046,7 +1089,8 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
1046 | 1089 | ||
1047 | static void | 1090 | static void |
1048 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 1091 | ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
1049 | u64 timestamp, struct ieee802_11_elems *elems, | 1092 | u64 timestamp, u32 device_timestamp, |
1093 | struct ieee802_11_elems *elems, | ||
1050 | bool beacon) | 1094 | bool beacon) |
1051 | { | 1095 | { |
1052 | struct ieee80211_local *local = sdata->local; | 1096 | struct ieee80211_local *local = sdata->local; |
@@ -1056,6 +1100,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1056 | struct ieee80211_chanctx *chanctx; | 1100 | struct ieee80211_chanctx *chanctx; |
1057 | enum ieee80211_band current_band; | 1101 | enum ieee80211_band current_band; |
1058 | struct ieee80211_csa_ie csa_ie; | 1102 | struct ieee80211_csa_ie csa_ie; |
1103 | struct ieee80211_channel_switch ch_switch; | ||
1059 | int res; | 1104 | int res; |
1060 | 1105 | ||
1061 | sdata_assert_lock(sdata); | 1106 | sdata_assert_lock(sdata); |
@@ -1110,21 +1155,31 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1110 | 1155 | ||
1111 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); | 1156 | chanctx = container_of(conf, struct ieee80211_chanctx, conf); |
1112 | 1157 | ||
1113 | if (local->use_chanctx) { | 1158 | if (local->use_chanctx && |
1114 | u32 num_chanctx = 0; | 1159 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { |
1115 | list_for_each_entry(chanctx, &local->chanctx_list, list) | 1160 | sdata_info(sdata, |
1116 | num_chanctx++; | 1161 | "driver doesn't support chan-switch with channel contexts\n"); |
1162 | ieee80211_queue_work(&local->hw, | ||
1163 | &ifmgd->csa_connection_drop_work); | ||
1164 | mutex_unlock(&local->chanctx_mtx); | ||
1165 | mutex_unlock(&local->mtx); | ||
1166 | return; | ||
1167 | } | ||
1117 | 1168 | ||
1118 | if (num_chanctx > 1 || | 1169 | ch_switch.timestamp = timestamp; |
1119 | !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { | 1170 | ch_switch.device_timestamp = device_timestamp; |
1120 | sdata_info(sdata, | 1171 | ch_switch.block_tx = csa_ie.mode; |
1121 | "not handling chan-switch with channel contexts\n"); | 1172 | ch_switch.chandef = csa_ie.chandef; |
1122 | ieee80211_queue_work(&local->hw, | 1173 | ch_switch.count = csa_ie.count; |
1123 | &ifmgd->csa_connection_drop_work); | 1174 | |
1124 | mutex_unlock(&local->chanctx_mtx); | 1175 | if (drv_pre_channel_switch(sdata, &ch_switch)) { |
1125 | mutex_unlock(&local->mtx); | 1176 | sdata_info(sdata, |
1126 | return; | 1177 | "preparing for channel switch failed, disconnecting\n"); |
1127 | } | 1178 | ieee80211_queue_work(&local->hw, |
1179 | &ifmgd->csa_connection_drop_work); | ||
1180 | mutex_unlock(&local->chanctx_mtx); | ||
1181 | mutex_unlock(&local->mtx); | ||
1182 | return; | ||
1128 | } | 1183 | } |
1129 | 1184 | ||
1130 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, | 1185 | res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef, |
@@ -1152,14 +1207,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
1152 | 1207 | ||
1153 | if (local->ops->channel_switch) { | 1208 | if (local->ops->channel_switch) { |
1154 | /* use driver's channel switch callback */ | 1209 | /* use driver's channel switch callback */ |
1155 | struct ieee80211_channel_switch ch_switch = { | 1210 | drv_channel_switch(local, sdata, &ch_switch); |
1156 | .timestamp = timestamp, | ||
1157 | .block_tx = csa_ie.mode, | ||
1158 | .chandef = csa_ie.chandef, | ||
1159 | .count = csa_ie.count, | ||
1160 | }; | ||
1161 | |||
1162 | drv_channel_switch(local, &ch_switch); | ||
1163 | return; | 1211 | return; |
1164 | } | 1212 | } |
1165 | 1213 | ||
@@ -1579,6 +1627,95 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work) | |||
1579 | mutex_unlock(&sdata->local->mtx); | 1627 | mutex_unlock(&sdata->local->mtx); |
1580 | } | 1628 | } |
1581 | 1629 | ||
1630 | static bool | ||
1631 | __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) | ||
1632 | { | ||
1633 | struct ieee80211_local *local = sdata->local; | ||
1634 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1635 | bool ret; | ||
1636 | int ac; | ||
1637 | |||
1638 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
1639 | return false; | ||
1640 | |||
1641 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
1642 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
1643 | int non_acm_ac; | ||
1644 | unsigned long now = jiffies; | ||
1645 | |||
1646 | if (tx_tspec->action == TX_TSPEC_ACTION_NONE && | ||
1647 | tx_tspec->admitted_time && | ||
1648 | time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
1649 | tx_tspec->consumed_tx_time = 0; | ||
1650 | tx_tspec->time_slice_start = now; | ||
1651 | |||
1652 | if (tx_tspec->downgraded) | ||
1653 | tx_tspec->action = | ||
1654 | TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
1655 | } | ||
1656 | |||
1657 | switch (tx_tspec->action) { | ||
1658 | case TX_TSPEC_ACTION_STOP_DOWNGRADE: | ||
1659 | /* take the original parameters */ | ||
1660 | if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac])) | ||
1661 | sdata_err(sdata, | ||
1662 | "failed to set TX queue parameters for queue %d\n", | ||
1663 | ac); | ||
1664 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1665 | tx_tspec->downgraded = false; | ||
1666 | ret = true; | ||
1667 | break; | ||
1668 | case TX_TSPEC_ACTION_DOWNGRADE: | ||
1669 | if (time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
1670 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1671 | ret = true; | ||
1672 | break; | ||
1673 | } | ||
1674 | /* downgrade next lower non-ACM AC */ | ||
1675 | for (non_acm_ac = ac + 1; | ||
1676 | non_acm_ac < IEEE80211_NUM_ACS; | ||
1677 | non_acm_ac++) | ||
1678 | if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac))) | ||
1679 | break; | ||
1680 | /* The loop will result in using BK even if it requires | ||
1681 | * admission control, such configuration makes no sense | ||
1682 | * and we have to transmit somehow - the AC selection | ||
1683 | * does the same thing. | ||
1684 | */ | ||
1685 | if (drv_conf_tx(local, sdata, ac, | ||
1686 | &sdata->tx_conf[non_acm_ac])) | ||
1687 | sdata_err(sdata, | ||
1688 | "failed to set TX queue parameters for queue %d\n", | ||
1689 | ac); | ||
1690 | tx_tspec->action = TX_TSPEC_ACTION_NONE; | ||
1691 | ret = true; | ||
1692 | schedule_delayed_work(&ifmgd->tx_tspec_wk, | ||
1693 | tx_tspec->time_slice_start + HZ - now + 1); | ||
1694 | break; | ||
1695 | case TX_TSPEC_ACTION_NONE: | ||
1696 | /* nothing now */ | ||
1697 | break; | ||
1698 | } | ||
1699 | } | ||
1700 | |||
1701 | return ret; | ||
1702 | } | ||
1703 | |||
1704 | void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata) | ||
1705 | { | ||
1706 | if (__ieee80211_sta_handle_tspec_ac_params(sdata)) | ||
1707 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); | ||
1708 | } | ||
1709 | |||
1710 | static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work) | ||
1711 | { | ||
1712 | struct ieee80211_sub_if_data *sdata; | ||
1713 | |||
1714 | sdata = container_of(work, struct ieee80211_sub_if_data, | ||
1715 | u.mgd.tx_tspec_wk.work); | ||
1716 | ieee80211_sta_handle_tspec_ac_params(sdata); | ||
1717 | } | ||
1718 | |||
1582 | /* MLME */ | 1719 | /* MLME */ |
1583 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | 1720 | static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, |
1584 | struct ieee80211_sub_if_data *sdata, | 1721 | struct ieee80211_sub_if_data *sdata, |
@@ -1663,12 +1800,14 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
1663 | params.uapsd = uapsd; | 1800 | params.uapsd = uapsd; |
1664 | 1801 | ||
1665 | mlme_dbg(sdata, | 1802 | mlme_dbg(sdata, |
1666 | "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n", | 1803 | "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n", |
1667 | queue, aci, acm, | 1804 | queue, aci, acm, |
1668 | params.aifs, params.cw_min, params.cw_max, | 1805 | params.aifs, params.cw_min, params.cw_max, |
1669 | params.txop, params.uapsd); | 1806 | params.txop, params.uapsd, |
1807 | ifmgd->tx_tspec[queue].downgraded); | ||
1670 | sdata->tx_conf[queue] = params; | 1808 | sdata->tx_conf[queue] = params; |
1671 | if (drv_conf_tx(local, sdata, queue, ¶ms)) | 1809 | if (!ifmgd->tx_tspec[queue].downgraded && |
1810 | drv_conf_tx(local, sdata, queue, ¶ms)) | ||
1672 | sdata_err(sdata, | 1811 | sdata_err(sdata, |
1673 | "failed to set TX queue parameters for queue %d\n", | 1812 | "failed to set TX queue parameters for queue %d\n", |
1674 | queue); | 1813 | queue); |
@@ -1923,6 +2062,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1923 | ieee80211_vif_release_channel(sdata); | 2062 | ieee80211_vif_release_channel(sdata); |
1924 | 2063 | ||
1925 | sdata->vif.csa_active = false; | 2064 | sdata->vif.csa_active = false; |
2065 | ifmgd->csa_waiting_bcn = false; | ||
1926 | if (sdata->csa_block_tx) { | 2066 | if (sdata->csa_block_tx) { |
1927 | ieee80211_wake_vif_queues(local, sdata, | 2067 | ieee80211_wake_vif_queues(local, sdata, |
1928 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2068 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -1930,6 +2070,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1930 | } | 2070 | } |
1931 | mutex_unlock(&local->mtx); | 2071 | mutex_unlock(&local->mtx); |
1932 | 2072 | ||
2073 | /* existing TX TSPEC sessions no longer exist */ | ||
2074 | memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec)); | ||
2075 | cancel_delayed_work_sync(&ifmgd->tx_tspec_wk); | ||
2076 | |||
1933 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; | 2077 | sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; |
1934 | } | 2078 | } |
1935 | 2079 | ||
@@ -1982,9 +2126,46 @@ out: | |||
1982 | mutex_unlock(&local->mtx); | 2126 | mutex_unlock(&local->mtx); |
1983 | } | 2127 | } |
1984 | 2128 | ||
2129 | static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata, | ||
2130 | struct ieee80211_hdr *hdr, | ||
2131 | u16 tx_time) | ||
2132 | { | ||
2133 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2134 | u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | ||
2135 | int ac = ieee80211_ac_from_tid(tid); | ||
2136 | struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac]; | ||
2137 | unsigned long now = jiffies; | ||
2138 | |||
2139 | if (likely(!tx_tspec->admitted_time)) | ||
2140 | return; | ||
2141 | |||
2142 | if (time_after(now, tx_tspec->time_slice_start + HZ)) { | ||
2143 | tx_tspec->consumed_tx_time = 0; | ||
2144 | tx_tspec->time_slice_start = now; | ||
2145 | |||
2146 | if (tx_tspec->downgraded) { | ||
2147 | tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE; | ||
2148 | schedule_delayed_work(&ifmgd->tx_tspec_wk, 0); | ||
2149 | } | ||
2150 | } | ||
2151 | |||
2152 | if (tx_tspec->downgraded) | ||
2153 | return; | ||
2154 | |||
2155 | tx_tspec->consumed_tx_time += tx_time; | ||
2156 | |||
2157 | if (tx_tspec->consumed_tx_time >= tx_tspec->admitted_time) { | ||
2158 | tx_tspec->downgraded = true; | ||
2159 | tx_tspec->action = TX_TSPEC_ACTION_DOWNGRADE; | ||
2160 | schedule_delayed_work(&ifmgd->tx_tspec_wk, 0); | ||
2161 | } | ||
2162 | } | ||
2163 | |||
1985 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | 2164 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, |
1986 | struct ieee80211_hdr *hdr, bool ack) | 2165 | struct ieee80211_hdr *hdr, bool ack, u16 tx_time) |
1987 | { | 2166 | { |
2167 | ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time); | ||
2168 | |||
1988 | if (!ieee80211_is_data(hdr->frame_control)) | 2169 | if (!ieee80211_is_data(hdr->frame_control)) |
1989 | return; | 2170 | return; |
1990 | 2171 | ||
@@ -2047,8 +2228,6 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
2047 | 2228 | ||
2048 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); | 2229 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); |
2049 | run_again(sdata, ifmgd->probe_timeout); | 2230 | run_again(sdata, ifmgd->probe_timeout); |
2050 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
2051 | ieee80211_flush_queues(sdata->local, sdata); | ||
2052 | } | 2231 | } |
2053 | 2232 | ||
2054 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | 2233 | static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, |
@@ -2171,6 +2350,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) | |||
2171 | true, frame_buf); | 2350 | true, frame_buf); |
2172 | mutex_lock(&local->mtx); | 2351 | mutex_lock(&local->mtx); |
2173 | sdata->vif.csa_active = false; | 2352 | sdata->vif.csa_active = false; |
2353 | ifmgd->csa_waiting_bcn = false; | ||
2174 | if (sdata->csa_block_tx) { | 2354 | if (sdata->csa_block_tx) { |
2175 | ieee80211_wake_vif_queues(local, sdata, | 2355 | ieee80211_wake_vif_queues(local, sdata, |
2176 | IEEE80211_QUEUE_STOP_REASON_CSA); | 2356 | IEEE80211_QUEUE_STOP_REASON_CSA); |
@@ -3195,6 +3375,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3195 | } | 3375 | } |
3196 | } | 3376 | } |
3197 | 3377 | ||
3378 | if (ifmgd->csa_waiting_bcn) | ||
3379 | ieee80211_chswitch_post_beacon(sdata); | ||
3380 | |||
3198 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) | 3381 | if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) |
3199 | return; | 3382 | return; |
3200 | ifmgd->beacon_crc = ncrc; | 3383 | ifmgd->beacon_crc = ncrc; |
@@ -3203,6 +3386,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
3203 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 3386 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); |
3204 | 3387 | ||
3205 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, | 3388 | ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, |
3389 | rx_status->device_timestamp, | ||
3206 | &elems, true); | 3390 | &elems, true); |
3207 | 3391 | ||
3208 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && | 3392 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) && |
@@ -3334,8 +3518,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3334 | break; | 3518 | break; |
3335 | 3519 | ||
3336 | ieee80211_sta_process_chanswitch(sdata, | 3520 | ieee80211_sta_process_chanswitch(sdata, |
3337 | rx_status->mactime, | 3521 | rx_status->mactime, |
3338 | &elems, false); | 3522 | rx_status->device_timestamp, |
3523 | &elems, false); | ||
3339 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { | 3524 | } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) { |
3340 | ies_len = skb->len - | 3525 | ies_len = skb->len - |
3341 | offsetof(struct ieee80211_mgmt, | 3526 | offsetof(struct ieee80211_mgmt, |
@@ -3356,8 +3541,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
3356 | &mgmt->u.action.u.ext_chan_switch.data; | 3541 | &mgmt->u.action.u.ext_chan_switch.data; |
3357 | 3542 | ||
3358 | ieee80211_sta_process_chanswitch(sdata, | 3543 | ieee80211_sta_process_chanswitch(sdata, |
3359 | rx_status->mactime, | 3544 | rx_status->mactime, |
3360 | &elems, false); | 3545 | rx_status->device_timestamp, |
3546 | &elems, false); | ||
3361 | } | 3547 | } |
3362 | break; | 3548 | break; |
3363 | } | 3549 | } |
@@ -3664,11 +3850,12 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) | |||
3664 | struct ieee80211_sub_if_data *sdata = | 3850 | struct ieee80211_sub_if_data *sdata = |
3665 | (struct ieee80211_sub_if_data *) data; | 3851 | (struct ieee80211_sub_if_data *) data; |
3666 | struct ieee80211_local *local = sdata->local; | 3852 | struct ieee80211_local *local = sdata->local; |
3853 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
3667 | 3854 | ||
3668 | if (local->quiescing) | 3855 | if (local->quiescing) |
3669 | return; | 3856 | return; |
3670 | 3857 | ||
3671 | if (sdata->vif.csa_active) | 3858 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3672 | return; | 3859 | return; |
3673 | 3860 | ||
3674 | sdata->u.mgd.connection_loss = false; | 3861 | sdata->u.mgd.connection_loss = false; |
@@ -3686,7 +3873,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) | |||
3686 | if (local->quiescing) | 3873 | if (local->quiescing) |
3687 | return; | 3874 | return; |
3688 | 3875 | ||
3689 | if (sdata->vif.csa_active) | 3876 | if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) |
3690 | return; | 3877 | return; |
3691 | 3878 | ||
3692 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); | 3879 | ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); |
@@ -3798,6 +3985,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
3798 | (unsigned long) sdata); | 3985 | (unsigned long) sdata); |
3799 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, | 3986 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
3800 | (unsigned long) sdata); | 3987 | (unsigned long) sdata); |
3988 | INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk, | ||
3989 | ieee80211_sta_handle_tspec_ac_params_wk); | ||
3801 | 3990 | ||
3802 | ifmgd->flags = 0; | 3991 | ifmgd->flags = 0; |
3803 | ifmgd->powersave = sdata->wdev.ps; | 3992 | ifmgd->powersave = sdata->wdev.ps; |
diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c new file mode 100644 index 000000000000..358d5f9d8207 --- /dev/null +++ b/net/mac80211/ocb.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * OCB mode implementation | ||
3 | * | ||
4 | * Copyright: (c) 2014 Czech Technical University in Prague | ||
5 | * (c) 2014 Volkswagen Group Research | ||
6 | * Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz> | ||
7 | * Funded by: Volkswagen Group Research | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/if_ether.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/if_arp.h> | ||
18 | #include <linux/etherdevice.h> | ||
19 | #include <linux/rtnetlink.h> | ||
20 | #include <net/mac80211.h> | ||
21 | #include <asm/unaligned.h> | ||
22 | |||
23 | #include "ieee80211_i.h" | ||
24 | #include "driver-ops.h" | ||
25 | #include "rate.h" | ||
26 | |||
27 | #define IEEE80211_OCB_HOUSEKEEPING_INTERVAL (60 * HZ) | ||
28 | #define IEEE80211_OCB_PEER_INACTIVITY_LIMIT (240 * HZ) | ||
29 | #define IEEE80211_OCB_MAX_STA_ENTRIES 128 | ||
30 | |||
31 | /** | ||
32 | * enum ocb_deferred_task_flags - mac80211 OCB deferred tasks | ||
33 | * @OCB_WORK_HOUSEKEEPING: run the periodic OCB housekeeping tasks | ||
34 | * | ||
35 | * These flags are used in @wrkq_flags field of &struct ieee80211_if_ocb | ||
36 | */ | ||
37 | enum ocb_deferred_task_flags { | ||
38 | OCB_WORK_HOUSEKEEPING, | ||
39 | }; | ||
40 | |||
41 | void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, | ||
42 | const u8 *bssid, const u8 *addr, | ||
43 | u32 supp_rates) | ||
44 | { | ||
45 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
46 | struct ieee80211_local *local = sdata->local; | ||
47 | struct ieee80211_chanctx_conf *chanctx_conf; | ||
48 | struct ieee80211_supported_band *sband; | ||
49 | enum nl80211_bss_scan_width scan_width; | ||
50 | struct sta_info *sta; | ||
51 | int band; | ||
52 | |||
53 | /* XXX: Consider removing the least recently used entry and | ||
54 | * allow new one to be added. | ||
55 | */ | ||
56 | if (local->num_sta >= IEEE80211_OCB_MAX_STA_ENTRIES) { | ||
57 | net_info_ratelimited("%s: No room for a new OCB STA entry %pM\n", | ||
58 | sdata->name, addr); | ||
59 | return; | ||
60 | } | ||
61 | |||
62 | ocb_dbg(sdata, "Adding new OCB station %pM\n", addr); | ||
63 | |||
64 | rcu_read_lock(); | ||
65 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
66 | if (WARN_ON_ONCE(!chanctx_conf)) { | ||
67 | rcu_read_unlock(); | ||
68 | return; | ||
69 | } | ||
70 | band = chanctx_conf->def.chan->band; | ||
71 | scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); | ||
72 | rcu_read_unlock(); | ||
73 | |||
74 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | ||
75 | if (!sta) | ||
76 | return; | ||
77 | |||
78 | sta->last_rx = jiffies; | ||
79 | |||
80 | /* Add only mandatory rates for now */ | ||
81 | sband = local->hw.wiphy->bands[band]; | ||
82 | sta->sta.supp_rates[band] = | ||
83 | ieee80211_mandatory_rates(sband, scan_width); | ||
84 | |||
85 | spin_lock(&ifocb->incomplete_lock); | ||
86 | list_add(&sta->list, &ifocb->incomplete_stations); | ||
87 | spin_unlock(&ifocb->incomplete_lock); | ||
88 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
89 | } | ||
90 | |||
91 | static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta) | ||
92 | __acquires(RCU) | ||
93 | { | ||
94 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
95 | u8 addr[ETH_ALEN]; | ||
96 | |||
97 | memcpy(addr, sta->sta.addr, ETH_ALEN); | ||
98 | |||
99 | ocb_dbg(sdata, "Adding new IBSS station %pM (dev=%s)\n", | ||
100 | addr, sdata->name); | ||
101 | |||
102 | sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
103 | sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
104 | sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
105 | |||
106 | rate_control_rate_init(sta); | ||
107 | |||
108 | /* If it fails, maybe we raced another insertion? */ | ||
109 | if (sta_info_insert_rcu(sta)) | ||
110 | return sta_info_get(sdata, addr); | ||
111 | return sta; | ||
112 | } | ||
113 | |||
114 | static void ieee80211_ocb_housekeeping(struct ieee80211_sub_if_data *sdata) | ||
115 | { | ||
116 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
117 | |||
118 | ocb_dbg(sdata, "Running ocb housekeeping\n"); | ||
119 | |||
120 | ieee80211_sta_expire(sdata, IEEE80211_OCB_PEER_INACTIVITY_LIMIT); | ||
121 | |||
122 | mod_timer(&ifocb->housekeeping_timer, | ||
123 | round_jiffies(jiffies + IEEE80211_OCB_HOUSEKEEPING_INTERVAL)); | ||
124 | } | ||
125 | |||
126 | void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata) | ||
127 | { | ||
128 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
129 | struct sta_info *sta; | ||
130 | |||
131 | if (ifocb->joined != true) | ||
132 | return; | ||
133 | |||
134 | sdata_lock(sdata); | ||
135 | |||
136 | spin_lock_bh(&ifocb->incomplete_lock); | ||
137 | while (!list_empty(&ifocb->incomplete_stations)) { | ||
138 | sta = list_first_entry(&ifocb->incomplete_stations, | ||
139 | struct sta_info, list); | ||
140 | list_del(&sta->list); | ||
141 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
142 | |||
143 | ieee80211_ocb_finish_sta(sta); | ||
144 | rcu_read_unlock(); | ||
145 | spin_lock_bh(&ifocb->incomplete_lock); | ||
146 | } | ||
147 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
148 | |||
149 | if (test_and_clear_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags)) | ||
150 | ieee80211_ocb_housekeeping(sdata); | ||
151 | |||
152 | sdata_unlock(sdata); | ||
153 | } | ||
154 | |||
155 | static void ieee80211_ocb_housekeeping_timer(unsigned long data) | ||
156 | { | ||
157 | struct ieee80211_sub_if_data *sdata = (void *)data; | ||
158 | struct ieee80211_local *local = sdata->local; | ||
159 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
160 | |||
161 | set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags); | ||
162 | |||
163 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
164 | } | ||
165 | |||
166 | void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata) | ||
167 | { | ||
168 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
169 | |||
170 | setup_timer(&ifocb->housekeeping_timer, | ||
171 | ieee80211_ocb_housekeeping_timer, | ||
172 | (unsigned long)sdata); | ||
173 | INIT_LIST_HEAD(&ifocb->incomplete_stations); | ||
174 | spin_lock_init(&ifocb->incomplete_lock); | ||
175 | } | ||
176 | |||
177 | int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, | ||
178 | struct ocb_setup *setup) | ||
179 | { | ||
180 | struct ieee80211_local *local = sdata->local; | ||
181 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
182 | u32 changed = BSS_CHANGED_OCB; | ||
183 | int err; | ||
184 | |||
185 | if (ifocb->joined == true) | ||
186 | return -EINVAL; | ||
187 | |||
188 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
189 | sdata->smps_mode = IEEE80211_SMPS_OFF; | ||
190 | sdata->needed_rx_chains = sdata->local->rx_chains; | ||
191 | |||
192 | mutex_lock(&sdata->local->mtx); | ||
193 | err = ieee80211_vif_use_channel(sdata, &setup->chandef, | ||
194 | IEEE80211_CHANCTX_SHARED); | ||
195 | mutex_unlock(&sdata->local->mtx); | ||
196 | if (err) | ||
197 | return err; | ||
198 | |||
199 | ieee80211_bss_info_change_notify(sdata, changed); | ||
200 | |||
201 | ifocb->joined = true; | ||
202 | |||
203 | set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags); | ||
204 | ieee80211_queue_work(&local->hw, &sdata->work); | ||
205 | |||
206 | netif_carrier_on(sdata->dev); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata) | ||
211 | { | ||
212 | struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | ||
213 | struct ieee80211_local *local = sdata->local; | ||
214 | struct sta_info *sta; | ||
215 | |||
216 | ifocb->joined = false; | ||
217 | sta_info_flush(sdata); | ||
218 | |||
219 | spin_lock_bh(&ifocb->incomplete_lock); | ||
220 | while (!list_empty(&ifocb->incomplete_stations)) { | ||
221 | sta = list_first_entry(&ifocb->incomplete_stations, | ||
222 | struct sta_info, list); | ||
223 | list_del(&sta->list); | ||
224 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
225 | |||
226 | sta_info_free(local, sta); | ||
227 | spin_lock_bh(&ifocb->incomplete_lock); | ||
228 | } | ||
229 | spin_unlock_bh(&ifocb->incomplete_lock); | ||
230 | |||
231 | netif_carrier_off(sdata->dev); | ||
232 | clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||
233 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB); | ||
234 | |||
235 | mutex_lock(&sdata->local->mtx); | ||
236 | ieee80211_vif_release_channel(sdata); | ||
237 | mutex_unlock(&sdata->local->mtx); | ||
238 | |||
239 | skb_queue_purge(&sdata->skb_queue); | ||
240 | |||
241 | del_timer_sync(&sdata->u.ocb.housekeeping_timer); | ||
242 | /* If the timer fired while we waited for it, it will have | ||
243 | * requeued the work. Now the work will be running again | ||
244 | * but will not rearm the timer again because it checks | ||
245 | * whether we are connected to the network or not -- at this | ||
246 | * point we shouldn't be anymore. | ||
247 | */ | ||
248 | |||
249 | return 0; | ||
250 | } | ||
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 2baa7ed8789d..c2b91bf47f6d 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c | |||
@@ -191,7 +191,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) | |||
191 | * (1) if any success probabilitiy >= 95%, out of those rates | 191 | * (1) if any success probabilitiy >= 95%, out of those rates |
192 | * choose the maximum throughput rate as max_prob_rate | 192 | * choose the maximum throughput rate as max_prob_rate |
193 | * (2) if all success probabilities < 95%, the rate with | 193 | * (2) if all success probabilities < 95%, the rate with |
194 | * highest success probability is choosen as max_prob_rate */ | 194 | * highest success probability is chosen as max_prob_rate */ |
195 | if (mrs->probability >= MINSTREL_FRAC(95, 100)) { | 195 | if (mrs->probability >= MINSTREL_FRAC(95, 100)) { |
196 | if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp) | 196 | if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp) |
197 | tmp_prob_rate = i; | 197 | tmp_prob_rate = i; |
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index df90ce2db00c..c50fd94d2aef 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/skbuff.h> | 10 | #include <linux/skbuff.h> |
11 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
12 | #include <linux/random.h> | 12 | #include <linux/random.h> |
13 | #include <linux/moduleparam.h> | ||
13 | #include <linux/ieee80211.h> | 14 | #include <linux/ieee80211.h> |
14 | #include <net/mac80211.h> | 15 | #include <net/mac80211.h> |
15 | #include "rate.h" | 16 | #include "rate.h" |
@@ -34,12 +35,17 @@ | |||
34 | /* Transmit duration for the raw data part of an average sized packet */ | 35 | /* Transmit duration for the raw data part of an average sized packet */ |
35 | #define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) | 36 | #define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) |
36 | 37 | ||
38 | #define BW_20 0 | ||
39 | #define BW_40 1 | ||
40 | #define BW_80 2 | ||
41 | |||
37 | /* | 42 | /* |
38 | * Define group sort order: HT40 -> SGI -> #streams | 43 | * Define group sort order: HT40 -> SGI -> #streams |
39 | */ | 44 | */ |
40 | #define GROUP_IDX(_streams, _sgi, _ht40) \ | 45 | #define GROUP_IDX(_streams, _sgi, _ht40) \ |
46 | MINSTREL_HT_GROUP_0 + \ | ||
41 | MINSTREL_MAX_STREAMS * 2 * _ht40 + \ | 47 | MINSTREL_MAX_STREAMS * 2 * _ht40 + \ |
42 | MINSTREL_MAX_STREAMS * _sgi + \ | 48 | MINSTREL_MAX_STREAMS * _sgi + \ |
43 | _streams - 1 | 49 | _streams - 1 |
44 | 50 | ||
45 | /* MCS rate information for an MCS group */ | 51 | /* MCS rate information for an MCS group */ |
@@ -47,6 +53,7 @@ | |||
47 | [GROUP_IDX(_streams, _sgi, _ht40)] = { \ | 53 | [GROUP_IDX(_streams, _sgi, _ht40)] = { \ |
48 | .streams = _streams, \ | 54 | .streams = _streams, \ |
49 | .flags = \ | 55 | .flags = \ |
56 | IEEE80211_TX_RC_MCS | \ | ||
50 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ | 57 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ |
51 | (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ | 58 | (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ |
52 | .duration = { \ | 59 | .duration = { \ |
@@ -61,6 +68,47 @@ | |||
61 | } \ | 68 | } \ |
62 | } | 69 | } |
63 | 70 | ||
71 | #define VHT_GROUP_IDX(_streams, _sgi, _bw) \ | ||
72 | (MINSTREL_VHT_GROUP_0 + \ | ||
73 | MINSTREL_MAX_STREAMS * 2 * (_bw) + \ | ||
74 | MINSTREL_MAX_STREAMS * (_sgi) + \ | ||
75 | (_streams) - 1) | ||
76 | |||
77 | #define BW2VBPS(_bw, r3, r2, r1) \ | ||
78 | (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) | ||
79 | |||
80 | #define VHT_GROUP(_streams, _sgi, _bw) \ | ||
81 | [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ | ||
82 | .streams = _streams, \ | ||
83 | .flags = \ | ||
84 | IEEE80211_TX_RC_VHT_MCS | \ | ||
85 | (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \ | ||
86 | (_bw == BW_80 ? IEEE80211_TX_RC_80_MHZ_WIDTH : \ | ||
87 | _bw == BW_40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \ | ||
88 | .duration = { \ | ||
89 | MCS_DURATION(_streams, _sgi, \ | ||
90 | BW2VBPS(_bw, 117, 54, 26)), \ | ||
91 | MCS_DURATION(_streams, _sgi, \ | ||
92 | BW2VBPS(_bw, 234, 108, 52)), \ | ||
93 | MCS_DURATION(_streams, _sgi, \ | ||
94 | BW2VBPS(_bw, 351, 162, 78)), \ | ||
95 | MCS_DURATION(_streams, _sgi, \ | ||
96 | BW2VBPS(_bw, 468, 216, 104)), \ | ||
97 | MCS_DURATION(_streams, _sgi, \ | ||
98 | BW2VBPS(_bw, 702, 324, 156)), \ | ||
99 | MCS_DURATION(_streams, _sgi, \ | ||
100 | BW2VBPS(_bw, 936, 432, 208)), \ | ||
101 | MCS_DURATION(_streams, _sgi, \ | ||
102 | BW2VBPS(_bw, 1053, 486, 234)), \ | ||
103 | MCS_DURATION(_streams, _sgi, \ | ||
104 | BW2VBPS(_bw, 1170, 540, 260)), \ | ||
105 | MCS_DURATION(_streams, _sgi, \ | ||
106 | BW2VBPS(_bw, 1404, 648, 312)), \ | ||
107 | MCS_DURATION(_streams, _sgi, \ | ||
108 | BW2VBPS(_bw, 1560, 720, 346)) \ | ||
109 | } \ | ||
110 | } | ||
111 | |||
64 | #define CCK_DURATION(_bitrate, _short, _len) \ | 112 | #define CCK_DURATION(_bitrate, _short, _len) \ |
65 | (1000 * (10 /* SIFS */ + \ | 113 | (1000 * (10 /* SIFS */ + \ |
66 | (_short ? 72 + 24 : 144 + 48) + \ | 114 | (_short ? 72 + 24 : 144 + 48) + \ |
@@ -76,53 +124,96 @@ | |||
76 | CCK_ACK_DURATION(55, _short), \ | 124 | CCK_ACK_DURATION(55, _short), \ |
77 | CCK_ACK_DURATION(110, _short) | 125 | CCK_ACK_DURATION(110, _short) |
78 | 126 | ||
79 | #define CCK_GROUP \ | 127 | #define CCK_GROUP \ |
80 | [MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS] = { \ | 128 | [MINSTREL_CCK_GROUP] = { \ |
81 | .streams = 0, \ | 129 | .streams = 0, \ |
82 | .duration = { \ | 130 | .flags = 0, \ |
83 | CCK_DURATION_LIST(false), \ | 131 | .duration = { \ |
84 | CCK_DURATION_LIST(true) \ | 132 | CCK_DURATION_LIST(false), \ |
85 | } \ | 133 | CCK_DURATION_LIST(true) \ |
134 | } \ | ||
86 | } | 135 | } |
87 | 136 | ||
137 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
138 | static bool minstrel_vht_only = true; | ||
139 | module_param(minstrel_vht_only, bool, 0644); | ||
140 | MODULE_PARM_DESC(minstrel_vht_only, | ||
141 | "Use only VHT rates when VHT is supported by sta."); | ||
142 | #endif | ||
143 | |||
88 | /* | 144 | /* |
89 | * To enable sufficiently targeted rate sampling, MCS rates are divided into | 145 | * To enable sufficiently targeted rate sampling, MCS rates are divided into |
90 | * groups, based on the number of streams and flags (HT40, SGI) that they | 146 | * groups, based on the number of streams and flags (HT40, SGI) that they |
91 | * use. | 147 | * use. |
92 | * | 148 | * |
93 | * Sortorder has to be fixed for GROUP_IDX macro to be applicable: | 149 | * Sortorder has to be fixed for GROUP_IDX macro to be applicable: |
94 | * HT40 -> SGI -> #streams | 150 | * BW -> SGI -> #streams |
95 | */ | 151 | */ |
96 | const struct mcs_group minstrel_mcs_groups[] = { | 152 | const struct mcs_group minstrel_mcs_groups[] = { |
97 | MCS_GROUP(1, 0, 0), | 153 | MCS_GROUP(1, 0, BW_20), |
98 | MCS_GROUP(2, 0, 0), | 154 | MCS_GROUP(2, 0, BW_20), |
99 | #if MINSTREL_MAX_STREAMS >= 3 | 155 | #if MINSTREL_MAX_STREAMS >= 3 |
100 | MCS_GROUP(3, 0, 0), | 156 | MCS_GROUP(3, 0, BW_20), |
101 | #endif | 157 | #endif |
102 | 158 | ||
103 | MCS_GROUP(1, 1, 0), | 159 | MCS_GROUP(1, 1, BW_20), |
104 | MCS_GROUP(2, 1, 0), | 160 | MCS_GROUP(2, 1, BW_20), |
105 | #if MINSTREL_MAX_STREAMS >= 3 | 161 | #if MINSTREL_MAX_STREAMS >= 3 |
106 | MCS_GROUP(3, 1, 0), | 162 | MCS_GROUP(3, 1, BW_20), |
107 | #endif | 163 | #endif |
108 | 164 | ||
109 | MCS_GROUP(1, 0, 1), | 165 | MCS_GROUP(1, 0, BW_40), |
110 | MCS_GROUP(2, 0, 1), | 166 | MCS_GROUP(2, 0, BW_40), |
111 | #if MINSTREL_MAX_STREAMS >= 3 | 167 | #if MINSTREL_MAX_STREAMS >= 3 |
112 | MCS_GROUP(3, 0, 1), | 168 | MCS_GROUP(3, 0, BW_40), |
113 | #endif | 169 | #endif |
114 | 170 | ||
115 | MCS_GROUP(1, 1, 1), | 171 | MCS_GROUP(1, 1, BW_40), |
116 | MCS_GROUP(2, 1, 1), | 172 | MCS_GROUP(2, 1, BW_40), |
117 | #if MINSTREL_MAX_STREAMS >= 3 | 173 | #if MINSTREL_MAX_STREAMS >= 3 |
118 | MCS_GROUP(3, 1, 1), | 174 | MCS_GROUP(3, 1, BW_40), |
119 | #endif | 175 | #endif |
120 | 176 | ||
121 | /* must be last */ | 177 | CCK_GROUP, |
122 | CCK_GROUP | ||
123 | }; | ||
124 | 178 | ||
125 | #define MINSTREL_CCK_GROUP (ARRAY_SIZE(minstrel_mcs_groups) - 1) | 179 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT |
180 | VHT_GROUP(1, 0, BW_20), | ||
181 | VHT_GROUP(2, 0, BW_20), | ||
182 | #if MINSTREL_MAX_STREAMS >= 3 | ||
183 | VHT_GROUP(3, 0, BW_20), | ||
184 | #endif | ||
185 | |||
186 | VHT_GROUP(1, 1, BW_20), | ||
187 | VHT_GROUP(2, 1, BW_20), | ||
188 | #if MINSTREL_MAX_STREAMS >= 3 | ||
189 | VHT_GROUP(3, 1, BW_20), | ||
190 | #endif | ||
191 | |||
192 | VHT_GROUP(1, 0, BW_40), | ||
193 | VHT_GROUP(2, 0, BW_40), | ||
194 | #if MINSTREL_MAX_STREAMS >= 3 | ||
195 | VHT_GROUP(3, 0, BW_40), | ||
196 | #endif | ||
197 | |||
198 | VHT_GROUP(1, 1, BW_40), | ||
199 | VHT_GROUP(2, 1, BW_40), | ||
200 | #if MINSTREL_MAX_STREAMS >= 3 | ||
201 | VHT_GROUP(3, 1, BW_40), | ||
202 | #endif | ||
203 | |||
204 | VHT_GROUP(1, 0, BW_80), | ||
205 | VHT_GROUP(2, 0, BW_80), | ||
206 | #if MINSTREL_MAX_STREAMS >= 3 | ||
207 | VHT_GROUP(3, 0, BW_80), | ||
208 | #endif | ||
209 | |||
210 | VHT_GROUP(1, 1, BW_80), | ||
211 | VHT_GROUP(2, 1, BW_80), | ||
212 | #if MINSTREL_MAX_STREAMS >= 3 | ||
213 | VHT_GROUP(3, 1, BW_80), | ||
214 | #endif | ||
215 | #endif | ||
216 | }; | ||
126 | 217 | ||
127 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; | 218 | static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; |
128 | 219 | ||
@@ -130,16 +221,64 @@ static void | |||
130 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); | 221 | minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); |
131 | 222 | ||
132 | /* | 223 | /* |
224 | * Some VHT MCSes are invalid (when Ndbps / Nes is not an integer) | ||
225 | * e.g for MCS9@20MHzx1Nss: Ndbps=8x52*(5/6) Nes=1 | ||
226 | * | ||
227 | * Returns the valid mcs map for struct minstrel_mcs_group_data.supported | ||
228 | */ | ||
229 | static u16 | ||
230 | minstrel_get_valid_vht_rates(int bw, int nss, __le16 mcs_map) | ||
231 | { | ||
232 | u16 mask = 0; | ||
233 | |||
234 | if (bw == BW_20) { | ||
235 | if (nss != 3 && nss != 6) | ||
236 | mask = BIT(9); | ||
237 | } else if (bw == BW_80) { | ||
238 | if (nss == 3 || nss == 7) | ||
239 | mask = BIT(6); | ||
240 | else if (nss == 6) | ||
241 | mask = BIT(9); | ||
242 | } else { | ||
243 | WARN_ON(bw != BW_40); | ||
244 | } | ||
245 | |||
246 | switch ((le16_to_cpu(mcs_map) >> (2 * (nss - 1))) & 3) { | ||
247 | case IEEE80211_VHT_MCS_SUPPORT_0_7: | ||
248 | mask |= 0x300; | ||
249 | break; | ||
250 | case IEEE80211_VHT_MCS_SUPPORT_0_8: | ||
251 | mask |= 0x200; | ||
252 | break; | ||
253 | case IEEE80211_VHT_MCS_SUPPORT_0_9: | ||
254 | break; | ||
255 | default: | ||
256 | mask = 0x3ff; | ||
257 | } | ||
258 | |||
259 | return 0x3ff & ~mask; | ||
260 | } | ||
261 | |||
262 | /* | ||
133 | * Look up an MCS group index based on mac80211 rate information | 263 | * Look up an MCS group index based on mac80211 rate information |
134 | */ | 264 | */ |
135 | static int | 265 | static int |
136 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) | 266 | minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate) |
137 | { | 267 | { |
138 | return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1, | 268 | return GROUP_IDX((rate->idx / 8) + 1, |
139 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), | 269 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), |
140 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); | 270 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)); |
141 | } | 271 | } |
142 | 272 | ||
273 | static int | ||
274 | minstrel_vht_get_group_idx(struct ieee80211_tx_rate *rate) | ||
275 | { | ||
276 | return VHT_GROUP_IDX(ieee80211_rate_get_vht_nss(rate), | ||
277 | !!(rate->flags & IEEE80211_TX_RC_SHORT_GI), | ||
278 | !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + | ||
279 | 2*!!(rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)); | ||
280 | } | ||
281 | |||
143 | static struct minstrel_rate_stats * | 282 | static struct minstrel_rate_stats * |
144 | minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | 283 | minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, |
145 | struct ieee80211_tx_rate *rate) | 284 | struct ieee80211_tx_rate *rate) |
@@ -149,6 +288,9 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
149 | if (rate->flags & IEEE80211_TX_RC_MCS) { | 288 | if (rate->flags & IEEE80211_TX_RC_MCS) { |
150 | group = minstrel_ht_get_group_idx(rate); | 289 | group = minstrel_ht_get_group_idx(rate); |
151 | idx = rate->idx % 8; | 290 | idx = rate->idx % 8; |
291 | } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { | ||
292 | group = minstrel_vht_get_group_idx(rate); | ||
293 | idx = ieee80211_rate_get_vht_mcs(rate); | ||
152 | } else { | 294 | } else { |
153 | group = MINSTREL_CCK_GROUP; | 295 | group = MINSTREL_CCK_GROUP; |
154 | 296 | ||
@@ -240,8 +382,8 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) | |||
240 | * MCS groups, CCK rates do not provide aggregation and are therefore at last. | 382 | * MCS groups, CCK rates do not provide aggregation and are therefore at last. |
241 | */ | 383 | */ |
242 | static void | 384 | static void |
243 | minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index, | 385 | minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index, |
244 | u8 *tp_list) | 386 | u16 *tp_list) |
245 | { | 387 | { |
246 | int cur_group, cur_idx, cur_thr, cur_prob; | 388 | int cur_group, cur_idx, cur_thr, cur_prob; |
247 | int tmp_group, tmp_idx, tmp_thr, tmp_prob; | 389 | int tmp_group, tmp_idx, tmp_thr, tmp_prob; |
@@ -278,7 +420,7 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index, | |||
278 | * Find and set the topmost probability rate per sta and per group | 420 | * Find and set the topmost probability rate per sta and per group |
279 | */ | 421 | */ |
280 | static void | 422 | static void |
281 | minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index) | 423 | minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) |
282 | { | 424 | { |
283 | struct minstrel_mcs_group_data *mg; | 425 | struct minstrel_mcs_group_data *mg; |
284 | struct minstrel_rate_stats *mr; | 426 | struct minstrel_rate_stats *mr; |
@@ -321,8 +463,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index) | |||
321 | */ | 463 | */ |
322 | static void | 464 | static void |
323 | minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, | 465 | minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, |
324 | u8 tmp_mcs_tp_rate[MAX_THR_RATES], | 466 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], |
325 | u8 tmp_cck_tp_rate[MAX_THR_RATES]) | 467 | u16 tmp_cck_tp_rate[MAX_THR_RATES]) |
326 | { | 468 | { |
327 | unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; | 469 | unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; |
328 | int i; | 470 | int i; |
@@ -386,8 +528,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | |||
386 | struct minstrel_mcs_group_data *mg; | 528 | struct minstrel_mcs_group_data *mg; |
387 | struct minstrel_rate_stats *mr; | 529 | struct minstrel_rate_stats *mr; |
388 | int group, i, j; | 530 | int group, i, j; |
389 | u8 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; | 531 | u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; |
390 | u8 tmp_cck_tp_rate[MAX_THR_RATES], index; | 532 | u16 tmp_cck_tp_rate[MAX_THR_RATES], index; |
391 | 533 | ||
392 | if (mi->ampdu_packets > 0) { | 534 | if (mi->ampdu_packets > 0) { |
393 | mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, | 535 | mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, |
@@ -485,7 +627,8 @@ minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rat | |||
485 | if (!rate->count) | 627 | if (!rate->count) |
486 | return false; | 628 | return false; |
487 | 629 | ||
488 | if (rate->flags & IEEE80211_TX_RC_MCS) | 630 | if (rate->flags & IEEE80211_TX_RC_MCS || |
631 | rate->flags & IEEE80211_TX_RC_VHT_MCS) | ||
489 | return true; | 632 | return true; |
490 | 633 | ||
491 | return rate->idx == mp->cck_rates[0] || | 634 | return rate->idx == mp->cck_rates[0] || |
@@ -517,7 +660,7 @@ minstrel_next_sample_idx(struct minstrel_ht_sta *mi) | |||
517 | } | 660 | } |
518 | 661 | ||
519 | static void | 662 | static void |
520 | minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u8 *idx, bool primary) | 663 | minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) |
521 | { | 664 | { |
522 | int group, orig_group; | 665 | int group, orig_group; |
523 | 666 | ||
@@ -714,7 +857,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
714 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; | 857 | const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; |
715 | struct minstrel_rate_stats *mr; | 858 | struct minstrel_rate_stats *mr; |
716 | u8 idx; | 859 | u8 idx; |
717 | u16 flags; | 860 | u16 flags = group->flags; |
718 | 861 | ||
719 | mr = minstrel_get_ratestats(mi, index); | 862 | mr = minstrel_get_ratestats(mi, index); |
720 | if (!mr->retry_updated) | 863 | if (!mr->retry_updated) |
@@ -730,13 +873,13 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, | |||
730 | ratetbl->rate[offset].count_rts = mr->retry_count_rtscts; | 873 | ratetbl->rate[offset].count_rts = mr->retry_count_rtscts; |
731 | } | 874 | } |
732 | 875 | ||
733 | if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { | 876 | if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) |
734 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; | 877 | idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; |
735 | flags = 0; | 878 | else if (flags & IEEE80211_TX_RC_VHT_MCS) |
736 | } else { | 879 | idx = ((group->streams - 1) << 4) | |
880 | ((index % MCS_GROUP_RATES) & 0xF); | ||
881 | else | ||
737 | idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; | 882 | idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; |
738 | flags = IEEE80211_TX_RC_MCS | group->flags; | ||
739 | } | ||
740 | 883 | ||
741 | if (offset > 0) { | 884 | if (offset > 0) { |
742 | ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; | 885 | ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; |
@@ -916,13 +1059,15 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, | |||
916 | if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { | 1059 | if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) { |
917 | int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); | 1060 | int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); |
918 | rate->idx = mp->cck_rates[idx]; | 1061 | rate->idx = mp->cck_rates[idx]; |
919 | rate->flags = 0; | 1062 | } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) { |
920 | return; | 1063 | ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES, |
1064 | sample_group->streams); | ||
1065 | } else { | ||
1066 | rate->idx = sample_idx % MCS_GROUP_RATES + | ||
1067 | (sample_group->streams - 1) * 8; | ||
921 | } | 1068 | } |
922 | 1069 | ||
923 | rate->idx = sample_idx % MCS_GROUP_RATES + | 1070 | rate->flags = sample_group->flags; |
924 | (sample_group->streams - 1) * 8; | ||
925 | rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags; | ||
926 | } | 1071 | } |
927 | 1072 | ||
928 | static void | 1073 | static void |
@@ -962,6 +1107,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
962 | struct minstrel_ht_sta *mi = &msp->ht; | 1107 | struct minstrel_ht_sta *mi = &msp->ht; |
963 | struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; | 1108 | struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; |
964 | u16 sta_cap = sta->ht_cap.cap; | 1109 | u16 sta_cap = sta->ht_cap.cap; |
1110 | struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; | ||
1111 | int use_vht; | ||
965 | int n_supported = 0; | 1112 | int n_supported = 0; |
966 | int ack_dur; | 1113 | int ack_dur; |
967 | int stbc; | 1114 | int stbc; |
@@ -971,8 +1118,14 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
971 | if (!sta->ht_cap.ht_supported) | 1118 | if (!sta->ht_cap.ht_supported) |
972 | goto use_legacy; | 1119 | goto use_legacy; |
973 | 1120 | ||
974 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != | 1121 | BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB); |
975 | MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1); | 1122 | |
1123 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
1124 | if (vht_cap->vht_supported) | ||
1125 | use_vht = vht_cap->vht_mcs.tx_mcs_map != cpu_to_le16(~0); | ||
1126 | else | ||
1127 | #endif | ||
1128 | use_vht = 0; | ||
976 | 1129 | ||
977 | msp->is_ht = true; | 1130 | msp->is_ht = true; |
978 | memset(mi, 0, sizeof(*mi)); | 1131 | memset(mi, 0, sizeof(*mi)); |
@@ -997,22 +1150,28 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
997 | } | 1150 | } |
998 | mi->sample_tries = 4; | 1151 | mi->sample_tries = 4; |
999 | 1152 | ||
1000 | stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >> | 1153 | /* TODO tx_flags for vht - ATM the RC API is not fine-grained enough */ |
1001 | IEEE80211_HT_CAP_RX_STBC_SHIFT; | 1154 | if (!use_vht) { |
1002 | mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; | 1155 | stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >> |
1156 | IEEE80211_HT_CAP_RX_STBC_SHIFT; | ||
1157 | mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT; | ||
1003 | 1158 | ||
1004 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) | 1159 | if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING) |
1005 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; | 1160 | mi->tx_flags |= IEEE80211_TX_CTL_LDPC; |
1161 | } | ||
1006 | 1162 | ||
1007 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { | 1163 | for (i = 0; i < ARRAY_SIZE(mi->groups); i++) { |
1164 | u32 gflags = minstrel_mcs_groups[i].flags; | ||
1165 | int bw, nss; | ||
1166 | |||
1008 | mi->groups[i].supported = 0; | 1167 | mi->groups[i].supported = 0; |
1009 | if (i == MINSTREL_CCK_GROUP) { | 1168 | if (i == MINSTREL_CCK_GROUP) { |
1010 | minstrel_ht_update_cck(mp, mi, sband, sta); | 1169 | minstrel_ht_update_cck(mp, mi, sband, sta); |
1011 | continue; | 1170 | continue; |
1012 | } | 1171 | } |
1013 | 1172 | ||
1014 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) { | 1173 | if (gflags & IEEE80211_TX_RC_SHORT_GI) { |
1015 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | 1174 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) { |
1016 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) | 1175 | if (!(sta_cap & IEEE80211_HT_CAP_SGI_40)) |
1017 | continue; | 1176 | continue; |
1018 | } else { | 1177 | } else { |
@@ -1021,17 +1180,51 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, | |||
1021 | } | 1180 | } |
1022 | } | 1181 | } |
1023 | 1182 | ||
1024 | if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH && | 1183 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH && |
1025 | sta->bandwidth < IEEE80211_STA_RX_BW_40) | 1184 | sta->bandwidth < IEEE80211_STA_RX_BW_40) |
1026 | continue; | 1185 | continue; |
1027 | 1186 | ||
1187 | nss = minstrel_mcs_groups[i].streams; | ||
1188 | |||
1028 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ | 1189 | /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */ |
1029 | if (sta->smps_mode == IEEE80211_SMPS_STATIC && | 1190 | if (sta->smps_mode == IEEE80211_SMPS_STATIC && nss > 1) |
1030 | minstrel_mcs_groups[i].streams > 1) | 1191 | continue; |
1192 | |||
1193 | /* HT rate */ | ||
1194 | if (gflags & IEEE80211_TX_RC_MCS) { | ||
1195 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
1196 | if (use_vht && minstrel_vht_only) | ||
1197 | continue; | ||
1198 | #endif | ||
1199 | mi->groups[i].supported = mcs->rx_mask[nss - 1]; | ||
1200 | if (mi->groups[i].supported) | ||
1201 | n_supported++; | ||
1031 | continue; | 1202 | continue; |
1203 | } | ||
1204 | |||
1205 | /* VHT rate */ | ||
1206 | if (!vht_cap->vht_supported || | ||
1207 | WARN_ON(!(gflags & IEEE80211_TX_RC_VHT_MCS)) || | ||
1208 | WARN_ON(gflags & IEEE80211_TX_RC_160_MHZ_WIDTH)) | ||
1209 | continue; | ||
1210 | |||
1211 | if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) { | ||
1212 | if (sta->bandwidth < IEEE80211_STA_RX_BW_80 || | ||
1213 | ((gflags & IEEE80211_TX_RC_SHORT_GI) && | ||
1214 | !(vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80))) { | ||
1215 | continue; | ||
1216 | } | ||
1217 | } | ||
1218 | |||
1219 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
1220 | bw = BW_40; | ||
1221 | else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) | ||
1222 | bw = BW_80; | ||
1223 | else | ||
1224 | bw = BW_20; | ||
1032 | 1225 | ||
1033 | mi->groups[i].supported = | 1226 | mi->groups[i].supported = minstrel_get_valid_vht_rates(bw, nss, |
1034 | mcs->rx_mask[minstrel_mcs_groups[i].streams - 1]; | 1227 | vht_cap->vht_mcs.tx_mcs_map); |
1035 | 1228 | ||
1036 | if (mi->groups[i].supported) | 1229 | if (mi->groups[i].supported) |
1037 | n_supported++; | 1230 | n_supported++; |
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h index 01570e0e014b..f2217d6aa0c2 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h | |||
@@ -13,10 +13,32 @@ | |||
13 | * The number of streams can be changed to 2 to reduce code | 13 | * The number of streams can be changed to 2 to reduce code |
14 | * size and memory footprint. | 14 | * size and memory footprint. |
15 | */ | 15 | */ |
16 | #define MINSTREL_MAX_STREAMS 3 | 16 | #define MINSTREL_MAX_STREAMS 3 |
17 | #define MINSTREL_STREAM_GROUPS 4 | 17 | #define MINSTREL_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ |
18 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
19 | #define MINSTREL_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */ | ||
20 | #else | ||
21 | #define MINSTREL_VHT_STREAM_GROUPS 0 | ||
22 | #endif | ||
18 | 23 | ||
19 | #define MCS_GROUP_RATES 8 | 24 | #define MINSTREL_HT_GROUPS_NB (MINSTREL_MAX_STREAMS * \ |
25 | MINSTREL_HT_STREAM_GROUPS) | ||
26 | #define MINSTREL_VHT_GROUPS_NB (MINSTREL_MAX_STREAMS * \ | ||
27 | MINSTREL_VHT_STREAM_GROUPS) | ||
28 | #define MINSTREL_CCK_GROUPS_NB 1 | ||
29 | #define MINSTREL_GROUPS_NB (MINSTREL_HT_GROUPS_NB + \ | ||
30 | MINSTREL_VHT_GROUPS_NB + \ | ||
31 | MINSTREL_CCK_GROUPS_NB) | ||
32 | |||
33 | #define MINSTREL_HT_GROUP_0 0 | ||
34 | #define MINSTREL_CCK_GROUP (MINSTREL_HT_GROUP_0 + MINSTREL_HT_GROUPS_NB) | ||
35 | #define MINSTREL_VHT_GROUP_0 (MINSTREL_CCK_GROUP + 1) | ||
36 | |||
37 | #ifdef CONFIG_MAC80211_RC_MINSTREL_VHT | ||
38 | #define MCS_GROUP_RATES 10 | ||
39 | #else | ||
40 | #define MCS_GROUP_RATES 8 | ||
41 | #endif | ||
20 | 42 | ||
21 | struct mcs_group { | 43 | struct mcs_group { |
22 | u32 flags; | 44 | u32 flags; |
@@ -31,11 +53,11 @@ struct minstrel_mcs_group_data { | |||
31 | u8 column; | 53 | u8 column; |
32 | 54 | ||
33 | /* bitfield of supported MCS rates of this group */ | 55 | /* bitfield of supported MCS rates of this group */ |
34 | u8 supported; | 56 | u16 supported; |
35 | 57 | ||
36 | /* sorted rate set within a MCS group*/ | 58 | /* sorted rate set within a MCS group*/ |
37 | u8 max_group_tp_rate[MAX_THR_RATES]; | 59 | u16 max_group_tp_rate[MAX_THR_RATES]; |
38 | u8 max_group_prob_rate; | 60 | u16 max_group_prob_rate; |
39 | 61 | ||
40 | /* MCS rate statistics */ | 62 | /* MCS rate statistics */ |
41 | struct minstrel_rate_stats rates[MCS_GROUP_RATES]; | 63 | struct minstrel_rate_stats rates[MCS_GROUP_RATES]; |
@@ -52,8 +74,8 @@ struct minstrel_ht_sta { | |||
52 | unsigned int avg_ampdu_len; | 74 | unsigned int avg_ampdu_len; |
53 | 75 | ||
54 | /* overall sorted rate set */ | 76 | /* overall sorted rate set */ |
55 | u8 max_tp_rate[MAX_THR_RATES]; | 77 | u16 max_tp_rate[MAX_THR_RATES]; |
56 | u8 max_prob_rate; | 78 | u16 max_prob_rate; |
57 | 79 | ||
58 | /* time of last status update */ | 80 | /* time of last status update */ |
59 | unsigned long stats_update; | 81 | unsigned long stats_update; |
@@ -80,7 +102,7 @@ struct minstrel_ht_sta { | |||
80 | u8 cck_supported_short; | 102 | u8 cck_supported_short; |
81 | 103 | ||
82 | /* MCS rate group info and statistics */ | 104 | /* MCS rate group info and statistics */ |
83 | struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1]; | 105 | struct minstrel_mcs_group_data groups[MINSTREL_GROUPS_NB]; |
84 | }; | 106 | }; |
85 | 107 | ||
86 | struct minstrel_ht_sta_priv { | 108 | struct minstrel_ht_sta_priv { |
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c index d537bec93754..20c676b8e5b6 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c | |||
@@ -18,19 +18,23 @@ | |||
18 | static char * | 18 | static char * |
19 | minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | 19 | minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) |
20 | { | 20 | { |
21 | unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; | ||
22 | const struct mcs_group *mg; | 21 | const struct mcs_group *mg; |
23 | unsigned int j, tp, prob, eprob; | 22 | unsigned int j, tp, prob, eprob; |
24 | char htmode = '2'; | 23 | char htmode = '2'; |
25 | char gimode = 'L'; | 24 | char gimode = 'L'; |
25 | u32 gflags; | ||
26 | 26 | ||
27 | if (!mi->groups[i].supported) | 27 | if (!mi->groups[i].supported) |
28 | return p; | 28 | return p; |
29 | 29 | ||
30 | mg = &minstrel_mcs_groups[i]; | 30 | mg = &minstrel_mcs_groups[i]; |
31 | if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | 31 | gflags = mg->flags; |
32 | |||
33 | if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
32 | htmode = '4'; | 34 | htmode = '4'; |
33 | if (mg->flags & IEEE80211_TX_RC_SHORT_GI) | 35 | else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) |
36 | htmode = '8'; | ||
37 | if (gflags & IEEE80211_TX_RC_SHORT_GI) | ||
34 | gimode = 'S'; | 38 | gimode = 'S'; |
35 | 39 | ||
36 | for (j = 0; j < MCS_GROUP_RATES; j++) { | 40 | for (j = 0; j < MCS_GROUP_RATES; j++) { |
@@ -41,10 +45,12 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | |||
41 | if (!(mi->groups[i].supported & BIT(j))) | 45 | if (!(mi->groups[i].supported & BIT(j))) |
42 | continue; | 46 | continue; |
43 | 47 | ||
44 | if (i == max_mcs) | 48 | if (gflags & IEEE80211_TX_RC_MCS) |
45 | p += sprintf(p, "CCK/%cP ", j < 4 ? 'L' : 'S'); | 49 | p += sprintf(p, " HT%c0/%cGI ", htmode, gimode); |
50 | else if (gflags & IEEE80211_TX_RC_VHT_MCS) | ||
51 | p += sprintf(p, "VHT%c0/%cGI ", htmode, gimode); | ||
46 | else | 52 | else |
47 | p += sprintf(p, "HT%c0/%cGI ", htmode, gimode); | 53 | p += sprintf(p, " CCK/%cP ", j < 4 ? 'L' : 'S'); |
48 | 54 | ||
49 | *(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' '; | 55 | *(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' '; |
50 | *(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' '; | 56 | *(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' '; |
@@ -52,11 +58,14 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) | |||
52 | *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' '; | 58 | *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' '; |
53 | *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; | 59 | *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; |
54 | 60 | ||
55 | if (i == max_mcs) { | 61 | if (gflags & IEEE80211_TX_RC_MCS) { |
56 | int r = bitrates[j % 4]; | 62 | p += sprintf(p, " MCS%-2u ", (mg->streams - 1) * 8 + j); |
57 | p += sprintf(p, " %2u.%1uM", r / 10, r % 10); | 63 | } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { |
64 | p += sprintf(p, " MCS%-1u/%1u", j, mg->streams); | ||
58 | } else { | 65 | } else { |
59 | p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j); | 66 | int r = bitrates[j % 4]; |
67 | |||
68 | p += sprintf(p, " %2u.%1uM ", r / 10, r % 10); | ||
60 | } | 69 | } |
61 | 70 | ||
62 | tp = mr->cur_tp / 10; | 71 | tp = mr->cur_tp / 10; |
@@ -85,7 +94,6 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
85 | struct minstrel_ht_sta *mi = &msp->ht; | 94 | struct minstrel_ht_sta *mi = &msp->ht; |
86 | struct minstrel_debugfs_info *ms; | 95 | struct minstrel_debugfs_info *ms; |
87 | unsigned int i; | 96 | unsigned int i; |
88 | unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; | ||
89 | char *p; | 97 | char *p; |
90 | int ret; | 98 | int ret; |
91 | 99 | ||
@@ -96,18 +104,19 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
96 | return ret; | 104 | return ret; |
97 | } | 105 | } |
98 | 106 | ||
99 | ms = kmalloc(8192, GFP_KERNEL); | 107 | ms = kmalloc(32768, GFP_KERNEL); |
100 | if (!ms) | 108 | if (!ms) |
101 | return -ENOMEM; | 109 | return -ENOMEM; |
102 | 110 | ||
103 | file->private_data = ms; | 111 | file->private_data = ms; |
104 | p = ms->buf; | 112 | p = ms->buf; |
105 | p += sprintf(p, "type rate tpt eprob *prob " | 113 | p += sprintf(p, " type rate tpt eprob *prob " |
106 | "ret *ok(*cum) ok( cum)\n"); | 114 | "ret *ok(*cum) ok( cum)\n"); |
107 | 115 | ||
108 | 116 | p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); | |
109 | p = minstrel_ht_stats_dump(mi, max_mcs, p); | 117 | for (i = 0; i < MINSTREL_CCK_GROUP; i++) |
110 | for (i = 0; i < max_mcs; i++) | 118 | p = minstrel_ht_stats_dump(mi, i, p); |
119 | for (i++; i < ARRAY_SIZE(mi->groups); i++) | ||
111 | p = minstrel_ht_stats_dump(mi, i, p); | 120 | p = minstrel_ht_stats_dump(mi, i, p); |
112 | 121 | ||
113 | p += sprintf(p, "\nTotal packet count:: ideal %d " | 122 | p += sprintf(p, "\nTotal packet count:: ideal %d " |
@@ -119,7 +128,7 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) | |||
119 | MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); | 128 | MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); |
120 | ms->len = p - ms->buf; | 129 | ms->len = p - ms->buf; |
121 | 130 | ||
122 | WARN_ON(ms->len + sizeof(*ms) > 8192); | 131 | WARN_ON(ms->len + sizeof(*ms) > 32768); |
123 | 132 | ||
124 | return nonseekable_open(inode, file); | 133 | return nonseekable_open(inode, file); |
125 | } | 134 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b04ca4049c95..bc63aa0c5401 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1032,6 +1032,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
1032 | ieee80211_is_pspoll(hdr->frame_control)) && | 1032 | ieee80211_is_pspoll(hdr->frame_control)) && |
1033 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && | 1033 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && |
1034 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && | 1034 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && |
1035 | rx->sdata->vif.type != NL80211_IFTYPE_OCB && | ||
1035 | (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { | 1036 | (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { |
1036 | /* | 1037 | /* |
1037 | * accept port control frames from the AP even when it's not | 1038 | * accept port control frames from the AP even when it's not |
@@ -1272,6 +1273,12 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1272 | sta->last_rx_rate_vht_nss = status->vht_nss; | 1273 | sta->last_rx_rate_vht_nss = status->vht_nss; |
1273 | } | 1274 | } |
1274 | } | 1275 | } |
1276 | } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) { | ||
1277 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, | ||
1278 | NL80211_IFTYPE_OCB); | ||
1279 | /* OCB uses wild-card BSSID */ | ||
1280 | if (is_broadcast_ether_addr(bssid)) | ||
1281 | sta->last_rx = jiffies; | ||
1275 | } else if (!is_multicast_ether_addr(hdr->addr1)) { | 1282 | } else if (!is_multicast_ether_addr(hdr->addr1)) { |
1276 | /* | 1283 | /* |
1277 | * Mesh beacons will update last_rx when if they are found to | 1284 | * Mesh beacons will update last_rx when if they are found to |
@@ -2820,6 +2827,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
2820 | 2827 | ||
2821 | if (!ieee80211_vif_is_mesh(&sdata->vif) && | 2828 | if (!ieee80211_vif_is_mesh(&sdata->vif) && |
2822 | sdata->vif.type != NL80211_IFTYPE_ADHOC && | 2829 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
2830 | sdata->vif.type != NL80211_IFTYPE_OCB && | ||
2823 | sdata->vif.type != NL80211_IFTYPE_STATION) | 2831 | sdata->vif.type != NL80211_IFTYPE_STATION) |
2824 | return RX_DROP_MONITOR; | 2832 | return RX_DROP_MONITOR; |
2825 | 2833 | ||
@@ -3130,6 +3138,33 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
3130 | BIT(rate_idx)); | 3138 | BIT(rate_idx)); |
3131 | } | 3139 | } |
3132 | break; | 3140 | break; |
3141 | case NL80211_IFTYPE_OCB: | ||
3142 | if (!bssid) | ||
3143 | return false; | ||
3144 | if (ieee80211_is_beacon(hdr->frame_control)) { | ||
3145 | return false; | ||
3146 | } else if (!is_broadcast_ether_addr(bssid)) { | ||
3147 | ocb_dbg(sdata, "BSSID mismatch in OCB mode!\n"); | ||
3148 | return false; | ||
3149 | } else if (!multicast && | ||
3150 | !ether_addr_equal(sdata->dev->dev_addr, | ||
3151 | hdr->addr1)) { | ||
3152 | /* if we are in promisc mode we also accept | ||
3153 | * packets not destined for us | ||
3154 | */ | ||
3155 | if (!(sdata->dev->flags & IFF_PROMISC)) | ||
3156 | return false; | ||
3157 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | ||
3158 | } else if (!rx->sta) { | ||
3159 | int rate_idx; | ||
3160 | if (status->flag & RX_FLAG_HT) | ||
3161 | rate_idx = 0; /* TODO: HT rates */ | ||
3162 | else | ||
3163 | rate_idx = status->rate_idx; | ||
3164 | ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2, | ||
3165 | BIT(rate_idx)); | ||
3166 | } | ||
3167 | break; | ||
3133 | case NL80211_IFTYPE_MESH_POINT: | 3168 | case NL80211_IFTYPE_MESH_POINT: |
3134 | if (!multicast && | 3169 | if (!multicast && |
3135 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { | 3170 | !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index de494df3bab8..adc25371b171 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -501,7 +501,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
501 | /* make the station visible */ | 501 | /* make the station visible */ |
502 | sta_info_hash_add(local, sta); | 502 | sta_info_hash_add(local, sta); |
503 | 503 | ||
504 | list_add_rcu(&sta->list, &local->sta_list); | 504 | list_add_tail_rcu(&sta->list, &local->sta_list); |
505 | 505 | ||
506 | /* notify driver */ | 506 | /* notify driver */ |
507 | err = sta_info_insert_drv_state(local, sdata, sta); | 507 | err = sta_info_insert_drv_state(local, sdata, sta); |
@@ -1531,7 +1531,7 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta) | |||
1531 | break; | 1531 | break; |
1532 | case 0: | 1532 | case 0: |
1533 | /* XXX: what is a good value? */ | 1533 | /* XXX: what is a good value? */ |
1534 | n_frames = 8; | 1534 | n_frames = 128; |
1535 | break; | 1535 | break; |
1536 | } | 1536 | } |
1537 | 1537 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 89290e33dafe..9612d89fad56 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -704,7 +704,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
704 | 704 | ||
705 | if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && | 705 | if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) && |
706 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) | 706 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) |
707 | ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked); | 707 | ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, |
708 | acked, info->status.tx_time); | ||
708 | 709 | ||
709 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | 710 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { |
710 | if (info->flags & IEEE80211_TX_STAT_ACK) { | 711 | if (info->flags & IEEE80211_TX_STAT_ACK) { |
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 4ea25dec0698..b4f368e2cb3b 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c | |||
@@ -562,8 +562,10 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
562 | /* infer the initiator if we can, to support old userspace */ | 562 | /* infer the initiator if we can, to support old userspace */ |
563 | switch (action_code) { | 563 | switch (action_code) { |
564 | case WLAN_TDLS_SETUP_REQUEST: | 564 | case WLAN_TDLS_SETUP_REQUEST: |
565 | if (sta) | 565 | if (sta) { |
566 | set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); | 566 | set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); |
567 | sta->sta.tdls_initiator = false; | ||
568 | } | ||
567 | /* fall-through */ | 569 | /* fall-through */ |
568 | case WLAN_TDLS_SETUP_CONFIRM: | 570 | case WLAN_TDLS_SETUP_CONFIRM: |
569 | case WLAN_TDLS_DISCOVERY_REQUEST: | 571 | case WLAN_TDLS_DISCOVERY_REQUEST: |
@@ -575,8 +577,10 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, | |||
575 | * Make the last packet sent take effect for the initiator | 577 | * Make the last packet sent take effect for the initiator |
576 | * value. | 578 | * value. |
577 | */ | 579 | */ |
578 | if (sta) | 580 | if (sta) { |
579 | clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); | 581 | clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR); |
582 | sta->sta.tdls_initiator = true; | ||
583 | } | ||
580 | /* fall-through */ | 584 | /* fall-through */ |
581 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: | 585 | case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: |
582 | initiator = false; | 586 | initiator = false; |
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 38fae7ebe984..809a4983eb4a 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h | |||
@@ -987,29 +987,34 @@ TRACE_EVENT(drv_flush, | |||
987 | 987 | ||
988 | TRACE_EVENT(drv_channel_switch, | 988 | TRACE_EVENT(drv_channel_switch, |
989 | TP_PROTO(struct ieee80211_local *local, | 989 | TP_PROTO(struct ieee80211_local *local, |
990 | struct ieee80211_sub_if_data *sdata, | ||
990 | struct ieee80211_channel_switch *ch_switch), | 991 | struct ieee80211_channel_switch *ch_switch), |
991 | 992 | ||
992 | TP_ARGS(local, ch_switch), | 993 | TP_ARGS(local, sdata, ch_switch), |
993 | 994 | ||
994 | TP_STRUCT__entry( | 995 | TP_STRUCT__entry( |
995 | LOCAL_ENTRY | 996 | LOCAL_ENTRY |
997 | VIF_ENTRY | ||
996 | CHANDEF_ENTRY | 998 | CHANDEF_ENTRY |
997 | __field(u64, timestamp) | 999 | __field(u64, timestamp) |
1000 | __field(u32, device_timestamp) | ||
998 | __field(bool, block_tx) | 1001 | __field(bool, block_tx) |
999 | __field(u8, count) | 1002 | __field(u8, count) |
1000 | ), | 1003 | ), |
1001 | 1004 | ||
1002 | TP_fast_assign( | 1005 | TP_fast_assign( |
1003 | LOCAL_ASSIGN; | 1006 | LOCAL_ASSIGN; |
1007 | VIF_ASSIGN; | ||
1004 | CHANDEF_ASSIGN(&ch_switch->chandef) | 1008 | CHANDEF_ASSIGN(&ch_switch->chandef) |
1005 | __entry->timestamp = ch_switch->timestamp; | 1009 | __entry->timestamp = ch_switch->timestamp; |
1010 | __entry->device_timestamp = ch_switch->device_timestamp; | ||
1006 | __entry->block_tx = ch_switch->block_tx; | 1011 | __entry->block_tx = ch_switch->block_tx; |
1007 | __entry->count = ch_switch->count; | 1012 | __entry->count = ch_switch->count; |
1008 | ), | 1013 | ), |
1009 | 1014 | ||
1010 | TP_printk( | 1015 | TP_printk( |
1011 | LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d", | 1016 | LOCAL_PR_FMT VIF_PR_FMT " new " CHANDEF_PR_FMT " count:%d", |
1012 | LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count | 1017 | LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count |
1013 | ) | 1018 | ) |
1014 | ); | 1019 | ); |
1015 | 1020 | ||
@@ -1557,9 +1562,26 @@ DEFINE_EVENT(local_sdata_evt, drv_stop_ap, | |||
1557 | TP_ARGS(local, sdata) | 1562 | TP_ARGS(local, sdata) |
1558 | ); | 1563 | ); |
1559 | 1564 | ||
1560 | DEFINE_EVENT(local_only_evt, drv_restart_complete, | 1565 | TRACE_EVENT(drv_reconfig_complete, |
1561 | TP_PROTO(struct ieee80211_local *local), | 1566 | TP_PROTO(struct ieee80211_local *local, |
1562 | TP_ARGS(local) | 1567 | enum ieee80211_reconfig_type reconfig_type), |
1568 | TP_ARGS(local, reconfig_type), | ||
1569 | |||
1570 | TP_STRUCT__entry( | ||
1571 | LOCAL_ENTRY | ||
1572 | __field(u8, reconfig_type) | ||
1573 | ), | ||
1574 | |||
1575 | TP_fast_assign( | ||
1576 | LOCAL_ASSIGN; | ||
1577 | __entry->reconfig_type = reconfig_type; | ||
1578 | ), | ||
1579 | |||
1580 | TP_printk( | ||
1581 | LOCAL_PR_FMT " reconfig_type:%d", | ||
1582 | LOCAL_PR_ARG, __entry->reconfig_type | ||
1583 | ) | ||
1584 | |||
1563 | ); | 1585 | ); |
1564 | 1586 | ||
1565 | #if IS_ENABLED(CONFIG_IPV6) | 1587 | #if IS_ENABLED(CONFIG_IPV6) |
@@ -2106,6 +2128,72 @@ TRACE_EVENT(drv_channel_switch_beacon, | |||
2106 | ) | 2128 | ) |
2107 | ); | 2129 | ); |
2108 | 2130 | ||
2131 | TRACE_EVENT(drv_pre_channel_switch, | ||
2132 | TP_PROTO(struct ieee80211_local *local, | ||
2133 | struct ieee80211_sub_if_data *sdata, | ||
2134 | struct ieee80211_channel_switch *ch_switch), | ||
2135 | |||
2136 | TP_ARGS(local, sdata, ch_switch), | ||
2137 | |||
2138 | TP_STRUCT__entry( | ||
2139 | LOCAL_ENTRY | ||
2140 | VIF_ENTRY | ||
2141 | CHANDEF_ENTRY | ||
2142 | __field(u64, timestamp) | ||
2143 | __field(bool, block_tx) | ||
2144 | __field(u8, count) | ||
2145 | ), | ||
2146 | |||
2147 | TP_fast_assign( | ||
2148 | LOCAL_ASSIGN; | ||
2149 | VIF_ASSIGN; | ||
2150 | CHANDEF_ASSIGN(&ch_switch->chandef) | ||
2151 | __entry->timestamp = ch_switch->timestamp; | ||
2152 | __entry->block_tx = ch_switch->block_tx; | ||
2153 | __entry->count = ch_switch->count; | ||
2154 | ), | ||
2155 | |||
2156 | TP_printk( | ||
2157 | LOCAL_PR_FMT VIF_PR_FMT " prepare channel switch to " | ||
2158 | CHANDEF_PR_FMT " count:%d block_tx:%d timestamp:%llu", | ||
2159 | LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count, | ||
2160 | __entry->block_tx, __entry->timestamp | ||
2161 | ) | ||
2162 | ); | ||
2163 | |||
2164 | DEFINE_EVENT(local_sdata_evt, drv_post_channel_switch, | ||
2165 | TP_PROTO(struct ieee80211_local *local, | ||
2166 | struct ieee80211_sub_if_data *sdata), | ||
2167 | TP_ARGS(local, sdata) | ||
2168 | ); | ||
2169 | |||
2170 | TRACE_EVENT(drv_get_txpower, | ||
2171 | TP_PROTO(struct ieee80211_local *local, | ||
2172 | struct ieee80211_sub_if_data *sdata, | ||
2173 | int dbm, int ret), | ||
2174 | |||
2175 | TP_ARGS(local, sdata, dbm, ret), | ||
2176 | |||
2177 | TP_STRUCT__entry( | ||
2178 | LOCAL_ENTRY | ||
2179 | VIF_ENTRY | ||
2180 | __field(int, dbm) | ||
2181 | __field(int, ret) | ||
2182 | ), | ||
2183 | |||
2184 | TP_fast_assign( | ||
2185 | LOCAL_ASSIGN; | ||
2186 | VIF_ASSIGN; | ||
2187 | __entry->dbm = dbm; | ||
2188 | __entry->ret = ret; | ||
2189 | ), | ||
2190 | |||
2191 | TP_printk( | ||
2192 | LOCAL_PR_FMT VIF_PR_FMT " dbm:%d ret:%d", | ||
2193 | LOCAL_PR_ARG, VIF_PR_ARG, __entry->dbm, __entry->ret | ||
2194 | ) | ||
2195 | ); | ||
2196 | |||
2109 | 2197 | ||
2110 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING | 2198 | #ifdef CONFIG_MAC80211_MESSAGE_TRACING |
2111 | #undef TRACE_SYSTEM | 2199 | #undef TRACE_SYSTEM |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 900632a250ec..3ffd91f295a6 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -296,6 +296,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | |||
296 | */ | 296 | */ |
297 | return TX_DROP; | 297 | return TX_DROP; |
298 | 298 | ||
299 | if (tx->sdata->vif.type == NL80211_IFTYPE_OCB) | ||
300 | return TX_CONTINUE; | ||
301 | |||
299 | if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) | 302 | if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) |
300 | return TX_CONTINUE; | 303 | return TX_CONTINUE; |
301 | 304 | ||
@@ -2013,6 +2016,17 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2013 | goto fail_rcu; | 2016 | goto fail_rcu; |
2014 | band = chanctx_conf->def.chan->band; | 2017 | band = chanctx_conf->def.chan->band; |
2015 | break; | 2018 | break; |
2019 | case NL80211_IFTYPE_OCB: | ||
2020 | /* DA SA BSSID */ | ||
2021 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||
2022 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
2023 | eth_broadcast_addr(hdr.addr3); | ||
2024 | hdrlen = 24; | ||
2025 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
2026 | if (!chanctx_conf) | ||
2027 | goto fail_rcu; | ||
2028 | band = chanctx_conf->def.chan->band; | ||
2029 | break; | ||
2016 | case NL80211_IFTYPE_ADHOC: | 2030 | case NL80211_IFTYPE_ADHOC: |
2017 | /* DA SA BSSID */ | 2031 | /* DA SA BSSID */ |
2018 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 2032 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -2057,6 +2071,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
2057 | * EAPOL frames from the local station. | 2071 | * EAPOL frames from the local station. |
2058 | */ | 2072 | */ |
2059 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && | 2073 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && |
2074 | (sdata->vif.type != NL80211_IFTYPE_OCB) && | ||
2060 | !multicast && !authorized && | 2075 | !multicast && !authorized && |
2061 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || | 2076 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || |
2062 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { | 2077 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3c61060a4d2b..f9319a5dca64 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -693,6 +693,34 @@ void ieee80211_iterate_active_interfaces_rtnl( | |||
693 | } | 693 | } |
694 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); | 694 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl); |
695 | 695 | ||
696 | static void __iterate_stations(struct ieee80211_local *local, | ||
697 | void (*iterator)(void *data, | ||
698 | struct ieee80211_sta *sta), | ||
699 | void *data) | ||
700 | { | ||
701 | struct sta_info *sta; | ||
702 | |||
703 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
704 | if (!sta->uploaded) | ||
705 | continue; | ||
706 | |||
707 | iterator(data, &sta->sta); | ||
708 | } | ||
709 | } | ||
710 | |||
711 | void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw, | ||
712 | void (*iterator)(void *data, | ||
713 | struct ieee80211_sta *sta), | ||
714 | void *data) | ||
715 | { | ||
716 | struct ieee80211_local *local = hw_to_local(hw); | ||
717 | |||
718 | rcu_read_lock(); | ||
719 | __iterate_stations(local, iterator, data); | ||
720 | rcu_read_unlock(); | ||
721 | } | ||
722 | EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_atomic); | ||
723 | |||
696 | struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev) | 724 | struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev) |
697 | { | 725 | { |
698 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | 726 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
@@ -1073,6 +1101,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1073 | struct ieee80211_chanctx_conf *chanctx_conf; | 1101 | struct ieee80211_chanctx_conf *chanctx_conf; |
1074 | int ac; | 1102 | int ac; |
1075 | bool use_11b, enable_qos; | 1103 | bool use_11b, enable_qos; |
1104 | bool is_ocb; /* Use another EDCA parameters if dot11OCBActivated=true */ | ||
1076 | int aCWmin, aCWmax; | 1105 | int aCWmin, aCWmax; |
1077 | 1106 | ||
1078 | if (!local->ops->conf_tx) | 1107 | if (!local->ops->conf_tx) |
@@ -1097,6 +1126,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1097 | */ | 1126 | */ |
1098 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); | 1127 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); |
1099 | 1128 | ||
1129 | is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB); | ||
1130 | |||
1100 | /* Set defaults according to 802.11-2007 Table 7-37 */ | 1131 | /* Set defaults according to 802.11-2007 Table 7-37 */ |
1101 | aCWmax = 1023; | 1132 | aCWmax = 1023; |
1102 | if (use_11b) | 1133 | if (use_11b) |
@@ -1118,7 +1149,10 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1118 | qparam.cw_max = aCWmax; | 1149 | qparam.cw_max = aCWmax; |
1119 | qparam.cw_min = aCWmin; | 1150 | qparam.cw_min = aCWmin; |
1120 | qparam.txop = 0; | 1151 | qparam.txop = 0; |
1121 | qparam.aifs = 7; | 1152 | if (is_ocb) |
1153 | qparam.aifs = 9; | ||
1154 | else | ||
1155 | qparam.aifs = 7; | ||
1122 | break; | 1156 | break; |
1123 | /* never happens but let's not leave undefined */ | 1157 | /* never happens but let's not leave undefined */ |
1124 | default: | 1158 | default: |
@@ -1126,21 +1160,32 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata, | |||
1126 | qparam.cw_max = aCWmax; | 1160 | qparam.cw_max = aCWmax; |
1127 | qparam.cw_min = aCWmin; | 1161 | qparam.cw_min = aCWmin; |
1128 | qparam.txop = 0; | 1162 | qparam.txop = 0; |
1129 | qparam.aifs = 3; | 1163 | if (is_ocb) |
1164 | qparam.aifs = 6; | ||
1165 | else | ||
1166 | qparam.aifs = 3; | ||
1130 | break; | 1167 | break; |
1131 | case IEEE80211_AC_VI: | 1168 | case IEEE80211_AC_VI: |
1132 | qparam.cw_max = aCWmin; | 1169 | qparam.cw_max = aCWmin; |
1133 | qparam.cw_min = (aCWmin + 1) / 2 - 1; | 1170 | qparam.cw_min = (aCWmin + 1) / 2 - 1; |
1134 | if (use_11b) | 1171 | if (is_ocb) |
1172 | qparam.txop = 0; | ||
1173 | else if (use_11b) | ||
1135 | qparam.txop = 6016/32; | 1174 | qparam.txop = 6016/32; |
1136 | else | 1175 | else |
1137 | qparam.txop = 3008/32; | 1176 | qparam.txop = 3008/32; |
1138 | qparam.aifs = 2; | 1177 | |
1178 | if (is_ocb) | ||
1179 | qparam.aifs = 3; | ||
1180 | else | ||
1181 | qparam.aifs = 2; | ||
1139 | break; | 1182 | break; |
1140 | case IEEE80211_AC_VO: | 1183 | case IEEE80211_AC_VO: |
1141 | qparam.cw_max = (aCWmin + 1) / 2 - 1; | 1184 | qparam.cw_max = (aCWmin + 1) / 2 - 1; |
1142 | qparam.cw_min = (aCWmin + 1) / 4 - 1; | 1185 | qparam.cw_min = (aCWmin + 1) / 4 - 1; |
1143 | if (use_11b) | 1186 | if (is_ocb) |
1187 | qparam.txop = 0; | ||
1188 | else if (use_11b) | ||
1144 | qparam.txop = 3264/32; | 1189 | qparam.txop = 3264/32; |
1145 | else | 1190 | else |
1146 | qparam.txop = 1504/32; | 1191 | qparam.txop = 1504/32; |
@@ -1813,6 +1858,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1813 | ieee80211_bss_info_change_notify(sdata, changed); | 1858 | ieee80211_bss_info_change_notify(sdata, changed); |
1814 | sdata_unlock(sdata); | 1859 | sdata_unlock(sdata); |
1815 | break; | 1860 | break; |
1861 | case NL80211_IFTYPE_OCB: | ||
1862 | changed |= BSS_CHANGED_OCB; | ||
1863 | ieee80211_bss_info_change_notify(sdata, changed); | ||
1864 | break; | ||
1816 | case NL80211_IFTYPE_ADHOC: | 1865 | case NL80211_IFTYPE_ADHOC: |
1817 | changed |= BSS_CHANGED_IBSS; | 1866 | changed |= BSS_CHANGED_IBSS; |
1818 | /* fall through */ | 1867 | /* fall through */ |
@@ -1949,7 +1998,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1949 | * We may want to change that later, however. | 1998 | * We may want to change that later, however. |
1950 | */ | 1999 | */ |
1951 | if (!local->suspended || reconfig_due_to_wowlan) | 2000 | if (!local->suspended || reconfig_due_to_wowlan) |
1952 | drv_restart_complete(local); | 2001 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART); |
1953 | 2002 | ||
1954 | if (!local->suspended) | 2003 | if (!local->suspended) |
1955 | return 0; | 2004 | return 0; |
@@ -1960,6 +2009,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1960 | mb(); | 2009 | mb(); |
1961 | local->resuming = false; | 2010 | local->resuming = false; |
1962 | 2011 | ||
2012 | if (!reconfig_due_to_wowlan) | ||
2013 | drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND); | ||
2014 | |||
1963 | list_for_each_entry(sdata, &local->interfaces, list) { | 2015 | list_for_each_entry(sdata, &local->interfaces, list) { |
1964 | if (!ieee80211_sdata_running(sdata)) | 2016 | if (!ieee80211_sdata_running(sdata)) |
1965 | continue; | 2017 | continue; |
@@ -2052,42 +2104,36 @@ static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | |||
2052 | return false; | 2104 | return false; |
2053 | } | 2105 | } |
2054 | 2106 | ||
2055 | /** | 2107 | size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, |
2056 | * ieee80211_ie_split - split an IE buffer according to ordering | 2108 | const u8 *ids, int n_ids, |
2057 | * | 2109 | const u8 *after_ric, int n_after_ric, |
2058 | * @ies: the IE buffer | 2110 | size_t offset) |
2059 | * @ielen: the length of the IE buffer | ||
2060 | * @ids: an array with element IDs that are allowed before | ||
2061 | * the split | ||
2062 | * @n_ids: the size of the element ID array | ||
2063 | * @offset: offset where to start splitting in the buffer | ||
2064 | * | ||
2065 | * This function splits an IE buffer by updating the @offset | ||
2066 | * variable to point to the location where the buffer should be | ||
2067 | * split. | ||
2068 | * | ||
2069 | * It assumes that the given IE buffer is well-formed, this | ||
2070 | * has to be guaranteed by the caller! | ||
2071 | * | ||
2072 | * It also assumes that the IEs in the buffer are ordered | ||
2073 | * correctly, if not the result of using this function will not | ||
2074 | * be ordered correctly either, i.e. it does no reordering. | ||
2075 | * | ||
2076 | * The function returns the offset where the next part of the | ||
2077 | * buffer starts, which may be @ielen if the entire (remainder) | ||
2078 | * of the buffer should be used. | ||
2079 | */ | ||
2080 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
2081 | const u8 *ids, int n_ids, size_t offset) | ||
2082 | { | 2111 | { |
2083 | size_t pos = offset; | 2112 | size_t pos = offset; |
2084 | 2113 | ||
2085 | while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) | 2114 | while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) { |
2086 | pos += 2 + ies[pos + 1]; | 2115 | if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) { |
2116 | pos += 2 + ies[pos + 1]; | ||
2117 | |||
2118 | while (pos < ielen && | ||
2119 | !ieee80211_id_in_list(after_ric, n_after_ric, | ||
2120 | ies[pos])) | ||
2121 | pos += 2 + ies[pos + 1]; | ||
2122 | } else { | ||
2123 | pos += 2 + ies[pos + 1]; | ||
2124 | } | ||
2125 | } | ||
2087 | 2126 | ||
2088 | return pos; | 2127 | return pos; |
2089 | } | 2128 | } |
2090 | 2129 | ||
2130 | size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||
2131 | const u8 *ids, int n_ids, size_t offset) | ||
2132 | { | ||
2133 | return ieee80211_ie_split_ric(ies, ielen, ids, n_ids, NULL, 0, offset); | ||
2134 | } | ||
2135 | EXPORT_SYMBOL(ieee80211_ie_split); | ||
2136 | |||
2091 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) | 2137 | size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) |
2092 | { | 2138 | { |
2093 | size_t pos = offset; | 2139 | size_t pos = offset; |
@@ -2526,11 +2572,23 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work) | |||
2526 | struct ieee80211_local *local = | 2572 | struct ieee80211_local *local = |
2527 | container_of(work, struct ieee80211_local, radar_detected_work); | 2573 | container_of(work, struct ieee80211_local, radar_detected_work); |
2528 | struct cfg80211_chan_def chandef = local->hw.conf.chandef; | 2574 | struct cfg80211_chan_def chandef = local->hw.conf.chandef; |
2575 | struct ieee80211_chanctx *ctx; | ||
2576 | int num_chanctx = 0; | ||
2577 | |||
2578 | mutex_lock(&local->chanctx_mtx); | ||
2579 | list_for_each_entry(ctx, &local->chanctx_list, list) { | ||
2580 | if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER) | ||
2581 | continue; | ||
2582 | |||
2583 | num_chanctx++; | ||
2584 | chandef = ctx->conf.def; | ||
2585 | } | ||
2586 | mutex_unlock(&local->chanctx_mtx); | ||
2529 | 2587 | ||
2530 | ieee80211_dfs_cac_cancel(local); | 2588 | ieee80211_dfs_cac_cancel(local); |
2531 | 2589 | ||
2532 | if (local->use_chanctx) | 2590 | if (num_chanctx > 1) |
2533 | /* currently not handled */ | 2591 | /* XXX: multi-channel is not supported yet */ |
2534 | WARN_ON(1); | 2592 | WARN_ON(1); |
2535 | else | 2593 | else |
2536 | cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); | 2594 | cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL); |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 9181fb6d6437..a4220e92f0cc 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -111,8 +111,6 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, | |||
111 | (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) | 111 | (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) |
112 | return newhdr + hdrlen; | 112 | return newhdr + hdrlen; |
113 | 113 | ||
114 | skb_set_network_header(skb, skb_network_offset(skb) + | ||
115 | IEEE80211_WEP_IV_LEN); | ||
116 | ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); | 114 | ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); |
117 | return newhdr + hdrlen; | 115 | return newhdr + hdrlen; |
118 | } | 116 | } |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 3b873989992c..fdf52db95b33 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -54,10 +54,18 @@ static int wme_downgrade_ac(struct sk_buff *skb) | |||
54 | } | 54 | } |
55 | 55 | ||
56 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, | 56 | static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, |
57 | struct sk_buff *skb) | 57 | struct sta_info *sta, struct sk_buff *skb) |
58 | { | 58 | { |
59 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
60 | |||
59 | /* in case we are a client verify acm is not set for this ac */ | 61 | /* in case we are a client verify acm is not set for this ac */ |
60 | while (unlikely(sdata->wmm_acm & BIT(skb->priority))) { | 62 | while (sdata->wmm_acm & BIT(skb->priority)) { |
63 | int ac = ieee802_1d_to_ac[skb->priority]; | ||
64 | |||
65 | if (ifmgd->tx_tspec[ac].admitted_time && | ||
66 | skb->priority == ifmgd->tx_tspec[ac].up) | ||
67 | return ac; | ||
68 | |||
61 | if (wme_downgrade_ac(skb)) { | 69 | if (wme_downgrade_ac(skb)) { |
62 | /* | 70 | /* |
63 | * This should not really happen. The AP has marked all | 71 | * This should not really happen. The AP has marked all |
@@ -96,7 +104,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, | |||
96 | p = ieee80211_get_qos_ctl(hdr); | 104 | p = ieee80211_get_qos_ctl(hdr); |
97 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; | 105 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; |
98 | 106 | ||
99 | return ieee80211_downgrade_queue(sdata, skb); | 107 | return ieee80211_downgrade_queue(sdata, NULL, skb); |
100 | } | 108 | } |
101 | 109 | ||
102 | /* Indicate which queue to use. */ | 110 | /* Indicate which queue to use. */ |
@@ -108,6 +116,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
108 | const u8 *ra = NULL; | 116 | const u8 *ra = NULL; |
109 | bool qos = false; | 117 | bool qos = false; |
110 | struct mac80211_qos_map *qos_map; | 118 | struct mac80211_qos_map *qos_map; |
119 | u16 ret; | ||
111 | 120 | ||
112 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { | 121 | if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) { |
113 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 122 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
@@ -139,6 +148,10 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
139 | case NL80211_IFTYPE_ADHOC: | 148 | case NL80211_IFTYPE_ADHOC: |
140 | ra = skb->data; | 149 | ra = skb->data; |
141 | break; | 150 | break; |
151 | case NL80211_IFTYPE_OCB: | ||
152 | /* all stations are required to support WME */ | ||
153 | qos = true; | ||
154 | break; | ||
142 | default: | 155 | default: |
143 | break; | 156 | break; |
144 | } | 157 | } |
@@ -148,27 +161,29 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
148 | if (sta) | 161 | if (sta) |
149 | qos = sta->sta.wme; | 162 | qos = sta->sta.wme; |
150 | } | 163 | } |
151 | rcu_read_unlock(); | ||
152 | 164 | ||
153 | if (!qos) { | 165 | if (!qos) { |
154 | skb->priority = 0; /* required for correct WPA/11i MIC */ | 166 | skb->priority = 0; /* required for correct WPA/11i MIC */ |
155 | return IEEE80211_AC_BE; | 167 | ret = IEEE80211_AC_BE; |
168 | goto out; | ||
156 | } | 169 | } |
157 | 170 | ||
158 | if (skb->protocol == sdata->control_port_protocol) { | 171 | if (skb->protocol == sdata->control_port_protocol) { |
159 | skb->priority = 7; | 172 | skb->priority = 7; |
160 | return ieee80211_downgrade_queue(sdata, skb); | 173 | goto downgrade; |
161 | } | 174 | } |
162 | 175 | ||
163 | /* use the data classifier to determine what 802.1d tag the | 176 | /* use the data classifier to determine what 802.1d tag the |
164 | * data frame has */ | 177 | * data frame has */ |
165 | rcu_read_lock(); | ||
166 | qos_map = rcu_dereference(sdata->qos_map); | 178 | qos_map = rcu_dereference(sdata->qos_map); |
167 | skb->priority = cfg80211_classify8021d(skb, qos_map ? | 179 | skb->priority = cfg80211_classify8021d(skb, qos_map ? |
168 | &qos_map->qos_map : NULL); | 180 | &qos_map->qos_map : NULL); |
169 | rcu_read_unlock(); | ||
170 | 181 | ||
171 | return ieee80211_downgrade_queue(sdata, skb); | 182 | downgrade: |
183 | ret = ieee80211_downgrade_queue(sdata, sta, skb); | ||
184 | out: | ||
185 | rcu_read_unlock(); | ||
186 | return ret; | ||
172 | } | 187 | } |
173 | 188 | ||
174 | /** | 189 | /** |
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 7fea4bb8acbc..80151edc5195 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h | |||
@@ -13,8 +13,6 @@ | |||
13 | #include <linux/netdevice.h> | 13 | #include <linux/netdevice.h> |
14 | #include "ieee80211_i.h" | 14 | #include "ieee80211_i.h" |
15 | 15 | ||
16 | extern const int ieee802_1d_to_ac[8]; | ||
17 | |||
18 | u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, | 16 | u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, |
19 | struct sk_buff *skb, | 17 | struct sk_buff *skb, |
20 | struct ieee80211_hdr *hdr); | 18 | struct ieee80211_hdr *hdr); |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 983527a4c1ab..12398fde02e8 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -209,8 +209,6 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
209 | 209 | ||
210 | pos = skb_push(skb, IEEE80211_TKIP_IV_LEN); | 210 | pos = skb_push(skb, IEEE80211_TKIP_IV_LEN); |
211 | memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen); | 211 | memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen); |
212 | skb_set_network_header(skb, skb_network_offset(skb) + | ||
213 | IEEE80211_TKIP_IV_LEN); | ||
214 | pos += hdrlen; | 212 | pos += hdrlen; |
215 | 213 | ||
216 | /* the HW only needs room for the IV, but not the actual IV */ | 214 | /* the HW only needs room for the IV, but not the actual IV */ |
@@ -434,8 +432,6 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
434 | 432 | ||
435 | pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN); | 433 | pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN); |
436 | memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen); | 434 | memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen); |
437 | skb_set_network_header(skb, skb_network_offset(skb) + | ||
438 | IEEE80211_CCMP_HDR_LEN); | ||
439 | 435 | ||
440 | /* the HW only needs room for the IV, but not the actual IV */ | 436 | /* the HW only needs room for the IV, but not the actual IV */ |
441 | if (info->control.hw_key && | 437 | if (info->control.hw_key && |
@@ -575,7 +571,6 @@ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx, | |||
575 | 571 | ||
576 | pos = skb_push(skb, cs->hdr_len); | 572 | pos = skb_push(skb, cs->hdr_len); |
577 | memmove(pos, pos + cs->hdr_len, hdrlen); | 573 | memmove(pos, pos + cs->hdr_len, hdrlen); |
578 | skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len); | ||
579 | 574 | ||
580 | return TX_CONTINUE; | 575 | return TX_CONTINUE; |
581 | } | 576 | } |
diff --git a/net/mac802154/Kconfig b/net/mac802154/Kconfig index 1818a99b3081..aa462b480a39 100644 --- a/net/mac802154/Kconfig +++ b/net/mac802154/Kconfig | |||
@@ -16,5 +16,5 @@ config MAC802154 | |||
16 | been tested yet! | 16 | been tested yet! |
17 | 17 | ||
18 | If you plan to use HardMAC IEEE 802.15.4 devices, you can | 18 | If you plan to use HardMAC IEEE 802.15.4 devices, you can |
19 | say N here. Alternatievly you can say M to compile it as | 19 | say N here. Alternatively you can say M to compile it as |
20 | module. | 20 | module. |
diff --git a/net/mac802154/Makefile b/net/mac802154/Makefile index 9723d6f3f3e5..2e497d0c829a 100644 --- a/net/mac802154/Makefile +++ b/net/mac802154/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | obj-$(CONFIG_MAC802154) += mac802154.o | 1 | obj-$(CONFIG_MAC802154) += mac802154.o |
2 | mac802154-objs := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o \ | 2 | mac802154-objs := main.o rx.o tx.o mac_cmd.o mib.o \ |
3 | monitor.o wpan.o llsec.o | 3 | iface.o llsec.o util.o |
4 | 4 | ||
5 | ccflags-y += -D__CHECK_ENDIAN__ | 5 | ccflags-y += -D__CHECK_ENDIAN__ |
diff --git a/net/mac802154/driver-ops.h b/net/mac802154/driver-ops.h new file mode 100644 index 000000000000..dfd29ffb8fee --- /dev/null +++ b/net/mac802154/driver-ops.h | |||
@@ -0,0 +1,226 @@ | |||
1 | #ifndef __MAC802154_DRVIER_OPS | ||
2 | #define __MAC802154_DRIVER_OPS | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <linux/rtnetlink.h> | ||
6 | |||
7 | #include <net/mac802154.h> | ||
8 | |||
9 | #include "ieee802154_i.h" | ||
10 | |||
11 | static inline int | ||
12 | drv_xmit_async(struct ieee802154_local *local, struct sk_buff *skb) | ||
13 | { | ||
14 | return local->ops->xmit_async(&local->hw, skb); | ||
15 | } | ||
16 | |||
17 | static inline int | ||
18 | drv_xmit_sync(struct ieee802154_local *local, struct sk_buff *skb) | ||
19 | { | ||
20 | /* don't allow other operations while sync xmit */ | ||
21 | ASSERT_RTNL(); | ||
22 | |||
23 | might_sleep(); | ||
24 | |||
25 | return local->ops->xmit_sync(&local->hw, skb); | ||
26 | } | ||
27 | |||
28 | static inline int drv_start(struct ieee802154_local *local) | ||
29 | { | ||
30 | might_sleep(); | ||
31 | |||
32 | local->started = true; | ||
33 | smp_mb(); | ||
34 | |||
35 | return local->ops->start(&local->hw); | ||
36 | } | ||
37 | |||
38 | static inline void drv_stop(struct ieee802154_local *local) | ||
39 | { | ||
40 | might_sleep(); | ||
41 | |||
42 | local->ops->stop(&local->hw); | ||
43 | |||
44 | /* sync away all work on the tasklet before clearing started */ | ||
45 | tasklet_disable(&local->tasklet); | ||
46 | tasklet_enable(&local->tasklet); | ||
47 | |||
48 | barrier(); | ||
49 | |||
50 | local->started = false; | ||
51 | } | ||
52 | |||
53 | static inline int drv_set_channel(struct ieee802154_local *local, | ||
54 | const u8 page, const u8 channel) | ||
55 | { | ||
56 | might_sleep(); | ||
57 | |||
58 | return local->ops->set_channel(&local->hw, page, channel); | ||
59 | } | ||
60 | |||
61 | static inline int drv_set_tx_power(struct ieee802154_local *local, | ||
62 | const s8 dbm) | ||
63 | { | ||
64 | might_sleep(); | ||
65 | |||
66 | if (!local->ops->set_txpower) { | ||
67 | WARN_ON(1); | ||
68 | return -EOPNOTSUPP; | ||
69 | } | ||
70 | |||
71 | return local->ops->set_txpower(&local->hw, dbm); | ||
72 | } | ||
73 | |||
74 | static inline int drv_set_cca_mode(struct ieee802154_local *local, | ||
75 | const u8 cca_mode) | ||
76 | { | ||
77 | might_sleep(); | ||
78 | |||
79 | if (!local->ops->set_cca_mode) { | ||
80 | WARN_ON(1); | ||
81 | return -EOPNOTSUPP; | ||
82 | } | ||
83 | |||
84 | return local->ops->set_cca_mode(&local->hw, cca_mode); | ||
85 | } | ||
86 | |||
87 | static inline int drv_set_lbt_mode(struct ieee802154_local *local, | ||
88 | const bool mode) | ||
89 | { | ||
90 | might_sleep(); | ||
91 | |||
92 | if (!local->ops->set_lbt) { | ||
93 | WARN_ON(1); | ||
94 | return -EOPNOTSUPP; | ||
95 | } | ||
96 | |||
97 | return local->ops->set_lbt(&local->hw, mode); | ||
98 | } | ||
99 | |||
100 | static inline int drv_set_cca_ed_level(struct ieee802154_local *local, | ||
101 | const s32 ed_level) | ||
102 | { | ||
103 | might_sleep(); | ||
104 | |||
105 | if (!local->ops->set_cca_ed_level) { | ||
106 | WARN_ON(1); | ||
107 | return -EOPNOTSUPP; | ||
108 | } | ||
109 | |||
110 | return local->ops->set_cca_ed_level(&local->hw, ed_level); | ||
111 | } | ||
112 | |||
113 | static inline int drv_set_pan_id(struct ieee802154_local *local, | ||
114 | const __le16 pan_id) | ||
115 | { | ||
116 | struct ieee802154_hw_addr_filt filt; | ||
117 | |||
118 | might_sleep(); | ||
119 | |||
120 | if (!local->ops->set_hw_addr_filt) { | ||
121 | WARN_ON(1); | ||
122 | return -EOPNOTSUPP; | ||
123 | } | ||
124 | |||
125 | filt.pan_id = pan_id; | ||
126 | |||
127 | return local->ops->set_hw_addr_filt(&local->hw, &filt, | ||
128 | IEEE802154_AFILT_PANID_CHANGED); | ||
129 | } | ||
130 | |||
131 | static inline int drv_set_extended_addr(struct ieee802154_local *local, | ||
132 | const __le64 extended_addr) | ||
133 | { | ||
134 | struct ieee802154_hw_addr_filt filt; | ||
135 | |||
136 | might_sleep(); | ||
137 | |||
138 | if (!local->ops->set_hw_addr_filt) { | ||
139 | WARN_ON(1); | ||
140 | return -EOPNOTSUPP; | ||
141 | } | ||
142 | |||
143 | filt.ieee_addr = extended_addr; | ||
144 | |||
145 | return local->ops->set_hw_addr_filt(&local->hw, &filt, | ||
146 | IEEE802154_AFILT_IEEEADDR_CHANGED); | ||
147 | } | ||
148 | |||
149 | static inline int drv_set_short_addr(struct ieee802154_local *local, | ||
150 | const __le16 short_addr) | ||
151 | { | ||
152 | struct ieee802154_hw_addr_filt filt; | ||
153 | |||
154 | might_sleep(); | ||
155 | |||
156 | if (!local->ops->set_hw_addr_filt) { | ||
157 | WARN_ON(1); | ||
158 | return -EOPNOTSUPP; | ||
159 | } | ||
160 | |||
161 | filt.short_addr = short_addr; | ||
162 | |||
163 | return local->ops->set_hw_addr_filt(&local->hw, &filt, | ||
164 | IEEE802154_AFILT_SADDR_CHANGED); | ||
165 | } | ||
166 | |||
167 | static inline int drv_set_pan_coord(struct ieee802154_local *local, | ||
168 | const bool is_coord) | ||
169 | { | ||
170 | struct ieee802154_hw_addr_filt filt; | ||
171 | |||
172 | might_sleep(); | ||
173 | |||
174 | if (!local->ops->set_hw_addr_filt) { | ||
175 | WARN_ON(1); | ||
176 | return -EOPNOTSUPP; | ||
177 | } | ||
178 | |||
179 | filt.pan_coord = is_coord; | ||
180 | |||
181 | return local->ops->set_hw_addr_filt(&local->hw, &filt, | ||
182 | IEEE802154_AFILT_PANC_CHANGED); | ||
183 | } | ||
184 | |||
185 | static inline int drv_set_csma_params(struct ieee802154_local *local, | ||
186 | u8 min_be, u8 max_be, | ||
187 | u8 max_csma_backoffs) | ||
188 | { | ||
189 | might_sleep(); | ||
190 | |||
191 | if (!local->ops->set_csma_params) { | ||
192 | WARN_ON(1); | ||
193 | return -EOPNOTSUPP; | ||
194 | } | ||
195 | |||
196 | return local->ops->set_csma_params(&local->hw, min_be, max_be, | ||
197 | max_csma_backoffs); | ||
198 | } | ||
199 | |||
200 | static inline int drv_set_max_frame_retries(struct ieee802154_local *local, | ||
201 | s8 max_frame_retries) | ||
202 | { | ||
203 | might_sleep(); | ||
204 | |||
205 | if (!local->ops->set_frame_retries) { | ||
206 | WARN_ON(1); | ||
207 | return -EOPNOTSUPP; | ||
208 | } | ||
209 | |||
210 | return local->ops->set_frame_retries(&local->hw, max_frame_retries); | ||
211 | } | ||
212 | |||
213 | static inline int drv_set_promiscuous_mode(struct ieee802154_local *local, | ||
214 | const bool on) | ||
215 | { | ||
216 | might_sleep(); | ||
217 | |||
218 | if (!local->ops->set_promiscuous_mode) { | ||
219 | WARN_ON(1); | ||
220 | return -EOPNOTSUPP; | ||
221 | } | ||
222 | |||
223 | return local->ops->set_promiscuous_mode(&local->hw, on); | ||
224 | } | ||
225 | |||
226 | #endif /* __MAC802154_DRVIER_OPS */ | ||
diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c deleted file mode 100644 index b36b2b996578..000000000000 --- a/net/mac802154/ieee802154_dev.c +++ /dev/null | |||
@@ -1,415 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2012 Siemens AG | ||
3 | * | ||
4 | * Written by: | ||
5 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | ||
6 | * | ||
7 | * Based on the code from 'linux-zigbee.sourceforge.net' project. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 | ||
11 | * as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | |||
27 | #include <net/netlink.h> | ||
28 | #include <linux/nl802154.h> | ||
29 | #include <net/mac802154.h> | ||
30 | #include <net/ieee802154_netdev.h> | ||
31 | #include <net/route.h> | ||
32 | #include <net/wpan-phy.h> | ||
33 | |||
34 | #include "mac802154.h" | ||
35 | |||
36 | int mac802154_slave_open(struct net_device *dev) | ||
37 | { | ||
38 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | ||
39 | struct mac802154_sub_if_data *subif; | ||
40 | struct mac802154_priv *ipriv = priv->hw; | ||
41 | int res = 0; | ||
42 | |||
43 | ASSERT_RTNL(); | ||
44 | |||
45 | if (priv->type == IEEE802154_DEV_WPAN) { | ||
46 | mutex_lock(&priv->hw->slaves_mtx); | ||
47 | list_for_each_entry(subif, &priv->hw->slaves, list) { | ||
48 | if (subif != priv && subif->type == priv->type && | ||
49 | subif->running) { | ||
50 | mutex_unlock(&priv->hw->slaves_mtx); | ||
51 | return -EBUSY; | ||
52 | } | ||
53 | } | ||
54 | mutex_unlock(&priv->hw->slaves_mtx); | ||
55 | } | ||
56 | |||
57 | mutex_lock(&priv->hw->slaves_mtx); | ||
58 | priv->running = true; | ||
59 | mutex_unlock(&priv->hw->slaves_mtx); | ||
60 | |||
61 | if (ipriv->open_count++ == 0) { | ||
62 | res = ipriv->ops->start(&ipriv->hw); | ||
63 | WARN_ON(res); | ||
64 | if (res) | ||
65 | goto err; | ||
66 | } | ||
67 | |||
68 | if (ipriv->ops->ieee_addr) { | ||
69 | __le64 addr = ieee802154_devaddr_from_raw(dev->dev_addr); | ||
70 | |||
71 | res = ipriv->ops->ieee_addr(&ipriv->hw, addr); | ||
72 | WARN_ON(res); | ||
73 | if (res) | ||
74 | goto err; | ||
75 | mac802154_dev_set_ieee_addr(dev); | ||
76 | } | ||
77 | |||
78 | netif_start_queue(dev); | ||
79 | return 0; | ||
80 | err: | ||
81 | priv->hw->open_count--; | ||
82 | |||
83 | return res; | ||
84 | } | ||
85 | |||
86 | int mac802154_slave_close(struct net_device *dev) | ||
87 | { | ||
88 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | ||
89 | struct mac802154_priv *ipriv = priv->hw; | ||
90 | |||
91 | ASSERT_RTNL(); | ||
92 | |||
93 | netif_stop_queue(dev); | ||
94 | |||
95 | mutex_lock(&priv->hw->slaves_mtx); | ||
96 | priv->running = false; | ||
97 | mutex_unlock(&priv->hw->slaves_mtx); | ||
98 | |||
99 | if (!--ipriv->open_count) | ||
100 | ipriv->ops->stop(&ipriv->hw); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int | ||
106 | mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev) | ||
107 | { | ||
108 | struct mac802154_sub_if_data *priv; | ||
109 | struct mac802154_priv *ipriv; | ||
110 | int err; | ||
111 | |||
112 | ipriv = wpan_phy_priv(phy); | ||
113 | |||
114 | priv = netdev_priv(dev); | ||
115 | priv->dev = dev; | ||
116 | priv->hw = ipriv; | ||
117 | |||
118 | dev->needed_headroom = ipriv->hw.extra_tx_headroom; | ||
119 | |||
120 | SET_NETDEV_DEV(dev, &ipriv->phy->dev); | ||
121 | |||
122 | mutex_lock(&ipriv->slaves_mtx); | ||
123 | if (!ipriv->running) { | ||
124 | mutex_unlock(&ipriv->slaves_mtx); | ||
125 | return -ENODEV; | ||
126 | } | ||
127 | mutex_unlock(&ipriv->slaves_mtx); | ||
128 | |||
129 | err = register_netdev(dev); | ||
130 | if (err < 0) | ||
131 | return err; | ||
132 | |||
133 | rtnl_lock(); | ||
134 | mutex_lock(&ipriv->slaves_mtx); | ||
135 | list_add_tail_rcu(&priv->list, &ipriv->slaves); | ||
136 | mutex_unlock(&ipriv->slaves_mtx); | ||
137 | rtnl_unlock(); | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static void | ||
143 | mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev) | ||
144 | { | ||
145 | struct mac802154_sub_if_data *sdata; | ||
146 | |||
147 | ASSERT_RTNL(); | ||
148 | |||
149 | sdata = netdev_priv(dev); | ||
150 | |||
151 | BUG_ON(sdata->hw->phy != phy); | ||
152 | |||
153 | mutex_lock(&sdata->hw->slaves_mtx); | ||
154 | list_del_rcu(&sdata->list); | ||
155 | mutex_unlock(&sdata->hw->slaves_mtx); | ||
156 | |||
157 | synchronize_rcu(); | ||
158 | unregister_netdevice(sdata->dev); | ||
159 | } | ||
160 | |||
161 | static struct net_device * | ||
162 | mac802154_add_iface(struct wpan_phy *phy, const char *name, int type) | ||
163 | { | ||
164 | struct net_device *dev; | ||
165 | int err = -ENOMEM; | ||
166 | |||
167 | switch (type) { | ||
168 | case IEEE802154_DEV_MONITOR: | ||
169 | dev = alloc_netdev(sizeof(struct mac802154_sub_if_data), | ||
170 | name, NET_NAME_UNKNOWN, | ||
171 | mac802154_monitor_setup); | ||
172 | break; | ||
173 | case IEEE802154_DEV_WPAN: | ||
174 | dev = alloc_netdev(sizeof(struct mac802154_sub_if_data), | ||
175 | name, NET_NAME_UNKNOWN, | ||
176 | mac802154_wpan_setup); | ||
177 | break; | ||
178 | default: | ||
179 | dev = NULL; | ||
180 | err = -EINVAL; | ||
181 | break; | ||
182 | } | ||
183 | if (!dev) | ||
184 | goto err; | ||
185 | |||
186 | err = mac802154_netdev_register(phy, dev); | ||
187 | if (err) | ||
188 | goto err_free; | ||
189 | |||
190 | dev_hold(dev); /* we return an incremented device refcount */ | ||
191 | return dev; | ||
192 | |||
193 | err_free: | ||
194 | free_netdev(dev); | ||
195 | err: | ||
196 | return ERR_PTR(err); | ||
197 | } | ||
198 | |||
199 | static int mac802154_set_txpower(struct wpan_phy *phy, int db) | ||
200 | { | ||
201 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
202 | |||
203 | return priv->ops->set_txpower(&priv->hw, db); | ||
204 | } | ||
205 | |||
206 | static int mac802154_set_lbt(struct wpan_phy *phy, bool on) | ||
207 | { | ||
208 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
209 | |||
210 | return priv->ops->set_lbt(&priv->hw, on); | ||
211 | } | ||
212 | |||
213 | static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode) | ||
214 | { | ||
215 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
216 | |||
217 | return priv->ops->set_cca_mode(&priv->hw, mode); | ||
218 | } | ||
219 | |||
220 | static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level) | ||
221 | { | ||
222 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
223 | |||
224 | return priv->ops->set_cca_ed_level(&priv->hw, level); | ||
225 | } | ||
226 | |||
227 | static int mac802154_set_csma_params(struct wpan_phy *phy, u8 min_be, | ||
228 | u8 max_be, u8 retries) | ||
229 | { | ||
230 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
231 | |||
232 | return priv->ops->set_csma_params(&priv->hw, min_be, max_be, retries); | ||
233 | } | ||
234 | |||
235 | static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries) | ||
236 | { | ||
237 | struct mac802154_priv *priv = wpan_phy_priv(phy); | ||
238 | |||
239 | return priv->ops->set_frame_retries(&priv->hw, retries); | ||
240 | } | ||
241 | |||
242 | struct ieee802154_dev * | ||
243 | ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops) | ||
244 | { | ||
245 | struct wpan_phy *phy; | ||
246 | struct mac802154_priv *priv; | ||
247 | size_t priv_size; | ||
248 | |||
249 | if (!ops || !ops->xmit || !ops->ed || !ops->start || | ||
250 | !ops->stop || !ops->set_channel) { | ||
251 | pr_err("undefined IEEE802.15.4 device operations\n"); | ||
252 | return NULL; | ||
253 | } | ||
254 | |||
255 | /* Ensure 32-byte alignment of our private data and hw private data. | ||
256 | * We use the wpan_phy priv data for both our mac802154_priv and for | ||
257 | * the driver's private data | ||
258 | * | ||
259 | * in memory it'll be like this: | ||
260 | * | ||
261 | * +-----------------------+ | ||
262 | * | struct wpan_phy | | ||
263 | * +-----------------------+ | ||
264 | * | struct mac802154_priv | | ||
265 | * +-----------------------+ | ||
266 | * | driver's private data | | ||
267 | * +-----------------------+ | ||
268 | * | ||
269 | * Due to ieee802154 layer isn't aware of driver and MAC structures, | ||
270 | * so lets allign them here. | ||
271 | */ | ||
272 | |||
273 | priv_size = ALIGN(sizeof(*priv), NETDEV_ALIGN) + priv_data_len; | ||
274 | |||
275 | phy = wpan_phy_alloc(priv_size); | ||
276 | if (!phy) { | ||
277 | pr_err("failure to allocate master IEEE802.15.4 device\n"); | ||
278 | return NULL; | ||
279 | } | ||
280 | |||
281 | priv = wpan_phy_priv(phy); | ||
282 | priv->phy = phy; | ||
283 | priv->hw.phy = priv->phy; | ||
284 | priv->hw.priv = (char *)priv + ALIGN(sizeof(*priv), NETDEV_ALIGN); | ||
285 | priv->ops = ops; | ||
286 | |||
287 | INIT_LIST_HEAD(&priv->slaves); | ||
288 | mutex_init(&priv->slaves_mtx); | ||
289 | |||
290 | return &priv->hw; | ||
291 | } | ||
292 | EXPORT_SYMBOL(ieee802154_alloc_device); | ||
293 | |||
294 | void ieee802154_free_device(struct ieee802154_dev *hw) | ||
295 | { | ||
296 | struct mac802154_priv *priv = mac802154_to_priv(hw); | ||
297 | |||
298 | BUG_ON(!list_empty(&priv->slaves)); | ||
299 | |||
300 | mutex_destroy(&priv->slaves_mtx); | ||
301 | |||
302 | wpan_phy_free(priv->phy); | ||
303 | } | ||
304 | EXPORT_SYMBOL(ieee802154_free_device); | ||
305 | |||
306 | int ieee802154_register_device(struct ieee802154_dev *dev) | ||
307 | { | ||
308 | struct mac802154_priv *priv = mac802154_to_priv(dev); | ||
309 | int rc = -ENOSYS; | ||
310 | |||
311 | if (dev->flags & IEEE802154_HW_TXPOWER) { | ||
312 | if (!priv->ops->set_txpower) | ||
313 | goto out; | ||
314 | |||
315 | priv->phy->set_txpower = mac802154_set_txpower; | ||
316 | } | ||
317 | |||
318 | if (dev->flags & IEEE802154_HW_LBT) { | ||
319 | if (!priv->ops->set_lbt) | ||
320 | goto out; | ||
321 | |||
322 | priv->phy->set_lbt = mac802154_set_lbt; | ||
323 | } | ||
324 | |||
325 | if (dev->flags & IEEE802154_HW_CCA_MODE) { | ||
326 | if (!priv->ops->set_cca_mode) | ||
327 | goto out; | ||
328 | |||
329 | priv->phy->set_cca_mode = mac802154_set_cca_mode; | ||
330 | } | ||
331 | |||
332 | if (dev->flags & IEEE802154_HW_CCA_ED_LEVEL) { | ||
333 | if (!priv->ops->set_cca_ed_level) | ||
334 | goto out; | ||
335 | |||
336 | priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level; | ||
337 | } | ||
338 | |||
339 | if (dev->flags & IEEE802154_HW_CSMA_PARAMS) { | ||
340 | if (!priv->ops->set_csma_params) | ||
341 | goto out; | ||
342 | |||
343 | priv->phy->set_csma_params = mac802154_set_csma_params; | ||
344 | } | ||
345 | |||
346 | if (dev->flags & IEEE802154_HW_FRAME_RETRIES) { | ||
347 | if (!priv->ops->set_frame_retries) | ||
348 | goto out; | ||
349 | |||
350 | priv->phy->set_frame_retries = mac802154_set_frame_retries; | ||
351 | } | ||
352 | |||
353 | priv->dev_workqueue = | ||
354 | create_singlethread_workqueue(wpan_phy_name(priv->phy)); | ||
355 | if (!priv->dev_workqueue) { | ||
356 | rc = -ENOMEM; | ||
357 | goto out; | ||
358 | } | ||
359 | |||
360 | wpan_phy_set_dev(priv->phy, priv->hw.parent); | ||
361 | |||
362 | priv->phy->add_iface = mac802154_add_iface; | ||
363 | priv->phy->del_iface = mac802154_del_iface; | ||
364 | |||
365 | rc = wpan_phy_register(priv->phy); | ||
366 | if (rc < 0) | ||
367 | goto out_wq; | ||
368 | |||
369 | rtnl_lock(); | ||
370 | |||
371 | mutex_lock(&priv->slaves_mtx); | ||
372 | priv->running = MAC802154_DEVICE_RUN; | ||
373 | mutex_unlock(&priv->slaves_mtx); | ||
374 | |||
375 | rtnl_unlock(); | ||
376 | |||
377 | return 0; | ||
378 | |||
379 | out_wq: | ||
380 | destroy_workqueue(priv->dev_workqueue); | ||
381 | out: | ||
382 | return rc; | ||
383 | } | ||
384 | EXPORT_SYMBOL(ieee802154_register_device); | ||
385 | |||
386 | void ieee802154_unregister_device(struct ieee802154_dev *dev) | ||
387 | { | ||
388 | struct mac802154_priv *priv = mac802154_to_priv(dev); | ||
389 | struct mac802154_sub_if_data *sdata, *next; | ||
390 | |||
391 | flush_workqueue(priv->dev_workqueue); | ||
392 | destroy_workqueue(priv->dev_workqueue); | ||
393 | |||
394 | rtnl_lock(); | ||
395 | |||
396 | mutex_lock(&priv->slaves_mtx); | ||
397 | priv->running = MAC802154_DEVICE_STOPPED; | ||
398 | mutex_unlock(&priv->slaves_mtx); | ||
399 | |||
400 | list_for_each_entry_safe(sdata, next, &priv->slaves, list) { | ||
401 | mutex_lock(&sdata->hw->slaves_mtx); | ||
402 | list_del(&sdata->list); | ||
403 | mutex_unlock(&sdata->hw->slaves_mtx); | ||
404 | |||
405 | unregister_netdevice(sdata->dev); | ||
406 | } | ||
407 | |||
408 | rtnl_unlock(); | ||
409 | |||
410 | wpan_phy_unregister(priv->phy); | ||
411 | } | ||
412 | EXPORT_SYMBOL(ieee802154_unregister_device); | ||
413 | |||
414 | MODULE_DESCRIPTION("IEEE 802.15.4 implementation"); | ||
415 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/net/mac802154/mac802154.h b/net/mac802154/ieee802154_i.h index 762a6f849c6b..1086a9d96f8f 100644 --- a/net/mac802154/mac802154.h +++ b/net/mac802154/ieee802154_i.h | |||
@@ -10,18 +10,14 @@ | |||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Written by: | 13 | * Written by: |
18 | * Pavel Smolenskiy <pavel.smolenskiy@gmail.com> | 14 | * Pavel Smolenskiy <pavel.smolenskiy@gmail.com> |
19 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> | 15 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> |
20 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 16 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
21 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | 17 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> |
22 | */ | 18 | */ |
23 | #ifndef MAC802154_H | 19 | #ifndef __IEEE802154_I_H |
24 | #define MAC802154_H | 20 | #define __IEEE802154_I_H |
25 | 21 | ||
26 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
27 | #include <net/mac802154.h> | 23 | #include <net/mac802154.h> |
@@ -30,9 +26,9 @@ | |||
30 | #include "llsec.h" | 26 | #include "llsec.h" |
31 | 27 | ||
32 | /* mac802154 device private data */ | 28 | /* mac802154 device private data */ |
33 | struct mac802154_priv { | 29 | struct ieee802154_local { |
34 | struct ieee802154_dev hw; | 30 | struct ieee802154_hw hw; |
35 | struct ieee802154_ops *ops; | 31 | const struct ieee802154_ops *ops; |
36 | 32 | ||
37 | /* ieee802154 phy */ | 33 | /* ieee802154 phy */ |
38 | struct wpan_phy *phy; | 34 | struct wpan_phy *phy; |
@@ -46,23 +42,27 @@ struct mac802154_priv { | |||
46 | * | 42 | * |
47 | * So atomic readers can use any of this protection methods. | 43 | * So atomic readers can use any of this protection methods. |
48 | */ | 44 | */ |
49 | struct list_head slaves; | 45 | struct list_head interfaces; |
50 | struct mutex slaves_mtx; | 46 | struct mutex iflist_mtx; |
51 | 47 | ||
52 | /* This one is used for scanning and other jobs not to be interfered | 48 | /* This one is used for scanning and other jobs not to be interfered |
53 | * with serial driver. | 49 | * with serial driver. |
54 | */ | 50 | */ |
55 | struct workqueue_struct *dev_workqueue; | 51 | struct workqueue_struct *workqueue; |
56 | 52 | ||
57 | /* SoftMAC device is registered and running. One can add subinterfaces. | 53 | bool started; |
58 | * This flag should be modified under slaves_mtx and RTNL, so you can | 54 | |
59 | * read them using any of protection methods. | 55 | struct tasklet_struct tasklet; |
60 | */ | 56 | struct sk_buff_head skb_queue; |
61 | bool running; | ||
62 | }; | 57 | }; |
63 | 58 | ||
64 | #define MAC802154_DEVICE_STOPPED 0x00 | 59 | enum { |
65 | #define MAC802154_DEVICE_RUN 0x01 | 60 | IEEE802154_RX_MSG = 1, |
61 | }; | ||
62 | |||
63 | enum ieee802154_sdata_state_bits { | ||
64 | SDATA_STATE_RUNNING, | ||
65 | }; | ||
66 | 66 | ||
67 | /* Slave interface definition. | 67 | /* Slave interface definition. |
68 | * | 68 | * |
@@ -70,23 +70,21 @@ struct mac802154_priv { | |||
70 | * Each ieee802154 device/transceiver may have several slaves and able | 70 | * Each ieee802154 device/transceiver may have several slaves and able |
71 | * to be associated with several networks at the same time. | 71 | * to be associated with several networks at the same time. |
72 | */ | 72 | */ |
73 | struct mac802154_sub_if_data { | 73 | struct ieee802154_sub_if_data { |
74 | struct list_head list; /* the ieee802154_priv->slaves list */ | 74 | struct list_head list; /* the ieee802154_priv->slaves list */ |
75 | 75 | ||
76 | struct mac802154_priv *hw; | 76 | struct ieee802154_local *local; |
77 | struct net_device *dev; | 77 | struct net_device *dev; |
78 | 78 | ||
79 | int type; | 79 | int type; |
80 | bool running; | 80 | unsigned long state; |
81 | 81 | ||
82 | spinlock_t mib_lock; | 82 | spinlock_t mib_lock; |
83 | 83 | ||
84 | __le16 pan_id; | 84 | __le16 pan_id; |
85 | __le16 short_addr; | 85 | __le16 short_addr; |
86 | __le64 extended_addr; | 86 | __le64 extended_addr; |
87 | 87 | bool promisuous_mode; | |
88 | u8 chan; | ||
89 | u8 page; | ||
90 | 88 | ||
91 | struct ieee802154_mac_params mac_params; | 89 | struct ieee802154_mac_params mac_params; |
92 | 90 | ||
@@ -103,24 +101,36 @@ struct mac802154_sub_if_data { | |||
103 | struct mac802154_llsec sec; | 101 | struct mac802154_llsec sec; |
104 | }; | 102 | }; |
105 | 103 | ||
106 | #define mac802154_to_priv(_hw) container_of(_hw, struct mac802154_priv, hw) | ||
107 | |||
108 | #define MAC802154_CHAN_NONE 0xff /* No channel is assigned */ | 104 | #define MAC802154_CHAN_NONE 0xff /* No channel is assigned */ |
109 | 105 | ||
106 | static inline struct ieee802154_local * | ||
107 | hw_to_local(struct ieee802154_hw *hw) | ||
108 | { | ||
109 | return container_of(hw, struct ieee802154_local, hw); | ||
110 | } | ||
111 | |||
112 | static inline struct ieee802154_sub_if_data * | ||
113 | IEEE802154_DEV_TO_SUB_IF(const struct net_device *dev) | ||
114 | { | ||
115 | return netdev_priv(dev); | ||
116 | } | ||
117 | |||
118 | static inline bool | ||
119 | ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata) | ||
120 | { | ||
121 | return test_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
122 | } | ||
123 | |||
110 | extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced; | 124 | extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced; |
111 | extern struct ieee802154_mlme_ops mac802154_mlme_wpan; | 125 | extern struct ieee802154_mlme_ops mac802154_mlme_wpan; |
112 | 126 | ||
113 | int mac802154_slave_open(struct net_device *dev); | ||
114 | int mac802154_slave_close(struct net_device *dev); | ||
115 | |||
116 | void mac802154_monitors_rx(struct mac802154_priv *priv, struct sk_buff *skb); | ||
117 | void mac802154_monitor_setup(struct net_device *dev); | 127 | void mac802154_monitor_setup(struct net_device *dev); |
128 | netdev_tx_t | ||
129 | ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); | ||
118 | 130 | ||
119 | void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb); | ||
120 | void mac802154_wpan_setup(struct net_device *dev); | 131 | void mac802154_wpan_setup(struct net_device *dev); |
121 | 132 | netdev_tx_t | |
122 | netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, | 133 | ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); |
123 | u8 page, u8 chan); | ||
124 | 134 | ||
125 | /* MIB callbacks */ | 135 | /* MIB callbacks */ |
126 | void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val); | 136 | void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val); |
@@ -131,11 +141,6 @@ void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val); | |||
131 | void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan); | 141 | void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan); |
132 | u8 mac802154_dev_get_dsn(const struct net_device *dev); | 142 | u8 mac802154_dev_get_dsn(const struct net_device *dev); |
133 | 143 | ||
134 | int mac802154_set_mac_params(struct net_device *dev, | ||
135 | const struct ieee802154_mac_params *params); | ||
136 | void mac802154_get_mac_params(struct net_device *dev, | ||
137 | struct ieee802154_mac_params *params); | ||
138 | |||
139 | int mac802154_get_params(struct net_device *dev, | 144 | int mac802154_get_params(struct net_device *dev, |
140 | struct ieee802154_llsec_params *params); | 145 | struct ieee802154_llsec_params *params); |
141 | int mac802154_set_params(struct net_device *dev, | 146 | int mac802154_set_params(struct net_device *dev, |
@@ -169,4 +174,4 @@ void mac802154_get_table(struct net_device *dev, | |||
169 | struct ieee802154_llsec_table **t); | 174 | struct ieee802154_llsec_table **t); |
170 | void mac802154_unlock_table(struct net_device *dev); | 175 | void mac802154_unlock_table(struct net_device *dev); |
171 | 176 | ||
172 | #endif /* MAC802154_H */ | 177 | #endif /* __IEEE802154_I_H */ |
diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c new file mode 100644 index 000000000000..f7a6f83301e2 --- /dev/null +++ b/net/mac802154/iface.c | |||
@@ -0,0 +1,466 @@ | |||
1 | /* | ||
2 | * Copyright 2007-2012 Siemens AG | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 | ||
6 | * as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * Written by: | ||
14 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | ||
15 | * Sergey Lapin <slapin@ossfans.org> | ||
16 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> | ||
17 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | ||
18 | */ | ||
19 | |||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/if_arp.h> | ||
23 | #include <linux/ieee802154.h> | ||
24 | |||
25 | #include <net/rtnetlink.h> | ||
26 | #include <linux/nl802154.h> | ||
27 | #include <net/af_ieee802154.h> | ||
28 | #include <net/mac802154.h> | ||
29 | #include <net/ieee802154_netdev.h> | ||
30 | #include <net/cfg802154.h> | ||
31 | |||
32 | #include "ieee802154_i.h" | ||
33 | #include "driver-ops.h" | ||
34 | |||
35 | static int mac802154_wpan_update_llsec(struct net_device *dev) | ||
36 | { | ||
37 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
38 | struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev); | ||
39 | int rc = 0; | ||
40 | |||
41 | if (ops->llsec) { | ||
42 | struct ieee802154_llsec_params params; | ||
43 | int changed = 0; | ||
44 | |||
45 | params.pan_id = sdata->pan_id; | ||
46 | changed |= IEEE802154_LLSEC_PARAM_PAN_ID; | ||
47 | |||
48 | params.hwaddr = sdata->extended_addr; | ||
49 | changed |= IEEE802154_LLSEC_PARAM_HWADDR; | ||
50 | |||
51 | rc = ops->llsec->set_params(dev, ¶ms, changed); | ||
52 | } | ||
53 | |||
54 | return rc; | ||
55 | } | ||
56 | |||
57 | static int | ||
58 | mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
59 | { | ||
60 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
61 | struct sockaddr_ieee802154 *sa = | ||
62 | (struct sockaddr_ieee802154 *)&ifr->ifr_addr; | ||
63 | int err = -ENOIOCTLCMD; | ||
64 | |||
65 | spin_lock_bh(&sdata->mib_lock); | ||
66 | |||
67 | switch (cmd) { | ||
68 | case SIOCGIFADDR: | ||
69 | { | ||
70 | u16 pan_id, short_addr; | ||
71 | |||
72 | pan_id = le16_to_cpu(sdata->pan_id); | ||
73 | short_addr = le16_to_cpu(sdata->short_addr); | ||
74 | if (pan_id == IEEE802154_PANID_BROADCAST || | ||
75 | short_addr == IEEE802154_ADDR_BROADCAST) { | ||
76 | err = -EADDRNOTAVAIL; | ||
77 | break; | ||
78 | } | ||
79 | |||
80 | sa->family = AF_IEEE802154; | ||
81 | sa->addr.addr_type = IEEE802154_ADDR_SHORT; | ||
82 | sa->addr.pan_id = pan_id; | ||
83 | sa->addr.short_addr = short_addr; | ||
84 | |||
85 | err = 0; | ||
86 | break; | ||
87 | } | ||
88 | case SIOCSIFADDR: | ||
89 | dev_warn(&dev->dev, | ||
90 | "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n"); | ||
91 | if (sa->family != AF_IEEE802154 || | ||
92 | sa->addr.addr_type != IEEE802154_ADDR_SHORT || | ||
93 | sa->addr.pan_id == IEEE802154_PANID_BROADCAST || | ||
94 | sa->addr.short_addr == IEEE802154_ADDR_BROADCAST || | ||
95 | sa->addr.short_addr == IEEE802154_ADDR_UNDEF) { | ||
96 | err = -EINVAL; | ||
97 | break; | ||
98 | } | ||
99 | |||
100 | sdata->pan_id = cpu_to_le16(sa->addr.pan_id); | ||
101 | sdata->short_addr = cpu_to_le16(sa->addr.short_addr); | ||
102 | |||
103 | err = mac802154_wpan_update_llsec(dev); | ||
104 | break; | ||
105 | } | ||
106 | |||
107 | spin_unlock_bh(&sdata->mib_lock); | ||
108 | return err; | ||
109 | } | ||
110 | |||
111 | static int mac802154_wpan_mac_addr(struct net_device *dev, void *p) | ||
112 | { | ||
113 | struct sockaddr *addr = p; | ||
114 | |||
115 | if (netif_running(dev)) | ||
116 | return -EBUSY; | ||
117 | |||
118 | /* FIXME: validate addr */ | ||
119 | memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); | ||
120 | mac802154_dev_set_ieee_addr(dev); | ||
121 | return mac802154_wpan_update_llsec(dev); | ||
122 | } | ||
123 | |||
124 | int mac802154_set_mac_params(struct net_device *dev, | ||
125 | const struct ieee802154_mac_params *params) | ||
126 | { | ||
127 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
128 | |||
129 | mutex_lock(&sdata->local->iflist_mtx); | ||
130 | sdata->mac_params = *params; | ||
131 | mutex_unlock(&sdata->local->iflist_mtx); | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | void mac802154_get_mac_params(struct net_device *dev, | ||
137 | struct ieee802154_mac_params *params) | ||
138 | { | ||
139 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
140 | |||
141 | mutex_lock(&sdata->local->iflist_mtx); | ||
142 | *params = sdata->mac_params; | ||
143 | mutex_unlock(&sdata->local->iflist_mtx); | ||
144 | } | ||
145 | |||
146 | static int mac802154_slave_open(struct net_device *dev) | ||
147 | { | ||
148 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
149 | struct ieee802154_sub_if_data *subif; | ||
150 | struct ieee802154_local *local = sdata->local; | ||
151 | int res = 0; | ||
152 | |||
153 | ASSERT_RTNL(); | ||
154 | |||
155 | if (sdata->type == IEEE802154_DEV_WPAN) { | ||
156 | mutex_lock(&sdata->local->iflist_mtx); | ||
157 | list_for_each_entry(subif, &sdata->local->interfaces, list) { | ||
158 | if (subif != sdata && subif->type == sdata->type && | ||
159 | ieee802154_sdata_running(subif)) { | ||
160 | mutex_unlock(&sdata->local->iflist_mtx); | ||
161 | return -EBUSY; | ||
162 | } | ||
163 | } | ||
164 | mutex_unlock(&sdata->local->iflist_mtx); | ||
165 | } | ||
166 | |||
167 | set_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
168 | |||
169 | if (!local->open_count) { | ||
170 | res = drv_start(local); | ||
171 | WARN_ON(res); | ||
172 | if (res) | ||
173 | goto err; | ||
174 | } | ||
175 | |||
176 | local->open_count++; | ||
177 | netif_start_queue(dev); | ||
178 | return 0; | ||
179 | err: | ||
180 | /* might already be clear but that doesn't matter */ | ||
181 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
182 | |||
183 | return res; | ||
184 | } | ||
185 | |||
186 | static int mac802154_wpan_open(struct net_device *dev) | ||
187 | { | ||
188 | int rc; | ||
189 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
190 | struct ieee802154_local *local = sdata->local; | ||
191 | struct wpan_phy *phy = sdata->local->phy; | ||
192 | |||
193 | rc = mac802154_slave_open(dev); | ||
194 | if (rc < 0) | ||
195 | return rc; | ||
196 | |||
197 | mutex_lock(&phy->pib_lock); | ||
198 | |||
199 | if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) { | ||
200 | rc = drv_set_promiscuous_mode(local, sdata->promisuous_mode); | ||
201 | if (rc < 0) | ||
202 | goto out; | ||
203 | } | ||
204 | |||
205 | if (local->hw.flags & IEEE802154_HW_TXPOWER) { | ||
206 | rc = drv_set_tx_power(local, sdata->mac_params.transmit_power); | ||
207 | if (rc < 0) | ||
208 | goto out; | ||
209 | } | ||
210 | |||
211 | if (local->hw.flags & IEEE802154_HW_LBT) { | ||
212 | rc = drv_set_lbt_mode(local, sdata->mac_params.lbt); | ||
213 | if (rc < 0) | ||
214 | goto out; | ||
215 | } | ||
216 | |||
217 | if (local->hw.flags & IEEE802154_HW_CCA_MODE) { | ||
218 | rc = drv_set_cca_mode(local, sdata->mac_params.cca_mode); | ||
219 | if (rc < 0) | ||
220 | goto out; | ||
221 | } | ||
222 | |||
223 | if (local->hw.flags & IEEE802154_HW_CCA_ED_LEVEL) { | ||
224 | rc = drv_set_cca_ed_level(local, | ||
225 | sdata->mac_params.cca_ed_level); | ||
226 | if (rc < 0) | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) { | ||
231 | rc = drv_set_csma_params(local, sdata->mac_params.min_be, | ||
232 | sdata->mac_params.max_be, | ||
233 | sdata->mac_params.csma_retries); | ||
234 | if (rc < 0) | ||
235 | goto out; | ||
236 | } | ||
237 | |||
238 | if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) { | ||
239 | rc = drv_set_max_frame_retries(local, | ||
240 | sdata->mac_params.frame_retries); | ||
241 | if (rc < 0) | ||
242 | goto out; | ||
243 | } | ||
244 | |||
245 | mutex_unlock(&phy->pib_lock); | ||
246 | return 0; | ||
247 | |||
248 | out: | ||
249 | mutex_unlock(&phy->pib_lock); | ||
250 | return rc; | ||
251 | } | ||
252 | |||
253 | static int mac802154_slave_close(struct net_device *dev) | ||
254 | { | ||
255 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
256 | struct ieee802154_local *local = sdata->local; | ||
257 | |||
258 | ASSERT_RTNL(); | ||
259 | |||
260 | netif_stop_queue(dev); | ||
261 | local->open_count--; | ||
262 | |||
263 | clear_bit(SDATA_STATE_RUNNING, &sdata->state); | ||
264 | |||
265 | if (!local->open_count) | ||
266 | drv_stop(local); | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata, | ||
272 | struct ieee802154_hdr *hdr, | ||
273 | const struct ieee802154_mac_cb *cb) | ||
274 | { | ||
275 | struct ieee802154_llsec_params params; | ||
276 | u8 level; | ||
277 | |||
278 | mac802154_llsec_get_params(&sdata->sec, ¶ms); | ||
279 | |||
280 | if (!params.enabled && cb->secen_override && cb->secen) | ||
281 | return -EINVAL; | ||
282 | if (!params.enabled || | ||
283 | (cb->secen_override && !cb->secen) || | ||
284 | !params.out_level) | ||
285 | return 0; | ||
286 | if (cb->seclevel_override && !cb->seclevel) | ||
287 | return -EINVAL; | ||
288 | |||
289 | level = cb->seclevel_override ? cb->seclevel : params.out_level; | ||
290 | |||
291 | hdr->fc.security_enabled = 1; | ||
292 | hdr->sec.level = level; | ||
293 | hdr->sec.key_id_mode = params.out_key.mode; | ||
294 | if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX) | ||
295 | hdr->sec.short_src = params.out_key.short_source; | ||
296 | else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX) | ||
297 | hdr->sec.extended_src = params.out_key.extended_source; | ||
298 | hdr->sec.key_id = params.out_key.id; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int mac802154_header_create(struct sk_buff *skb, | ||
304 | struct net_device *dev, | ||
305 | unsigned short type, | ||
306 | const void *daddr, | ||
307 | const void *saddr, | ||
308 | unsigned len) | ||
309 | { | ||
310 | struct ieee802154_hdr hdr; | ||
311 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
312 | struct ieee802154_mac_cb *cb = mac_cb(skb); | ||
313 | int hlen; | ||
314 | |||
315 | if (!daddr) | ||
316 | return -EINVAL; | ||
317 | |||
318 | memset(&hdr.fc, 0, sizeof(hdr.fc)); | ||
319 | hdr.fc.type = cb->type; | ||
320 | hdr.fc.security_enabled = cb->secen; | ||
321 | hdr.fc.ack_request = cb->ackreq; | ||
322 | hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev); | ||
323 | |||
324 | if (mac802154_set_header_security(sdata, &hdr, cb) < 0) | ||
325 | return -EINVAL; | ||
326 | |||
327 | if (!saddr) { | ||
328 | spin_lock_bh(&sdata->mib_lock); | ||
329 | |||
330 | if (sdata->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) || | ||
331 | sdata->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) || | ||
332 | sdata->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) { | ||
333 | hdr.source.mode = IEEE802154_ADDR_LONG; | ||
334 | hdr.source.extended_addr = sdata->extended_addr; | ||
335 | } else { | ||
336 | hdr.source.mode = IEEE802154_ADDR_SHORT; | ||
337 | hdr.source.short_addr = sdata->short_addr; | ||
338 | } | ||
339 | |||
340 | hdr.source.pan_id = sdata->pan_id; | ||
341 | |||
342 | spin_unlock_bh(&sdata->mib_lock); | ||
343 | } else { | ||
344 | hdr.source = *(const struct ieee802154_addr *)saddr; | ||
345 | } | ||
346 | |||
347 | hdr.dest = *(const struct ieee802154_addr *)daddr; | ||
348 | |||
349 | hlen = ieee802154_hdr_push(skb, &hdr); | ||
350 | if (hlen < 0) | ||
351 | return -EINVAL; | ||
352 | |||
353 | skb_reset_mac_header(skb); | ||
354 | skb->mac_len = hlen; | ||
355 | |||
356 | if (len > ieee802154_max_payload(&hdr)) | ||
357 | return -EMSGSIZE; | ||
358 | |||
359 | return hlen; | ||
360 | } | ||
361 | |||
362 | static int | ||
363 | mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr) | ||
364 | { | ||
365 | struct ieee802154_hdr hdr; | ||
366 | struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr; | ||
367 | |||
368 | if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) { | ||
369 | pr_debug("malformed packet\n"); | ||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | *addr = hdr.source; | ||
374 | return sizeof(*addr); | ||
375 | } | ||
376 | |||
377 | static struct header_ops mac802154_header_ops = { | ||
378 | .create = mac802154_header_create, | ||
379 | .parse = mac802154_header_parse, | ||
380 | }; | ||
381 | |||
382 | static const struct net_device_ops mac802154_wpan_ops = { | ||
383 | .ndo_open = mac802154_wpan_open, | ||
384 | .ndo_stop = mac802154_slave_close, | ||
385 | .ndo_start_xmit = ieee802154_subif_start_xmit, | ||
386 | .ndo_do_ioctl = mac802154_wpan_ioctl, | ||
387 | .ndo_set_mac_address = mac802154_wpan_mac_addr, | ||
388 | }; | ||
389 | |||
390 | static const struct net_device_ops mac802154_monitor_ops = { | ||
391 | .ndo_open = mac802154_wpan_open, | ||
392 | .ndo_stop = mac802154_slave_close, | ||
393 | .ndo_start_xmit = ieee802154_monitor_start_xmit, | ||
394 | }; | ||
395 | |||
396 | static void mac802154_wpan_free(struct net_device *dev) | ||
397 | { | ||
398 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
399 | |||
400 | mac802154_llsec_destroy(&sdata->sec); | ||
401 | |||
402 | free_netdev(dev); | ||
403 | } | ||
404 | |||
405 | void mac802154_wpan_setup(struct net_device *dev) | ||
406 | { | ||
407 | struct ieee802154_sub_if_data *sdata; | ||
408 | |||
409 | dev->addr_len = IEEE802154_ADDR_LEN; | ||
410 | memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN); | ||
411 | |||
412 | dev->hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN; | ||
413 | dev->header_ops = &mac802154_header_ops; | ||
414 | dev->needed_tailroom = 2 + 16; /* FCS + MIC */ | ||
415 | dev->mtu = IEEE802154_MTU; | ||
416 | dev->tx_queue_len = 300; | ||
417 | dev->type = ARPHRD_IEEE802154; | ||
418 | dev->flags = IFF_NOARP | IFF_BROADCAST; | ||
419 | |||
420 | dev->destructor = mac802154_wpan_free; | ||
421 | dev->netdev_ops = &mac802154_wpan_ops; | ||
422 | dev->ml_priv = &mac802154_mlme_wpan; | ||
423 | |||
424 | sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
425 | sdata->type = IEEE802154_DEV_WPAN; | ||
426 | |||
427 | spin_lock_init(&sdata->mib_lock); | ||
428 | mutex_init(&sdata->sec_mtx); | ||
429 | |||
430 | get_random_bytes(&sdata->bsn, 1); | ||
431 | get_random_bytes(&sdata->dsn, 1); | ||
432 | |||
433 | /* defaults per 802.15.4-2011 */ | ||
434 | sdata->mac_params.min_be = 3; | ||
435 | sdata->mac_params.max_be = 5; | ||
436 | sdata->mac_params.csma_retries = 4; | ||
437 | /* for compatibility, actual default is 3 */ | ||
438 | sdata->mac_params.frame_retries = -1; | ||
439 | |||
440 | sdata->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST); | ||
441 | sdata->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST); | ||
442 | |||
443 | sdata->promisuous_mode = false; | ||
444 | |||
445 | mac802154_llsec_init(&sdata->sec); | ||
446 | } | ||
447 | |||
448 | void mac802154_monitor_setup(struct net_device *dev) | ||
449 | { | ||
450 | struct ieee802154_sub_if_data *sdata; | ||
451 | |||
452 | dev->needed_tailroom = 2; /* room for FCS */ | ||
453 | dev->mtu = IEEE802154_MTU; | ||
454 | dev->tx_queue_len = 10; | ||
455 | dev->type = ARPHRD_IEEE802154_MONITOR; | ||
456 | dev->flags = IFF_NOARP | IFF_BROADCAST; | ||
457 | |||
458 | dev->destructor = free_netdev; | ||
459 | dev->netdev_ops = &mac802154_monitor_ops; | ||
460 | dev->ml_priv = &mac802154_mlme_reduced; | ||
461 | |||
462 | sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
463 | sdata->type = IEEE802154_DEV_MONITOR; | ||
464 | |||
465 | sdata->promisuous_mode = true; | ||
466 | } | ||
diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c index 457058142098..fa0d5237c2e0 100644 --- a/net/mac802154/llsec.c +++ b/net/mac802154/llsec.c | |||
@@ -17,10 +17,10 @@ | |||
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/bug.h> | 18 | #include <linux/bug.h> |
19 | #include <linux/completion.h> | 19 | #include <linux/completion.h> |
20 | #include <net/ieee802154.h> | 20 | #include <linux/ieee802154.h> |
21 | #include <crypto/algapi.h> | 21 | #include <crypto/algapi.h> |
22 | 22 | ||
23 | #include "mac802154.h" | 23 | #include "ieee802154_i.h" |
24 | #include "llsec.h" | 24 | #include "llsec.h" |
25 | 25 | ||
26 | static void llsec_key_put(struct mac802154_llsec_key *key); | 26 | static void llsec_key_put(struct mac802154_llsec_key *key); |
diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c index bf809131eef7..fc261ab33347 100644 --- a/net/mac802154/mac_cmd.c +++ b/net/mac802154/mac_cmd.c | |||
@@ -12,10 +12,6 @@ | |||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * Written by: | 15 | * Written by: |
20 | * Sergey Lapin <slapin@ossfans.org> | 16 | * Sergey Lapin <slapin@ossfans.org> |
21 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 17 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
@@ -24,14 +20,14 @@ | |||
24 | 20 | ||
25 | #include <linux/skbuff.h> | 21 | #include <linux/skbuff.h> |
26 | #include <linux/if_arp.h> | 22 | #include <linux/if_arp.h> |
23 | #include <linux/ieee802154.h> | ||
27 | 24 | ||
28 | #include <net/ieee802154.h> | ||
29 | #include <net/ieee802154_netdev.h> | 25 | #include <net/ieee802154_netdev.h> |
30 | #include <net/wpan-phy.h> | 26 | #include <net/cfg802154.h> |
31 | #include <net/mac802154.h> | 27 | #include <net/mac802154.h> |
32 | #include <net/nl802154.h> | 28 | #include <net/nl802154.h> |
33 | 29 | ||
34 | #include "mac802154.h" | 30 | #include "ieee802154_i.h" |
35 | 31 | ||
36 | static int mac802154_mlme_start_req(struct net_device *dev, | 32 | static int mac802154_mlme_start_req(struct net_device *dev, |
37 | struct ieee802154_addr *addr, | 33 | struct ieee802154_addr *addr, |
@@ -79,11 +75,33 @@ static int mac802154_mlme_start_req(struct net_device *dev, | |||
79 | 75 | ||
80 | static struct wpan_phy *mac802154_get_phy(const struct net_device *dev) | 76 | static struct wpan_phy *mac802154_get_phy(const struct net_device *dev) |
81 | { | 77 | { |
82 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 78 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
83 | 79 | ||
84 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 80 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
85 | 81 | ||
86 | return to_phy(get_device(&priv->hw->phy->dev)); | 82 | return to_phy(get_device(&sdata->local->phy->dev)); |
83 | } | ||
84 | |||
85 | static int mac802154_set_mac_params(struct net_device *dev, | ||
86 | const struct ieee802154_mac_params *params) | ||
87 | { | ||
88 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
89 | |||
90 | mutex_lock(&sdata->local->iflist_mtx); | ||
91 | sdata->mac_params = *params; | ||
92 | mutex_unlock(&sdata->local->iflist_mtx); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static void mac802154_get_mac_params(struct net_device *dev, | ||
98 | struct ieee802154_mac_params *params) | ||
99 | { | ||
100 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
101 | |||
102 | mutex_lock(&sdata->local->iflist_mtx); | ||
103 | *params = sdata->mac_params; | ||
104 | mutex_unlock(&sdata->local->iflist_mtx); | ||
87 | } | 105 | } |
88 | 106 | ||
89 | static struct ieee802154_llsec_ops mac802154_llsec_ops = { | 107 | static struct ieee802154_llsec_ops mac802154_llsec_ops = { |
diff --git a/net/mac802154/main.c b/net/mac802154/main.c new file mode 100644 index 000000000000..86e533ed3775 --- /dev/null +++ b/net/mac802154/main.c | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2012 Siemens AG | ||
3 | * | ||
4 | * Written by: | ||
5 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | ||
6 | * | ||
7 | * Based on the code from 'linux-zigbee.sourceforge.net' project. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 | ||
11 | * as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/netdevice.h> | ||
22 | |||
23 | #include <net/netlink.h> | ||
24 | #include <linux/nl802154.h> | ||
25 | #include <net/mac802154.h> | ||
26 | #include <net/ieee802154_netdev.h> | ||
27 | #include <net/route.h> | ||
28 | #include <net/cfg802154.h> | ||
29 | |||
30 | #include "ieee802154_i.h" | ||
31 | |||
32 | static int | ||
33 | mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev) | ||
34 | { | ||
35 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
36 | struct ieee802154_local *local; | ||
37 | int err; | ||
38 | |||
39 | local = wpan_phy_priv(phy); | ||
40 | |||
41 | sdata->dev = dev; | ||
42 | sdata->local = local; | ||
43 | |||
44 | dev->needed_headroom = local->hw.extra_tx_headroom; | ||
45 | |||
46 | SET_NETDEV_DEV(dev, &local->phy->dev); | ||
47 | |||
48 | err = register_netdev(dev); | ||
49 | if (err < 0) | ||
50 | return err; | ||
51 | |||
52 | rtnl_lock(); | ||
53 | mutex_lock(&local->iflist_mtx); | ||
54 | list_add_tail_rcu(&sdata->list, &local->interfaces); | ||
55 | mutex_unlock(&local->iflist_mtx); | ||
56 | rtnl_unlock(); | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev) | ||
63 | { | ||
64 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
65 | |||
66 | ASSERT_RTNL(); | ||
67 | |||
68 | BUG_ON(sdata->local->phy != phy); | ||
69 | |||
70 | mutex_lock(&sdata->local->iflist_mtx); | ||
71 | list_del_rcu(&sdata->list); | ||
72 | mutex_unlock(&sdata->local->iflist_mtx); | ||
73 | |||
74 | synchronize_rcu(); | ||
75 | unregister_netdevice(sdata->dev); | ||
76 | } | ||
77 | |||
78 | static struct net_device * | ||
79 | mac802154_add_iface(struct wpan_phy *phy, const char *name, int type) | ||
80 | { | ||
81 | struct net_device *dev; | ||
82 | int err = -ENOMEM; | ||
83 | |||
84 | switch (type) { | ||
85 | case IEEE802154_DEV_MONITOR: | ||
86 | dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data), | ||
87 | name, NET_NAME_UNKNOWN, | ||
88 | mac802154_monitor_setup); | ||
89 | break; | ||
90 | case IEEE802154_DEV_WPAN: | ||
91 | dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data), | ||
92 | name, NET_NAME_UNKNOWN, | ||
93 | mac802154_wpan_setup); | ||
94 | break; | ||
95 | default: | ||
96 | dev = NULL; | ||
97 | err = -EINVAL; | ||
98 | break; | ||
99 | } | ||
100 | if (!dev) | ||
101 | goto err; | ||
102 | |||
103 | err = mac802154_netdev_register(phy, dev); | ||
104 | if (err) | ||
105 | goto err_free; | ||
106 | |||
107 | dev_hold(dev); /* we return an incremented device refcount */ | ||
108 | return dev; | ||
109 | |||
110 | err_free: | ||
111 | free_netdev(dev); | ||
112 | err: | ||
113 | return ERR_PTR(err); | ||
114 | } | ||
115 | |||
116 | static void ieee802154_tasklet_handler(unsigned long data) | ||
117 | { | ||
118 | struct ieee802154_local *local = (struct ieee802154_local *)data; | ||
119 | struct sk_buff *skb; | ||
120 | |||
121 | while ((skb = skb_dequeue(&local->skb_queue))) { | ||
122 | switch (skb->pkt_type) { | ||
123 | case IEEE802154_RX_MSG: | ||
124 | /* Clear skb->pkt_type in order to not confuse kernel | ||
125 | * netstack. | ||
126 | */ | ||
127 | skb->pkt_type = 0; | ||
128 | ieee802154_rx(&local->hw, skb); | ||
129 | break; | ||
130 | default: | ||
131 | WARN(1, "mac802154: Packet is of unknown type %d\n", | ||
132 | skb->pkt_type); | ||
133 | kfree_skb(skb); | ||
134 | break; | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
139 | struct ieee802154_hw * | ||
140 | ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) | ||
141 | { | ||
142 | struct wpan_phy *phy; | ||
143 | struct ieee802154_local *local; | ||
144 | size_t priv_size; | ||
145 | |||
146 | if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed || | ||
147 | !ops->start || !ops->stop || !ops->set_channel) { | ||
148 | pr_err("undefined IEEE802.15.4 device operations\n"); | ||
149 | return NULL; | ||
150 | } | ||
151 | |||
152 | /* Ensure 32-byte alignment of our private data and hw private data. | ||
153 | * We use the wpan_phy priv data for both our ieee802154_local and for | ||
154 | * the driver's private data | ||
155 | * | ||
156 | * in memory it'll be like this: | ||
157 | * | ||
158 | * +-------------------------+ | ||
159 | * | struct wpan_phy | | ||
160 | * +-------------------------+ | ||
161 | * | struct ieee802154_local | | ||
162 | * +-------------------------+ | ||
163 | * | driver's private data | | ||
164 | * +-------------------------+ | ||
165 | * | ||
166 | * Due to ieee802154 layer isn't aware of driver and MAC structures, | ||
167 | * so lets align them here. | ||
168 | */ | ||
169 | |||
170 | priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; | ||
171 | |||
172 | phy = wpan_phy_alloc(priv_size); | ||
173 | if (!phy) { | ||
174 | pr_err("failure to allocate master IEEE802.15.4 device\n"); | ||
175 | return NULL; | ||
176 | } | ||
177 | |||
178 | local = wpan_phy_priv(phy); | ||
179 | local->phy = phy; | ||
180 | local->hw.phy = local->phy; | ||
181 | local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); | ||
182 | local->ops = ops; | ||
183 | |||
184 | INIT_LIST_HEAD(&local->interfaces); | ||
185 | mutex_init(&local->iflist_mtx); | ||
186 | |||
187 | tasklet_init(&local->tasklet, | ||
188 | ieee802154_tasklet_handler, | ||
189 | (unsigned long)local); | ||
190 | |||
191 | skb_queue_head_init(&local->skb_queue); | ||
192 | |||
193 | return &local->hw; | ||
194 | } | ||
195 | EXPORT_SYMBOL(ieee802154_alloc_hw); | ||
196 | |||
197 | void ieee802154_free_hw(struct ieee802154_hw *hw) | ||
198 | { | ||
199 | struct ieee802154_local *local = hw_to_local(hw); | ||
200 | |||
201 | BUG_ON(!list_empty(&local->interfaces)); | ||
202 | |||
203 | mutex_destroy(&local->iflist_mtx); | ||
204 | |||
205 | wpan_phy_free(local->phy); | ||
206 | } | ||
207 | EXPORT_SYMBOL(ieee802154_free_hw); | ||
208 | |||
209 | int ieee802154_register_hw(struct ieee802154_hw *hw) | ||
210 | { | ||
211 | struct ieee802154_local *local = hw_to_local(hw); | ||
212 | int rc = -ENOSYS; | ||
213 | |||
214 | local->workqueue = | ||
215 | create_singlethread_workqueue(wpan_phy_name(local->phy)); | ||
216 | if (!local->workqueue) { | ||
217 | rc = -ENOMEM; | ||
218 | goto out; | ||
219 | } | ||
220 | |||
221 | wpan_phy_set_dev(local->phy, local->hw.parent); | ||
222 | |||
223 | local->phy->add_iface = mac802154_add_iface; | ||
224 | local->phy->del_iface = mac802154_del_iface; | ||
225 | |||
226 | rc = wpan_phy_register(local->phy); | ||
227 | if (rc < 0) | ||
228 | goto out_wq; | ||
229 | |||
230 | return 0; | ||
231 | |||
232 | out_wq: | ||
233 | destroy_workqueue(local->workqueue); | ||
234 | out: | ||
235 | return rc; | ||
236 | } | ||
237 | EXPORT_SYMBOL(ieee802154_register_hw); | ||
238 | |||
239 | void ieee802154_unregister_hw(struct ieee802154_hw *hw) | ||
240 | { | ||
241 | struct ieee802154_local *local = hw_to_local(hw); | ||
242 | struct ieee802154_sub_if_data *sdata, *next; | ||
243 | |||
244 | tasklet_kill(&local->tasklet); | ||
245 | flush_workqueue(local->workqueue); | ||
246 | destroy_workqueue(local->workqueue); | ||
247 | |||
248 | rtnl_lock(); | ||
249 | |||
250 | list_for_each_entry_safe(sdata, next, &local->interfaces, list) { | ||
251 | mutex_lock(&sdata->local->iflist_mtx); | ||
252 | list_del(&sdata->list); | ||
253 | mutex_unlock(&sdata->local->iflist_mtx); | ||
254 | |||
255 | unregister_netdevice(sdata->dev); | ||
256 | } | ||
257 | |||
258 | rtnl_unlock(); | ||
259 | |||
260 | wpan_phy_unregister(local->phy); | ||
261 | } | ||
262 | EXPORT_SYMBOL(ieee802154_unregister_hw); | ||
263 | |||
264 | MODULE_DESCRIPTION("IEEE 802.15.4 implementation"); | ||
265 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/net/mac802154/mib.c b/net/mac802154/mib.c index 868a040fd422..0184fced2f62 100644 --- a/net/mac802154/mib.c +++ b/net/mac802154/mib.c | |||
@@ -10,10 +10,6 @@ | |||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Written by: | 13 | * Written by: |
18 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 14 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
19 | * Sergey Lapin <slapin@ossfans.org> | 15 | * Sergey Lapin <slapin@ossfans.org> |
@@ -25,14 +21,10 @@ | |||
25 | 21 | ||
26 | #include <net/mac802154.h> | 22 | #include <net/mac802154.h> |
27 | #include <net/ieee802154_netdev.h> | 23 | #include <net/ieee802154_netdev.h> |
28 | #include <net/wpan-phy.h> | 24 | #include <net/cfg802154.h> |
29 | |||
30 | #include "mac802154.h" | ||
31 | 25 | ||
32 | struct phy_chan_notify_work { | 26 | #include "ieee802154_i.h" |
33 | struct work_struct work; | 27 | #include "driver-ops.h" |
34 | struct net_device *dev; | ||
35 | }; | ||
36 | 28 | ||
37 | struct hw_addr_filt_notify_work { | 29 | struct hw_addr_filt_notify_work { |
38 | struct work_struct work; | 30 | struct work_struct work; |
@@ -40,25 +32,24 @@ struct hw_addr_filt_notify_work { | |||
40 | unsigned long changed; | 32 | unsigned long changed; |
41 | }; | 33 | }; |
42 | 34 | ||
43 | static struct mac802154_priv *mac802154_slave_get_priv(struct net_device *dev) | 35 | static struct ieee802154_local *mac802154_slave_get_priv(struct net_device *dev) |
44 | { | 36 | { |
45 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 37 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
46 | 38 | ||
47 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 39 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
48 | 40 | ||
49 | return priv->hw; | 41 | return sdata->local; |
50 | } | 42 | } |
51 | 43 | ||
52 | static void hw_addr_notify(struct work_struct *work) | 44 | static void hw_addr_notify(struct work_struct *work) |
53 | { | 45 | { |
54 | struct hw_addr_filt_notify_work *nw = container_of(work, | 46 | struct hw_addr_filt_notify_work *nw = container_of(work, |
55 | struct hw_addr_filt_notify_work, work); | 47 | struct hw_addr_filt_notify_work, work); |
56 | struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev); | 48 | struct ieee802154_local *local = mac802154_slave_get_priv(nw->dev); |
57 | int res; | 49 | int res; |
58 | 50 | ||
59 | res = hw->ops->set_hw_addr_filt(&hw->hw, | 51 | res = local->ops->set_hw_addr_filt(&local->hw, &local->hw.hw_filt, |
60 | &hw->hw.hw_filt, | 52 | nw->changed); |
61 | nw->changed); | ||
62 | if (res) | 53 | if (res) |
63 | pr_debug("failed changed mask %lx\n", nw->changed); | 54 | pr_debug("failed changed mask %lx\n", nw->changed); |
64 | 55 | ||
@@ -67,7 +58,7 @@ static void hw_addr_notify(struct work_struct *work) | |||
67 | 58 | ||
68 | static void set_hw_addr_filt(struct net_device *dev, unsigned long changed) | 59 | static void set_hw_addr_filt(struct net_device *dev, unsigned long changed) |
69 | { | 60 | { |
70 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 61 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
71 | struct hw_addr_filt_notify_work *work; | 62 | struct hw_addr_filt_notify_work *work; |
72 | 63 | ||
73 | work = kzalloc(sizeof(*work), GFP_ATOMIC); | 64 | work = kzalloc(sizeof(*work), GFP_ATOMIC); |
@@ -77,141 +68,110 @@ static void set_hw_addr_filt(struct net_device *dev, unsigned long changed) | |||
77 | INIT_WORK(&work->work, hw_addr_notify); | 68 | INIT_WORK(&work->work, hw_addr_notify); |
78 | work->dev = dev; | 69 | work->dev = dev; |
79 | work->changed = changed; | 70 | work->changed = changed; |
80 | queue_work(priv->hw->dev_workqueue, &work->work); | 71 | queue_work(sdata->local->workqueue, &work->work); |
81 | } | 72 | } |
82 | 73 | ||
83 | void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val) | 74 | void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val) |
84 | { | 75 | { |
85 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 76 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
86 | 77 | ||
87 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 78 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
88 | 79 | ||
89 | spin_lock_bh(&priv->mib_lock); | 80 | spin_lock_bh(&sdata->mib_lock); |
90 | priv->short_addr = val; | 81 | sdata->short_addr = val; |
91 | spin_unlock_bh(&priv->mib_lock); | 82 | spin_unlock_bh(&sdata->mib_lock); |
92 | 83 | ||
93 | if ((priv->hw->ops->set_hw_addr_filt) && | 84 | if ((sdata->local->ops->set_hw_addr_filt) && |
94 | (priv->hw->hw.hw_filt.short_addr != priv->short_addr)) { | 85 | (sdata->local->hw.hw_filt.short_addr != sdata->short_addr)) { |
95 | priv->hw->hw.hw_filt.short_addr = priv->short_addr; | 86 | sdata->local->hw.hw_filt.short_addr = sdata->short_addr; |
96 | set_hw_addr_filt(dev, IEEE802515_AFILT_SADDR_CHANGED); | 87 | set_hw_addr_filt(dev, IEEE802154_AFILT_SADDR_CHANGED); |
97 | } | 88 | } |
98 | } | 89 | } |
99 | 90 | ||
100 | __le16 mac802154_dev_get_short_addr(const struct net_device *dev) | 91 | __le16 mac802154_dev_get_short_addr(const struct net_device *dev) |
101 | { | 92 | { |
102 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 93 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
103 | __le16 ret; | 94 | __le16 ret; |
104 | 95 | ||
105 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 96 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
106 | 97 | ||
107 | spin_lock_bh(&priv->mib_lock); | 98 | spin_lock_bh(&sdata->mib_lock); |
108 | ret = priv->short_addr; | 99 | ret = sdata->short_addr; |
109 | spin_unlock_bh(&priv->mib_lock); | 100 | spin_unlock_bh(&sdata->mib_lock); |
110 | 101 | ||
111 | return ret; | 102 | return ret; |
112 | } | 103 | } |
113 | 104 | ||
114 | void mac802154_dev_set_ieee_addr(struct net_device *dev) | 105 | void mac802154_dev_set_ieee_addr(struct net_device *dev) |
115 | { | 106 | { |
116 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 107 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
117 | struct mac802154_priv *mac = priv->hw; | 108 | struct ieee802154_local *local = sdata->local; |
118 | 109 | ||
119 | priv->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr); | 110 | sdata->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr); |
120 | 111 | ||
121 | if (mac->ops->set_hw_addr_filt && | 112 | if (local->ops->set_hw_addr_filt && |
122 | mac->hw.hw_filt.ieee_addr != priv->extended_addr) { | 113 | local->hw.hw_filt.ieee_addr != sdata->extended_addr) { |
123 | mac->hw.hw_filt.ieee_addr = priv->extended_addr; | 114 | local->hw.hw_filt.ieee_addr = sdata->extended_addr; |
124 | set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED); | 115 | set_hw_addr_filt(dev, IEEE802154_AFILT_IEEEADDR_CHANGED); |
125 | } | 116 | } |
126 | } | 117 | } |
127 | 118 | ||
128 | __le16 mac802154_dev_get_pan_id(const struct net_device *dev) | 119 | __le16 mac802154_dev_get_pan_id(const struct net_device *dev) |
129 | { | 120 | { |
130 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 121 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
131 | __le16 ret; | 122 | __le16 ret; |
132 | 123 | ||
133 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 124 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
134 | 125 | ||
135 | spin_lock_bh(&priv->mib_lock); | 126 | spin_lock_bh(&sdata->mib_lock); |
136 | ret = priv->pan_id; | 127 | ret = sdata->pan_id; |
137 | spin_unlock_bh(&priv->mib_lock); | 128 | spin_unlock_bh(&sdata->mib_lock); |
138 | 129 | ||
139 | return ret; | 130 | return ret; |
140 | } | 131 | } |
141 | 132 | ||
142 | void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val) | 133 | void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val) |
143 | { | 134 | { |
144 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 135 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
145 | 136 | ||
146 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 137 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
147 | 138 | ||
148 | spin_lock_bh(&priv->mib_lock); | 139 | spin_lock_bh(&sdata->mib_lock); |
149 | priv->pan_id = val; | 140 | sdata->pan_id = val; |
150 | spin_unlock_bh(&priv->mib_lock); | 141 | spin_unlock_bh(&sdata->mib_lock); |
151 | 142 | ||
152 | if ((priv->hw->ops->set_hw_addr_filt) && | 143 | if ((sdata->local->ops->set_hw_addr_filt) && |
153 | (priv->hw->hw.hw_filt.pan_id != priv->pan_id)) { | 144 | (sdata->local->hw.hw_filt.pan_id != sdata->pan_id)) { |
154 | priv->hw->hw.hw_filt.pan_id = priv->pan_id; | 145 | sdata->local->hw.hw_filt.pan_id = sdata->pan_id; |
155 | set_hw_addr_filt(dev, IEEE802515_AFILT_PANID_CHANGED); | 146 | set_hw_addr_filt(dev, IEEE802154_AFILT_PANID_CHANGED); |
156 | } | 147 | } |
157 | } | 148 | } |
158 | 149 | ||
159 | u8 mac802154_dev_get_dsn(const struct net_device *dev) | 150 | u8 mac802154_dev_get_dsn(const struct net_device *dev) |
160 | { | 151 | { |
161 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 152 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
162 | 153 | ||
163 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 154 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
164 | 155 | ||
165 | return priv->dsn++; | 156 | return sdata->dsn++; |
166 | } | ||
167 | |||
168 | static void phy_chan_notify(struct work_struct *work) | ||
169 | { | ||
170 | struct phy_chan_notify_work *nw = container_of(work, | ||
171 | struct phy_chan_notify_work, work); | ||
172 | struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev); | ||
173 | struct mac802154_sub_if_data *priv = netdev_priv(nw->dev); | ||
174 | int res; | ||
175 | |||
176 | mutex_lock(&priv->hw->phy->pib_lock); | ||
177 | res = hw->ops->set_channel(&hw->hw, priv->page, priv->chan); | ||
178 | if (res) { | ||
179 | pr_debug("set_channel failed\n"); | ||
180 | } else { | ||
181 | priv->hw->phy->current_channel = priv->chan; | ||
182 | priv->hw->phy->current_page = priv->page; | ||
183 | } | ||
184 | mutex_unlock(&priv->hw->phy->pib_lock); | ||
185 | |||
186 | kfree(nw); | ||
187 | } | 157 | } |
188 | 158 | ||
189 | void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) | 159 | void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) |
190 | { | 160 | { |
191 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 161 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
192 | struct phy_chan_notify_work *work; | 162 | struct ieee802154_local *local = sdata->local; |
163 | int res; | ||
193 | 164 | ||
194 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 165 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
195 | 166 | ||
196 | spin_lock_bh(&priv->mib_lock); | 167 | res = drv_set_channel(local, page, chan); |
197 | priv->page = page; | 168 | if (res) { |
198 | priv->chan = chan; | 169 | pr_debug("set_channel failed\n"); |
199 | spin_unlock_bh(&priv->mib_lock); | ||
200 | |||
201 | mutex_lock(&priv->hw->phy->pib_lock); | ||
202 | if (priv->hw->phy->current_channel != priv->chan || | ||
203 | priv->hw->phy->current_page != priv->page) { | ||
204 | mutex_unlock(&priv->hw->phy->pib_lock); | ||
205 | |||
206 | work = kzalloc(sizeof(*work), GFP_ATOMIC); | ||
207 | if (!work) | ||
208 | return; | ||
209 | |||
210 | INIT_WORK(&work->work, phy_chan_notify); | ||
211 | work->dev = dev; | ||
212 | queue_work(priv->hw->dev_workqueue, &work->work); | ||
213 | } else { | 170 | } else { |
214 | mutex_unlock(&priv->hw->phy->pib_lock); | 171 | mutex_lock(&local->phy->pib_lock); |
172 | local->phy->current_channel = chan; | ||
173 | local->phy->current_page = page; | ||
174 | mutex_unlock(&local->phy->pib_lock); | ||
215 | } | 175 | } |
216 | } | 176 | } |
217 | 177 | ||
@@ -219,14 +179,14 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan) | |||
219 | int mac802154_get_params(struct net_device *dev, | 179 | int mac802154_get_params(struct net_device *dev, |
220 | struct ieee802154_llsec_params *params) | 180 | struct ieee802154_llsec_params *params) |
221 | { | 181 | { |
222 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 182 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
223 | int res; | 183 | int res; |
224 | 184 | ||
225 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 185 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
226 | 186 | ||
227 | mutex_lock(&priv->sec_mtx); | 187 | mutex_lock(&sdata->sec_mtx); |
228 | res = mac802154_llsec_get_params(&priv->sec, params); | 188 | res = mac802154_llsec_get_params(&sdata->sec, params); |
229 | mutex_unlock(&priv->sec_mtx); | 189 | mutex_unlock(&sdata->sec_mtx); |
230 | 190 | ||
231 | return res; | 191 | return res; |
232 | } | 192 | } |
@@ -235,14 +195,14 @@ int mac802154_set_params(struct net_device *dev, | |||
235 | const struct ieee802154_llsec_params *params, | 195 | const struct ieee802154_llsec_params *params, |
236 | int changed) | 196 | int changed) |
237 | { | 197 | { |
238 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 198 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
239 | int res; | 199 | int res; |
240 | 200 | ||
241 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 201 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
242 | 202 | ||
243 | mutex_lock(&priv->sec_mtx); | 203 | mutex_lock(&sdata->sec_mtx); |
244 | res = mac802154_llsec_set_params(&priv->sec, params, changed); | 204 | res = mac802154_llsec_set_params(&sdata->sec, params, changed); |
245 | mutex_unlock(&priv->sec_mtx); | 205 | mutex_unlock(&sdata->sec_mtx); |
246 | 206 | ||
247 | return res; | 207 | return res; |
248 | } | 208 | } |
@@ -252,14 +212,14 @@ int mac802154_add_key(struct net_device *dev, | |||
252 | const struct ieee802154_llsec_key_id *id, | 212 | const struct ieee802154_llsec_key_id *id, |
253 | const struct ieee802154_llsec_key *key) | 213 | const struct ieee802154_llsec_key *key) |
254 | { | 214 | { |
255 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 215 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
256 | int res; | 216 | int res; |
257 | 217 | ||
258 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 218 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
259 | 219 | ||
260 | mutex_lock(&priv->sec_mtx); | 220 | mutex_lock(&sdata->sec_mtx); |
261 | res = mac802154_llsec_key_add(&priv->sec, id, key); | 221 | res = mac802154_llsec_key_add(&sdata->sec, id, key); |
262 | mutex_unlock(&priv->sec_mtx); | 222 | mutex_unlock(&sdata->sec_mtx); |
263 | 223 | ||
264 | return res; | 224 | return res; |
265 | } | 225 | } |
@@ -267,14 +227,14 @@ int mac802154_add_key(struct net_device *dev, | |||
267 | int mac802154_del_key(struct net_device *dev, | 227 | int mac802154_del_key(struct net_device *dev, |
268 | const struct ieee802154_llsec_key_id *id) | 228 | const struct ieee802154_llsec_key_id *id) |
269 | { | 229 | { |
270 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 230 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
271 | int res; | 231 | int res; |
272 | 232 | ||
273 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 233 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
274 | 234 | ||
275 | mutex_lock(&priv->sec_mtx); | 235 | mutex_lock(&sdata->sec_mtx); |
276 | res = mac802154_llsec_key_del(&priv->sec, id); | 236 | res = mac802154_llsec_key_del(&sdata->sec, id); |
277 | mutex_unlock(&priv->sec_mtx); | 237 | mutex_unlock(&sdata->sec_mtx); |
278 | 238 | ||
279 | return res; | 239 | return res; |
280 | } | 240 | } |
@@ -283,28 +243,28 @@ int mac802154_del_key(struct net_device *dev, | |||
283 | int mac802154_add_dev(struct net_device *dev, | 243 | int mac802154_add_dev(struct net_device *dev, |
284 | const struct ieee802154_llsec_device *llsec_dev) | 244 | const struct ieee802154_llsec_device *llsec_dev) |
285 | { | 245 | { |
286 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 246 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
287 | int res; | 247 | int res; |
288 | 248 | ||
289 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 249 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
290 | 250 | ||
291 | mutex_lock(&priv->sec_mtx); | 251 | mutex_lock(&sdata->sec_mtx); |
292 | res = mac802154_llsec_dev_add(&priv->sec, llsec_dev); | 252 | res = mac802154_llsec_dev_add(&sdata->sec, llsec_dev); |
293 | mutex_unlock(&priv->sec_mtx); | 253 | mutex_unlock(&sdata->sec_mtx); |
294 | 254 | ||
295 | return res; | 255 | return res; |
296 | } | 256 | } |
297 | 257 | ||
298 | int mac802154_del_dev(struct net_device *dev, __le64 dev_addr) | 258 | int mac802154_del_dev(struct net_device *dev, __le64 dev_addr) |
299 | { | 259 | { |
300 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 260 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
301 | int res; | 261 | int res; |
302 | 262 | ||
303 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 263 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
304 | 264 | ||
305 | mutex_lock(&priv->sec_mtx); | 265 | mutex_lock(&sdata->sec_mtx); |
306 | res = mac802154_llsec_dev_del(&priv->sec, dev_addr); | 266 | res = mac802154_llsec_dev_del(&sdata->sec, dev_addr); |
307 | mutex_unlock(&priv->sec_mtx); | 267 | mutex_unlock(&sdata->sec_mtx); |
308 | 268 | ||
309 | return res; | 269 | return res; |
310 | } | 270 | } |
@@ -314,14 +274,14 @@ int mac802154_add_devkey(struct net_device *dev, | |||
314 | __le64 device_addr, | 274 | __le64 device_addr, |
315 | const struct ieee802154_llsec_device_key *key) | 275 | const struct ieee802154_llsec_device_key *key) |
316 | { | 276 | { |
317 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 277 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
318 | int res; | 278 | int res; |
319 | 279 | ||
320 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 280 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
321 | 281 | ||
322 | mutex_lock(&priv->sec_mtx); | 282 | mutex_lock(&sdata->sec_mtx); |
323 | res = mac802154_llsec_devkey_add(&priv->sec, device_addr, key); | 283 | res = mac802154_llsec_devkey_add(&sdata->sec, device_addr, key); |
324 | mutex_unlock(&priv->sec_mtx); | 284 | mutex_unlock(&sdata->sec_mtx); |
325 | 285 | ||
326 | return res; | 286 | return res; |
327 | } | 287 | } |
@@ -330,14 +290,14 @@ int mac802154_del_devkey(struct net_device *dev, | |||
330 | __le64 device_addr, | 290 | __le64 device_addr, |
331 | const struct ieee802154_llsec_device_key *key) | 291 | const struct ieee802154_llsec_device_key *key) |
332 | { | 292 | { |
333 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 293 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
334 | int res; | 294 | int res; |
335 | 295 | ||
336 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 296 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
337 | 297 | ||
338 | mutex_lock(&priv->sec_mtx); | 298 | mutex_lock(&sdata->sec_mtx); |
339 | res = mac802154_llsec_devkey_del(&priv->sec, device_addr, key); | 299 | res = mac802154_llsec_devkey_del(&sdata->sec, device_addr, key); |
340 | mutex_unlock(&priv->sec_mtx); | 300 | mutex_unlock(&sdata->sec_mtx); |
341 | 301 | ||
342 | return res; | 302 | return res; |
343 | } | 303 | } |
@@ -346,14 +306,14 @@ int mac802154_del_devkey(struct net_device *dev, | |||
346 | int mac802154_add_seclevel(struct net_device *dev, | 306 | int mac802154_add_seclevel(struct net_device *dev, |
347 | const struct ieee802154_llsec_seclevel *sl) | 307 | const struct ieee802154_llsec_seclevel *sl) |
348 | { | 308 | { |
349 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 309 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
350 | int res; | 310 | int res; |
351 | 311 | ||
352 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 312 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
353 | 313 | ||
354 | mutex_lock(&priv->sec_mtx); | 314 | mutex_lock(&sdata->sec_mtx); |
355 | res = mac802154_llsec_seclevel_add(&priv->sec, sl); | 315 | res = mac802154_llsec_seclevel_add(&sdata->sec, sl); |
356 | mutex_unlock(&priv->sec_mtx); | 316 | mutex_unlock(&sdata->sec_mtx); |
357 | 317 | ||
358 | return res; | 318 | return res; |
359 | } | 319 | } |
@@ -361,14 +321,14 @@ int mac802154_add_seclevel(struct net_device *dev, | |||
361 | int mac802154_del_seclevel(struct net_device *dev, | 321 | int mac802154_del_seclevel(struct net_device *dev, |
362 | const struct ieee802154_llsec_seclevel *sl) | 322 | const struct ieee802154_llsec_seclevel *sl) |
363 | { | 323 | { |
364 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 324 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
365 | int res; | 325 | int res; |
366 | 326 | ||
367 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 327 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
368 | 328 | ||
369 | mutex_lock(&priv->sec_mtx); | 329 | mutex_lock(&sdata->sec_mtx); |
370 | res = mac802154_llsec_seclevel_del(&priv->sec, sl); | 330 | res = mac802154_llsec_seclevel_del(&sdata->sec, sl); |
371 | mutex_unlock(&priv->sec_mtx); | 331 | mutex_unlock(&sdata->sec_mtx); |
372 | 332 | ||
373 | return res; | 333 | return res; |
374 | } | 334 | } |
@@ -376,28 +336,28 @@ int mac802154_del_seclevel(struct net_device *dev, | |||
376 | 336 | ||
377 | void mac802154_lock_table(struct net_device *dev) | 337 | void mac802154_lock_table(struct net_device *dev) |
378 | { | 338 | { |
379 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 339 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
380 | 340 | ||
381 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 341 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
382 | 342 | ||
383 | mutex_lock(&priv->sec_mtx); | 343 | mutex_lock(&sdata->sec_mtx); |
384 | } | 344 | } |
385 | 345 | ||
386 | void mac802154_get_table(struct net_device *dev, | 346 | void mac802154_get_table(struct net_device *dev, |
387 | struct ieee802154_llsec_table **t) | 347 | struct ieee802154_llsec_table **t) |
388 | { | 348 | { |
389 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 349 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
390 | 350 | ||
391 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 351 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
392 | 352 | ||
393 | *t = &priv->sec.table; | 353 | *t = &sdata->sec.table; |
394 | } | 354 | } |
395 | 355 | ||
396 | void mac802154_unlock_table(struct net_device *dev) | 356 | void mac802154_unlock_table(struct net_device *dev) |
397 | { | 357 | { |
398 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | 358 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); |
399 | 359 | ||
400 | BUG_ON(dev->type != ARPHRD_IEEE802154); | 360 | BUG_ON(dev->type != ARPHRD_IEEE802154); |
401 | 361 | ||
402 | mutex_unlock(&priv->sec_mtx); | 362 | mutex_unlock(&sdata->sec_mtx); |
403 | } | 363 | } |
diff --git a/net/mac802154/monitor.c b/net/mac802154/monitor.c deleted file mode 100644 index a68230e2b25f..000000000000 --- a/net/mac802154/monitor.c +++ /dev/null | |||
@@ -1,117 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2007, 2008, 2009 Siemens AG | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 | ||
6 | * as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Written by: | ||
18 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | ||
19 | * Sergey Lapin <slapin@ossfans.org> | ||
20 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> | ||
21 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | ||
22 | */ | ||
23 | |||
24 | #include <linux/netdevice.h> | ||
25 | #include <linux/skbuff.h> | ||
26 | #include <linux/if_arp.h> | ||
27 | #include <linux/crc-ccitt.h> | ||
28 | |||
29 | #include <net/ieee802154.h> | ||
30 | #include <net/mac802154.h> | ||
31 | #include <net/netlink.h> | ||
32 | #include <net/wpan-phy.h> | ||
33 | #include <linux/nl802154.h> | ||
34 | |||
35 | #include "mac802154.h" | ||
36 | |||
37 | static netdev_tx_t mac802154_monitor_xmit(struct sk_buff *skb, | ||
38 | struct net_device *dev) | ||
39 | { | ||
40 | struct mac802154_sub_if_data *priv; | ||
41 | u8 chan, page; | ||
42 | |||
43 | priv = netdev_priv(dev); | ||
44 | |||
45 | /* FIXME: locking */ | ||
46 | chan = priv->hw->phy->current_channel; | ||
47 | page = priv->hw->phy->current_page; | ||
48 | |||
49 | if (chan == MAC802154_CHAN_NONE) /* not initialized */ | ||
50 | return NETDEV_TX_OK; | ||
51 | |||
52 | if (WARN_ON(page >= WPAN_NUM_PAGES) || | ||
53 | WARN_ON(chan >= WPAN_NUM_CHANNELS)) | ||
54 | return NETDEV_TX_OK; | ||
55 | |||
56 | skb->skb_iif = dev->ifindex; | ||
57 | dev->stats.tx_packets++; | ||
58 | dev->stats.tx_bytes += skb->len; | ||
59 | |||
60 | return mac802154_tx(priv->hw, skb, page, chan); | ||
61 | } | ||
62 | |||
63 | |||
64 | void mac802154_monitors_rx(struct mac802154_priv *priv, struct sk_buff *skb) | ||
65 | { | ||
66 | struct sk_buff *skb2; | ||
67 | struct mac802154_sub_if_data *sdata; | ||
68 | u16 crc = crc_ccitt(0, skb->data, skb->len); | ||
69 | u8 *data; | ||
70 | |||
71 | rcu_read_lock(); | ||
72 | list_for_each_entry_rcu(sdata, &priv->slaves, list) { | ||
73 | if (sdata->type != IEEE802154_DEV_MONITOR || | ||
74 | !netif_running(sdata->dev)) | ||
75 | continue; | ||
76 | |||
77 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
78 | skb2->dev = sdata->dev; | ||
79 | skb2->pkt_type = PACKET_HOST; | ||
80 | data = skb_put(skb2, 2); | ||
81 | data[0] = crc & 0xff; | ||
82 | data[1] = crc >> 8; | ||
83 | |||
84 | netif_rx_ni(skb2); | ||
85 | } | ||
86 | rcu_read_unlock(); | ||
87 | } | ||
88 | |||
89 | static const struct net_device_ops mac802154_monitor_ops = { | ||
90 | .ndo_open = mac802154_slave_open, | ||
91 | .ndo_stop = mac802154_slave_close, | ||
92 | .ndo_start_xmit = mac802154_monitor_xmit, | ||
93 | }; | ||
94 | |||
95 | void mac802154_monitor_setup(struct net_device *dev) | ||
96 | { | ||
97 | struct mac802154_sub_if_data *priv; | ||
98 | |||
99 | dev->addr_len = 0; | ||
100 | dev->hard_header_len = 0; | ||
101 | dev->needed_tailroom = 2; /* room for FCS */ | ||
102 | dev->mtu = IEEE802154_MTU; | ||
103 | dev->tx_queue_len = 10; | ||
104 | dev->type = ARPHRD_IEEE802154_MONITOR; | ||
105 | dev->flags = IFF_NOARP | IFF_BROADCAST; | ||
106 | dev->watchdog_timeo = 0; | ||
107 | |||
108 | dev->destructor = free_netdev; | ||
109 | dev->netdev_ops = &mac802154_monitor_ops; | ||
110 | dev->ml_priv = &mac802154_mlme_reduced; | ||
111 | |||
112 | priv = netdev_priv(dev); | ||
113 | priv->type = IEEE802154_DEV_MONITOR; | ||
114 | |||
115 | priv->chan = MAC802154_CHAN_NONE; /* not initialized */ | ||
116 | priv->page = 0; | ||
117 | } | ||
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index a14cf9ede171..95961cccc253 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c | |||
@@ -10,10 +10,6 @@ | |||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Written by: | 13 | * Written by: |
18 | * Pavel Smolenskiy <pavel.smolenskiy@gmail.com> | 14 | * Pavel Smolenskiy <pavel.smolenskiy@gmail.com> |
19 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> | 15 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> |
@@ -23,92 +19,285 @@ | |||
23 | 19 | ||
24 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
25 | #include <linux/module.h> | 21 | #include <linux/module.h> |
26 | #include <linux/workqueue.h> | ||
27 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
28 | #include <linux/crc-ccitt.h> | 23 | #include <linux/crc-ccitt.h> |
24 | #include <asm/unaligned.h> | ||
29 | 25 | ||
30 | #include <net/mac802154.h> | 26 | #include <net/mac802154.h> |
31 | #include <net/ieee802154_netdev.h> | 27 | #include <net/ieee802154_netdev.h> |
28 | #include <net/rtnetlink.h> | ||
29 | #include <linux/nl802154.h> | ||
32 | 30 | ||
33 | #include "mac802154.h" | 31 | #include "ieee802154_i.h" |
34 | 32 | ||
35 | /* The IEEE 802.15.4 standard defines 4 MAC packet types: | 33 | static int ieee802154_deliver_skb(struct sk_buff *skb) |
36 | * - beacon frame | 34 | { |
37 | * - MAC command frame | 35 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
38 | * - acknowledgement frame | 36 | skb->protocol = htons(ETH_P_IEEE802154); |
39 | * - data frame | ||
40 | * | ||
41 | * and only the data frame should be pushed to the upper layers, other types | ||
42 | * are just internal MAC layer management information. So only data packets | ||
43 | * are going to be sent to the networking queue, all other will be processed | ||
44 | * right here by using the device workqueue. | ||
45 | */ | ||
46 | struct rx_work { | ||
47 | struct sk_buff *skb; | ||
48 | struct work_struct work; | ||
49 | struct ieee802154_dev *dev; | ||
50 | u8 lqi; | ||
51 | }; | ||
52 | 37 | ||
53 | static void | 38 | return netif_receive_skb(skb); |
54 | mac802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb, u8 lqi) | 39 | } |
40 | |||
41 | static int | ||
42 | ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, | ||
43 | struct sk_buff *skb, const struct ieee802154_hdr *hdr) | ||
55 | { | 44 | { |
56 | struct mac802154_priv *priv = mac802154_to_priv(hw); | 45 | __le16 span, sshort; |
46 | int rc; | ||
57 | 47 | ||
58 | mac_cb(skb)->lqi = lqi; | 48 | pr_debug("getting packet via slave interface %s\n", sdata->dev->name); |
59 | skb->protocol = htons(ETH_P_IEEE802154); | ||
60 | skb_reset_mac_header(skb); | ||
61 | 49 | ||
62 | if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) { | 50 | spin_lock_bh(&sdata->mib_lock); |
63 | u16 crc; | ||
64 | 51 | ||
65 | if (skb->len < 2) { | 52 | span = sdata->pan_id; |
66 | pr_debug("got invalid frame\n"); | 53 | sshort = sdata->short_addr; |
67 | goto fail; | 54 | |
68 | } | 55 | switch (mac_cb(skb)->dest.mode) { |
69 | crc = crc_ccitt(0, skb->data, skb->len); | 56 | case IEEE802154_ADDR_NONE: |
70 | if (crc) { | 57 | if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE) |
71 | pr_debug("CRC mismatch\n"); | 58 | /* FIXME: check if we are PAN coordinator */ |
72 | goto fail; | 59 | skb->pkt_type = PACKET_OTHERHOST; |
73 | } | 60 | else |
74 | skb_trim(skb, skb->len - 2); /* CRC */ | 61 | /* ACK comes with both addresses empty */ |
62 | skb->pkt_type = PACKET_HOST; | ||
63 | break; | ||
64 | case IEEE802154_ADDR_LONG: | ||
65 | if (mac_cb(skb)->dest.pan_id != span && | ||
66 | mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST)) | ||
67 | skb->pkt_type = PACKET_OTHERHOST; | ||
68 | else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr) | ||
69 | skb->pkt_type = PACKET_HOST; | ||
70 | else | ||
71 | skb->pkt_type = PACKET_OTHERHOST; | ||
72 | break; | ||
73 | case IEEE802154_ADDR_SHORT: | ||
74 | if (mac_cb(skb)->dest.pan_id != span && | ||
75 | mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST)) | ||
76 | skb->pkt_type = PACKET_OTHERHOST; | ||
77 | else if (mac_cb(skb)->dest.short_addr == sshort) | ||
78 | skb->pkt_type = PACKET_HOST; | ||
79 | else if (mac_cb(skb)->dest.short_addr == | ||
80 | cpu_to_le16(IEEE802154_ADDR_BROADCAST)) | ||
81 | skb->pkt_type = PACKET_BROADCAST; | ||
82 | else | ||
83 | skb->pkt_type = PACKET_OTHERHOST; | ||
84 | break; | ||
85 | default: | ||
86 | spin_unlock_bh(&sdata->mib_lock); | ||
87 | pr_debug("invalid dest mode\n"); | ||
88 | kfree_skb(skb); | ||
89 | return NET_RX_DROP; | ||
75 | } | 90 | } |
76 | 91 | ||
77 | mac802154_monitors_rx(priv, skb); | 92 | spin_unlock_bh(&sdata->mib_lock); |
78 | mac802154_wpans_rx(priv, skb); | ||
79 | 93 | ||
80 | return; | 94 | skb->dev = sdata->dev; |
95 | |||
96 | rc = mac802154_llsec_decrypt(&sdata->sec, skb); | ||
97 | if (rc) { | ||
98 | pr_debug("decryption failed: %i\n", rc); | ||
99 | goto fail; | ||
100 | } | ||
101 | |||
102 | sdata->dev->stats.rx_packets++; | ||
103 | sdata->dev->stats.rx_bytes += skb->len; | ||
104 | |||
105 | switch (mac_cb(skb)->type) { | ||
106 | case IEEE802154_FC_TYPE_DATA: | ||
107 | return ieee802154_deliver_skb(skb); | ||
108 | default: | ||
109 | pr_warn("ieee802154: bad frame received (type = %d)\n", | ||
110 | mac_cb(skb)->type); | ||
111 | goto fail; | ||
112 | } | ||
81 | 113 | ||
82 | fail: | 114 | fail: |
83 | kfree_skb(skb); | 115 | kfree_skb(skb); |
116 | return NET_RX_DROP; | ||
84 | } | 117 | } |
85 | 118 | ||
86 | static void mac802154_rx_worker(struct work_struct *work) | 119 | static void |
120 | ieee802154_print_addr(const char *name, const struct ieee802154_addr *addr) | ||
87 | { | 121 | { |
88 | struct rx_work *rw = container_of(work, struct rx_work, work); | 122 | if (addr->mode == IEEE802154_ADDR_NONE) |
123 | pr_debug("%s not present\n", name); | ||
124 | |||
125 | pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id)); | ||
126 | if (addr->mode == IEEE802154_ADDR_SHORT) { | ||
127 | pr_debug("%s is short: %04x\n", name, | ||
128 | le16_to_cpu(addr->short_addr)); | ||
129 | } else { | ||
130 | u64 hw = swab64((__force u64)addr->extended_addr); | ||
89 | 131 | ||
90 | mac802154_subif_rx(rw->dev, rw->skb, rw->lqi); | 132 | pr_debug("%s is hardware: %8phC\n", name, &hw); |
91 | kfree(rw); | 133 | } |
92 | } | 134 | } |
93 | 135 | ||
94 | void | 136 | static int |
95 | ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi) | 137 | ieee802154_parse_frame_start(struct sk_buff *skb, struct ieee802154_hdr *hdr) |
96 | { | 138 | { |
97 | struct mac802154_priv *priv = mac802154_to_priv(dev); | 139 | int hlen; |
98 | struct rx_work *work; | 140 | struct ieee802154_mac_cb *cb = mac_cb_init(skb); |
99 | 141 | ||
100 | if (!skb) | 142 | skb_reset_mac_header(skb); |
101 | return; | 143 | |
144 | hlen = ieee802154_hdr_pull(skb, hdr); | ||
145 | if (hlen < 0) | ||
146 | return -EINVAL; | ||
147 | |||
148 | skb->mac_len = hlen; | ||
149 | |||
150 | pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc), | ||
151 | hdr->seq); | ||
152 | |||
153 | cb->type = hdr->fc.type; | ||
154 | cb->ackreq = hdr->fc.ack_request; | ||
155 | cb->secen = hdr->fc.security_enabled; | ||
156 | |||
157 | ieee802154_print_addr("destination", &hdr->dest); | ||
158 | ieee802154_print_addr("source", &hdr->source); | ||
159 | |||
160 | cb->source = hdr->source; | ||
161 | cb->dest = hdr->dest; | ||
162 | |||
163 | if (hdr->fc.security_enabled) { | ||
164 | u64 key; | ||
165 | |||
166 | pr_debug("seclevel %i\n", hdr->sec.level); | ||
167 | |||
168 | switch (hdr->sec.key_id_mode) { | ||
169 | case IEEE802154_SCF_KEY_IMPLICIT: | ||
170 | pr_debug("implicit key\n"); | ||
171 | break; | ||
172 | |||
173 | case IEEE802154_SCF_KEY_INDEX: | ||
174 | pr_debug("key %02x\n", hdr->sec.key_id); | ||
175 | break; | ||
176 | |||
177 | case IEEE802154_SCF_KEY_SHORT_INDEX: | ||
178 | pr_debug("key %04x:%04x %02x\n", | ||
179 | le32_to_cpu(hdr->sec.short_src) >> 16, | ||
180 | le32_to_cpu(hdr->sec.short_src) & 0xffff, | ||
181 | hdr->sec.key_id); | ||
182 | break; | ||
183 | |||
184 | case IEEE802154_SCF_KEY_HW_INDEX: | ||
185 | key = swab64((__force u64)hdr->sec.extended_src); | ||
186 | pr_debug("key source %8phC %02x\n", &key, | ||
187 | hdr->sec.key_id); | ||
188 | break; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static void | ||
196 | __ieee802154_rx_handle_packet(struct ieee802154_local *local, | ||
197 | struct sk_buff *skb) | ||
198 | { | ||
199 | int ret; | ||
200 | struct ieee802154_sub_if_data *sdata; | ||
201 | struct ieee802154_hdr hdr; | ||
102 | 202 | ||
103 | work = kzalloc(sizeof(*work), GFP_ATOMIC); | 203 | ret = ieee802154_parse_frame_start(skb, &hdr); |
104 | if (!work) | 204 | if (ret) { |
205 | pr_debug("got invalid frame\n"); | ||
206 | kfree_skb(skb); | ||
105 | return; | 207 | return; |
208 | } | ||
209 | |||
210 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
211 | if (sdata->type != IEEE802154_DEV_WPAN || | ||
212 | !netif_running(sdata->dev)) | ||
213 | continue; | ||
214 | |||
215 | ieee802154_subif_frame(sdata, skb, &hdr); | ||
216 | skb = NULL; | ||
217 | break; | ||
218 | } | ||
219 | |||
220 | if (skb) | ||
221 | kfree_skb(skb); | ||
222 | } | ||
223 | |||
224 | static void | ||
225 | ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb) | ||
226 | { | ||
227 | struct sk_buff *skb2; | ||
228 | struct ieee802154_sub_if_data *sdata; | ||
229 | |||
230 | skb_reset_mac_header(skb); | ||
231 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
232 | skb->pkt_type = PACKET_OTHERHOST; | ||
233 | skb->protocol = htons(ETH_P_IEEE802154); | ||
234 | |||
235 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
236 | if (sdata->type != IEEE802154_DEV_MONITOR) | ||
237 | continue; | ||
238 | |||
239 | if (!ieee802154_sdata_running(sdata)) | ||
240 | continue; | ||
241 | |||
242 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
243 | if (skb2) { | ||
244 | skb2->dev = sdata->dev; | ||
245 | ieee802154_deliver_skb(skb2); | ||
246 | |||
247 | sdata->dev->stats.rx_packets++; | ||
248 | sdata->dev->stats.rx_bytes += skb->len; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | |||
253 | void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) | ||
254 | { | ||
255 | struct ieee802154_local *local = hw_to_local(hw); | ||
256 | u16 crc; | ||
106 | 257 | ||
107 | INIT_WORK(&work->work, mac802154_rx_worker); | 258 | WARN_ON_ONCE(softirq_count() == 0); |
108 | work->skb = skb; | ||
109 | work->dev = dev; | ||
110 | work->lqi = lqi; | ||
111 | 259 | ||
112 | queue_work(priv->dev_workqueue, &work->work); | 260 | /* TODO: When a transceiver omits the checksum here, we |
261 | * add an own calculated one. This is currently an ugly | ||
262 | * solution because the monitor needs a crc here. | ||
263 | */ | ||
264 | if (local->hw.flags & IEEE802154_HW_RX_OMIT_CKSUM) { | ||
265 | crc = crc_ccitt(0, skb->data, skb->len); | ||
266 | put_unaligned_le16(crc, skb_put(skb, 2)); | ||
267 | } | ||
268 | |||
269 | rcu_read_lock(); | ||
270 | |||
271 | ieee802154_monitors_rx(local, skb); | ||
272 | |||
273 | /* Check if transceiver doesn't validate the checksum. | ||
274 | * If not we validate the checksum here. | ||
275 | */ | ||
276 | if (local->hw.flags & IEEE802154_HW_RX_DROP_BAD_CKSUM) { | ||
277 | crc = crc_ccitt(0, skb->data, skb->len); | ||
278 | if (crc) { | ||
279 | rcu_read_unlock(); | ||
280 | kfree_skb(skb); | ||
281 | return; | ||
282 | } | ||
283 | } | ||
284 | /* remove crc */ | ||
285 | skb_trim(skb, skb->len - 2); | ||
286 | |||
287 | __ieee802154_rx_handle_packet(local, skb); | ||
288 | |||
289 | rcu_read_unlock(); | ||
290 | } | ||
291 | EXPORT_SYMBOL(ieee802154_rx); | ||
292 | |||
293 | void | ||
294 | ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi) | ||
295 | { | ||
296 | struct ieee802154_local *local = hw_to_local(hw); | ||
297 | |||
298 | mac_cb(skb)->lqi = lqi; | ||
299 | skb->pkt_type = IEEE802154_RX_MSG; | ||
300 | skb_queue_tail(&local->skb_queue, skb); | ||
301 | tasklet_schedule(&local->tasklet); | ||
113 | } | 302 | } |
114 | EXPORT_SYMBOL(ieee802154_rx_irqsafe); | 303 | EXPORT_SYMBOL(ieee802154_rx_irqsafe); |
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c index fdf4c0e67259..cc37b77f2632 100644 --- a/net/mac802154/tx.c +++ b/net/mac802154/tx.c | |||
@@ -10,10 +10,6 @@ | |||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. | 11 | * GNU General Public License for more details. |
12 | * | 12 | * |
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Written by: | 13 | * Written by: |
18 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 14 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> |
19 | * Sergey Lapin <slapin@ossfans.org> | 15 | * Sergey Lapin <slapin@ossfans.org> |
@@ -24,106 +20,98 @@ | |||
24 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
25 | #include <linux/if_arp.h> | 21 | #include <linux/if_arp.h> |
26 | #include <linux/crc-ccitt.h> | 22 | #include <linux/crc-ccitt.h> |
23 | #include <asm/unaligned.h> | ||
27 | 24 | ||
25 | #include <net/rtnetlink.h> | ||
28 | #include <net/ieee802154_netdev.h> | 26 | #include <net/ieee802154_netdev.h> |
29 | #include <net/mac802154.h> | 27 | #include <net/mac802154.h> |
30 | #include <net/wpan-phy.h> | 28 | #include <net/cfg802154.h> |
31 | 29 | ||
32 | #include "mac802154.h" | 30 | #include "ieee802154_i.h" |
31 | #include "driver-ops.h" | ||
33 | 32 | ||
34 | /* IEEE 802.15.4 transceivers can sleep during the xmit session, so process | 33 | /* IEEE 802.15.4 transceivers can sleep during the xmit session, so process |
35 | * packets through the workqueue. | 34 | * packets through the workqueue. |
36 | */ | 35 | */ |
37 | struct xmit_work { | 36 | struct ieee802154_xmit_cb { |
38 | struct sk_buff *skb; | 37 | struct sk_buff *skb; |
39 | struct work_struct work; | 38 | struct work_struct work; |
40 | struct mac802154_priv *priv; | 39 | struct ieee802154_local *local; |
41 | u8 chan; | ||
42 | u8 page; | ||
43 | }; | 40 | }; |
44 | 41 | ||
45 | static void mac802154_xmit_worker(struct work_struct *work) | 42 | static struct ieee802154_xmit_cb ieee802154_xmit_cb; |
43 | |||
44 | static void ieee802154_xmit_worker(struct work_struct *work) | ||
46 | { | 45 | { |
47 | struct xmit_work *xw = container_of(work, struct xmit_work, work); | 46 | struct ieee802154_xmit_cb *cb = |
48 | struct mac802154_sub_if_data *sdata; | 47 | container_of(work, struct ieee802154_xmit_cb, work); |
48 | struct ieee802154_local *local = cb->local; | ||
49 | struct sk_buff *skb = cb->skb; | ||
50 | struct net_device *dev = skb->dev; | ||
49 | int res; | 51 | int res; |
50 | 52 | ||
51 | mutex_lock(&xw->priv->phy->pib_lock); | 53 | rtnl_lock(); |
52 | if (xw->priv->phy->current_channel != xw->chan || | ||
53 | xw->priv->phy->current_page != xw->page) { | ||
54 | res = xw->priv->ops->set_channel(&xw->priv->hw, | ||
55 | xw->page, | ||
56 | xw->chan); | ||
57 | if (res) { | ||
58 | pr_debug("set_channel failed\n"); | ||
59 | goto out; | ||
60 | } | ||
61 | 54 | ||
62 | xw->priv->phy->current_channel = xw->chan; | 55 | /* check if ifdown occurred while schedule */ |
63 | xw->priv->phy->current_page = xw->page; | 56 | if (!netif_running(dev)) |
64 | } | 57 | goto err_tx; |
65 | 58 | ||
66 | res = xw->priv->ops->xmit(&xw->priv->hw, xw->skb); | 59 | res = drv_xmit_sync(local, skb); |
67 | if (res) | 60 | if (res) |
68 | pr_debug("transmission failed\n"); | 61 | goto err_tx; |
69 | 62 | ||
70 | out: | 63 | ieee802154_xmit_complete(&local->hw, skb); |
71 | mutex_unlock(&xw->priv->phy->pib_lock); | ||
72 | 64 | ||
73 | /* Restart the netif queue on each sub_if_data object. */ | 65 | dev->stats.tx_packets++; |
74 | rcu_read_lock(); | 66 | dev->stats.tx_bytes += skb->len; |
75 | list_for_each_entry_rcu(sdata, &xw->priv->slaves, list) | ||
76 | netif_wake_queue(sdata->dev); | ||
77 | rcu_read_unlock(); | ||
78 | 67 | ||
79 | dev_kfree_skb(xw->skb); | 68 | rtnl_unlock(); |
80 | 69 | ||
81 | kfree(xw); | 70 | return; |
71 | |||
72 | err_tx: | ||
73 | /* Restart the netif queue on each sub_if_data object. */ | ||
74 | ieee802154_wake_queue(&local->hw); | ||
75 | rtnl_unlock(); | ||
76 | kfree_skb(skb); | ||
77 | netdev_dbg(dev, "transmission failed\n"); | ||
82 | } | 78 | } |
83 | 79 | ||
84 | netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, | 80 | static netdev_tx_t |
85 | u8 page, u8 chan) | 81 | ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb) |
86 | { | 82 | { |
87 | struct xmit_work *work; | 83 | struct net_device *dev = skb->dev; |
88 | struct mac802154_sub_if_data *sdata; | 84 | int ret; |
89 | |||
90 | if (!(priv->phy->channels_supported[page] & (1 << chan))) { | ||
91 | WARN_ON(1); | ||
92 | goto err_tx; | ||
93 | } | ||
94 | |||
95 | mac802154_monitors_rx(mac802154_to_priv(&priv->hw), skb); | ||
96 | 85 | ||
97 | if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) { | 86 | if (!(local->hw.flags & IEEE802154_HW_TX_OMIT_CKSUM)) { |
98 | u16 crc = crc_ccitt(0, skb->data, skb->len); | 87 | u16 crc = crc_ccitt(0, skb->data, skb->len); |
99 | u8 *data = skb_put(skb, 2); | ||
100 | 88 | ||
101 | data[0] = crc & 0xff; | 89 | put_unaligned_le16(crc, skb_put(skb, 2)); |
102 | data[1] = crc >> 8; | ||
103 | } | 90 | } |
104 | 91 | ||
105 | if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) | 92 | if (skb_cow_head(skb, local->hw.extra_tx_headroom)) |
106 | goto err_tx; | 93 | goto err_tx; |
107 | 94 | ||
108 | work = kzalloc(sizeof(*work), GFP_ATOMIC); | ||
109 | if (!work) { | ||
110 | kfree_skb(skb); | ||
111 | return NETDEV_TX_BUSY; | ||
112 | } | ||
113 | |||
114 | /* Stop the netif queue on each sub_if_data object. */ | 95 | /* Stop the netif queue on each sub_if_data object. */ |
115 | rcu_read_lock(); | 96 | ieee802154_stop_queue(&local->hw); |
116 | list_for_each_entry_rcu(sdata, &priv->slaves, list) | 97 | |
117 | netif_stop_queue(sdata->dev); | 98 | /* async is priority, otherwise sync is fallback */ |
118 | rcu_read_unlock(); | 99 | if (local->ops->xmit_async) { |
100 | ret = drv_xmit_async(local, skb); | ||
101 | if (ret) { | ||
102 | ieee802154_wake_queue(&local->hw); | ||
103 | goto err_tx; | ||
104 | } | ||
119 | 105 | ||
120 | INIT_WORK(&work->work, mac802154_xmit_worker); | 106 | dev->stats.tx_packets++; |
121 | work->skb = skb; | 107 | dev->stats.tx_bytes += skb->len; |
122 | work->priv = priv; | 108 | } else { |
123 | work->page = page; | 109 | INIT_WORK(&ieee802154_xmit_cb.work, ieee802154_xmit_worker); |
124 | work->chan = chan; | 110 | ieee802154_xmit_cb.skb = skb; |
111 | ieee802154_xmit_cb.local = local; | ||
125 | 112 | ||
126 | queue_work(priv->dev_workqueue, &work->work); | 113 | queue_work(local->workqueue, &ieee802154_xmit_cb.work); |
114 | } | ||
127 | 115 | ||
128 | return NETDEV_TX_OK; | 116 | return NETDEV_TX_OK; |
129 | 117 | ||
@@ -131,3 +119,31 @@ err_tx: | |||
131 | kfree_skb(skb); | 119 | kfree_skb(skb); |
132 | return NETDEV_TX_OK; | 120 | return NETDEV_TX_OK; |
133 | } | 121 | } |
122 | |||
123 | netdev_tx_t | ||
124 | ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
125 | { | ||
126 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
127 | |||
128 | skb->skb_iif = dev->ifindex; | ||
129 | |||
130 | return ieee802154_tx(sdata->local, skb); | ||
131 | } | ||
132 | |||
133 | netdev_tx_t | ||
134 | ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
135 | { | ||
136 | struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); | ||
137 | int rc; | ||
138 | |||
139 | rc = mac802154_llsec_encrypt(&sdata->sec, skb); | ||
140 | if (rc) { | ||
141 | netdev_warn(dev, "encryption failed: %i\n", rc); | ||
142 | kfree_skb(skb); | ||
143 | return NETDEV_TX_OK; | ||
144 | } | ||
145 | |||
146 | skb->skb_iif = dev->ifindex; | ||
147 | |||
148 | return ieee802154_tx(sdata->local, skb); | ||
149 | } | ||
diff --git a/net/mac802154/util.c b/net/mac802154/util.c new file mode 100644 index 000000000000..117e4eff4ca8 --- /dev/null +++ b/net/mac802154/util.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* This program is free software; you can redistribute it and/or modify | ||
2 | * it under the terms of the GNU General Public License version 2 | ||
3 | * as published by the Free Software Foundation. | ||
4 | * | ||
5 | * This program is distributed in the hope that it will be useful, | ||
6 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
7 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
8 | * GNU General Public License for more details. | ||
9 | * | ||
10 | * Authors: | ||
11 | * Alexander Aring <aar@pengutronix.de> | ||
12 | * | ||
13 | * Based on: net/mac80211/util.c | ||
14 | */ | ||
15 | |||
16 | #include "ieee802154_i.h" | ||
17 | |||
18 | void ieee802154_wake_queue(struct ieee802154_hw *hw) | ||
19 | { | ||
20 | struct ieee802154_local *local = hw_to_local(hw); | ||
21 | struct ieee802154_sub_if_data *sdata; | ||
22 | |||
23 | rcu_read_lock(); | ||
24 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
25 | if (!sdata->dev) | ||
26 | continue; | ||
27 | |||
28 | netif_wake_queue(sdata->dev); | ||
29 | } | ||
30 | rcu_read_unlock(); | ||
31 | } | ||
32 | EXPORT_SYMBOL(ieee802154_wake_queue); | ||
33 | |||
34 | void ieee802154_stop_queue(struct ieee802154_hw *hw) | ||
35 | { | ||
36 | struct ieee802154_local *local = hw_to_local(hw); | ||
37 | struct ieee802154_sub_if_data *sdata; | ||
38 | |||
39 | rcu_read_lock(); | ||
40 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
41 | if (!sdata->dev) | ||
42 | continue; | ||
43 | |||
44 | netif_stop_queue(sdata->dev); | ||
45 | } | ||
46 | rcu_read_unlock(); | ||
47 | } | ||
48 | EXPORT_SYMBOL(ieee802154_stop_queue); | ||
49 | |||
50 | void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb) | ||
51 | { | ||
52 | ieee802154_wake_queue(hw); | ||
53 | consume_skb(skb); | ||
54 | } | ||
55 | EXPORT_SYMBOL(ieee802154_xmit_complete); | ||
diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c deleted file mode 100644 index 4ab86a57dca5..000000000000 --- a/net/mac802154/wpan.c +++ /dev/null | |||
@@ -1,599 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2007-2012 Siemens AG | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 | ||
6 | * as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Written by: | ||
18 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | ||
19 | * Sergey Lapin <slapin@ossfans.org> | ||
20 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> | ||
21 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | ||
22 | */ | ||
23 | |||
24 | #include <linux/netdevice.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/if_arp.h> | ||
27 | |||
28 | #include <net/rtnetlink.h> | ||
29 | #include <linux/nl802154.h> | ||
30 | #include <net/af_ieee802154.h> | ||
31 | #include <net/mac802154.h> | ||
32 | #include <net/ieee802154_netdev.h> | ||
33 | #include <net/ieee802154.h> | ||
34 | #include <net/wpan-phy.h> | ||
35 | |||
36 | #include "mac802154.h" | ||
37 | |||
38 | static int mac802154_wpan_update_llsec(struct net_device *dev) | ||
39 | { | ||
40 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | ||
41 | struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev); | ||
42 | int rc = 0; | ||
43 | |||
44 | if (ops->llsec) { | ||
45 | struct ieee802154_llsec_params params; | ||
46 | int changed = 0; | ||
47 | |||
48 | params.pan_id = priv->pan_id; | ||
49 | changed |= IEEE802154_LLSEC_PARAM_PAN_ID; | ||
50 | |||
51 | params.hwaddr = priv->extended_addr; | ||
52 | changed |= IEEE802154_LLSEC_PARAM_HWADDR; | ||
53 | |||
54 | rc = ops->llsec->set_params(dev, ¶ms, changed); | ||
55 | } | ||
56 | |||
57 | return rc; | ||
58 | } | ||
59 | |||
60 | static int | ||
61 | mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
62 | { | ||
63 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | ||
64 | struct sockaddr_ieee802154 *sa = | ||
65 | (struct sockaddr_ieee802154 *)&ifr->ifr_addr; | ||
66 | int err = -ENOIOCTLCMD; | ||
67 | |||
68 | spin_lock_bh(&priv->mib_lock); | ||
69 | |||
70 | switch (cmd) { | ||
71 | case SIOCGIFADDR: | ||
72 | { | ||
73 | u16 pan_id, short_addr; | ||
74 | |||
75 | pan_id = le16_to_cpu(priv->pan_id); | ||
76 | short_addr = le16_to_cpu(priv->short_addr); | ||
77 | if (pan_id == IEEE802154_PANID_BROADCAST || | ||
78 | short_addr == IEEE802154_ADDR_BROADCAST) { | ||
79 | err = -EADDRNOTAVAIL; | ||
80 | break; | ||
81 | } | ||
82 | |||
83 | sa->family = AF_IEEE802154; | ||
84 | sa->addr.addr_type = IEEE802154_ADDR_SHORT; | ||
85 | sa->addr.pan_id = pan_id; | ||
86 | sa->addr.short_addr = short_addr; | ||
87 | |||
88 | err = 0; | ||
89 | break; | ||
90 | } | ||
91 | case SIOCSIFADDR: | ||
92 | dev_warn(&dev->dev, | ||
93 | "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n"); | ||
94 | if (sa->family != AF_IEEE802154 || | ||
95 | sa->addr.addr_type != IEEE802154_ADDR_SHORT || | ||
96 | sa->addr.pan_id == IEEE802154_PANID_BROADCAST || | ||
97 | sa->addr.short_addr == IEEE802154_ADDR_BROADCAST || | ||
98 | sa->addr.short_addr == IEEE802154_ADDR_UNDEF) { | ||
99 | err = -EINVAL; | ||
100 | break; | ||
101 | } | ||
102 | |||
103 | priv->pan_id = cpu_to_le16(sa->addr.pan_id); | ||
104 | priv->short_addr = cpu_to_le16(sa->addr.short_addr); | ||
105 | |||
106 | err = mac802154_wpan_update_llsec(dev); | ||
107 | break; | ||
108 | } | ||
109 | |||
110 | spin_unlock_bh(&priv->mib_lock); | ||
111 | return err; | ||
112 | } | ||
113 | |||
114 | static int mac802154_wpan_mac_addr(struct net_device *dev, void *p) | ||
115 | { | ||
116 | struct sockaddr *addr = p; | ||
117 | |||
118 | if (netif_running(dev)) | ||
119 | return -EBUSY; | ||
120 | |||
121 | /* FIXME: validate addr */ | ||
122 | memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); | ||
123 | mac802154_dev_set_ieee_addr(dev); | ||
124 | return mac802154_wpan_update_llsec(dev); | ||
125 | } | ||
126 | |||
127 | int mac802154_set_mac_params(struct net_device *dev, | ||
128 | const struct ieee802154_mac_params *params) | ||
129 | { | ||
130 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | ||
131 | |||
132 | mutex_lock(&priv->hw->slaves_mtx); | ||
133 | priv->mac_params = *params; | ||
134 | mutex_unlock(&priv->hw->slaves_mtx); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | void mac802154_get_mac_params(struct net_device *dev, | ||
140 | struct ieee802154_mac_params *params) | ||
141 | { | ||
142 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | ||
143 | |||
144 | mutex_lock(&priv->hw->slaves_mtx); | ||
145 | *params = priv->mac_params; | ||
146 | mutex_unlock(&priv->hw->slaves_mtx); | ||
147 | } | ||
148 | |||
149 | static int mac802154_wpan_open(struct net_device *dev) | ||
150 | { | ||
151 | int rc; | ||
152 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | ||
153 | struct wpan_phy *phy = priv->hw->phy; | ||
154 | |||
155 | rc = mac802154_slave_open(dev); | ||
156 | if (rc < 0) | ||
157 | return rc; | ||
158 | |||
159 | mutex_lock(&phy->pib_lock); | ||
160 | |||
161 | if (phy->set_txpower) { | ||
162 | rc = phy->set_txpower(phy, priv->mac_params.transmit_power); | ||
163 | if (rc < 0) | ||
164 | goto out; | ||
165 | } | ||
166 | |||
167 | if (phy->set_lbt) { | ||
168 | rc = phy->set_lbt(phy, priv->mac_params.lbt); | ||
169 | if (rc < 0) | ||
170 | goto out; | ||
171 | } | ||
172 | |||
173 | if (phy->set_cca_mode) { | ||
174 | rc = phy->set_cca_mode(phy, priv->mac_params.cca_mode); | ||
175 | if (rc < 0) | ||
176 | goto out; | ||
177 | } | ||
178 | |||
179 | if (phy->set_cca_ed_level) { | ||
180 | rc = phy->set_cca_ed_level(phy, priv->mac_params.cca_ed_level); | ||
181 | if (rc < 0) | ||
182 | goto out; | ||
183 | } | ||
184 | |||
185 | if (phy->set_csma_params) { | ||
186 | rc = phy->set_csma_params(phy, priv->mac_params.min_be, | ||
187 | priv->mac_params.max_be, | ||
188 | priv->mac_params.csma_retries); | ||
189 | if (rc < 0) | ||
190 | goto out; | ||
191 | } | ||
192 | |||
193 | if (phy->set_frame_retries) { | ||
194 | rc = phy->set_frame_retries(phy, | ||
195 | priv->mac_params.frame_retries); | ||
196 | if (rc < 0) | ||
197 | goto out; | ||
198 | } | ||
199 | |||
200 | mutex_unlock(&phy->pib_lock); | ||
201 | return 0; | ||
202 | |||
203 | out: | ||
204 | mutex_unlock(&phy->pib_lock); | ||
205 | return rc; | ||
206 | } | ||
207 | |||
208 | static int mac802154_set_header_security(struct mac802154_sub_if_data *priv, | ||
209 | struct ieee802154_hdr *hdr, | ||
210 | const struct ieee802154_mac_cb *cb) | ||
211 | { | ||
212 | struct ieee802154_llsec_params params; | ||
213 | u8 level; | ||
214 | |||
215 | mac802154_llsec_get_params(&priv->sec, ¶ms); | ||
216 | |||
217 | if (!params.enabled && cb->secen_override && cb->secen) | ||
218 | return -EINVAL; | ||
219 | if (!params.enabled || | ||
220 | (cb->secen_override && !cb->secen) || | ||
221 | !params.out_level) | ||
222 | return 0; | ||
223 | if (cb->seclevel_override && !cb->seclevel) | ||
224 | return -EINVAL; | ||
225 | |||
226 | level = cb->seclevel_override ? cb->seclevel : params.out_level; | ||
227 | |||
228 | hdr->fc.security_enabled = 1; | ||
229 | hdr->sec.level = level; | ||
230 | hdr->sec.key_id_mode = params.out_key.mode; | ||
231 | if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX) | ||
232 | hdr->sec.short_src = params.out_key.short_source; | ||
233 | else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX) | ||
234 | hdr->sec.extended_src = params.out_key.extended_source; | ||
235 | hdr->sec.key_id = params.out_key.id; | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int mac802154_header_create(struct sk_buff *skb, | ||
241 | struct net_device *dev, | ||
242 | unsigned short type, | ||
243 | const void *daddr, | ||
244 | const void *saddr, | ||
245 | unsigned len) | ||
246 | { | ||
247 | struct ieee802154_hdr hdr; | ||
248 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | ||
249 | struct ieee802154_mac_cb *cb = mac_cb(skb); | ||
250 | int hlen; | ||
251 | |||
252 | if (!daddr) | ||
253 | return -EINVAL; | ||
254 | |||
255 | memset(&hdr.fc, 0, sizeof(hdr.fc)); | ||
256 | hdr.fc.type = cb->type; | ||
257 | hdr.fc.security_enabled = cb->secen; | ||
258 | hdr.fc.ack_request = cb->ackreq; | ||
259 | hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev); | ||
260 | |||
261 | if (mac802154_set_header_security(priv, &hdr, cb) < 0) | ||
262 | return -EINVAL; | ||
263 | |||
264 | if (!saddr) { | ||
265 | spin_lock_bh(&priv->mib_lock); | ||
266 | |||
267 | if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) || | ||
268 | priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) || | ||
269 | priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) { | ||
270 | hdr.source.mode = IEEE802154_ADDR_LONG; | ||
271 | hdr.source.extended_addr = priv->extended_addr; | ||
272 | } else { | ||
273 | hdr.source.mode = IEEE802154_ADDR_SHORT; | ||
274 | hdr.source.short_addr = priv->short_addr; | ||
275 | } | ||
276 | |||
277 | hdr.source.pan_id = priv->pan_id; | ||
278 | |||
279 | spin_unlock_bh(&priv->mib_lock); | ||
280 | } else { | ||
281 | hdr.source = *(const struct ieee802154_addr *)saddr; | ||
282 | } | ||
283 | |||
284 | hdr.dest = *(const struct ieee802154_addr *)daddr; | ||
285 | |||
286 | hlen = ieee802154_hdr_push(skb, &hdr); | ||
287 | if (hlen < 0) | ||
288 | return -EINVAL; | ||
289 | |||
290 | skb_reset_mac_header(skb); | ||
291 | skb->mac_len = hlen; | ||
292 | |||
293 | if (len > ieee802154_max_payload(&hdr)) | ||
294 | return -EMSGSIZE; | ||
295 | |||
296 | return hlen; | ||
297 | } | ||
298 | |||
299 | static int | ||
300 | mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr) | ||
301 | { | ||
302 | struct ieee802154_hdr hdr; | ||
303 | struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr; | ||
304 | |||
305 | if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) { | ||
306 | pr_debug("malformed packet\n"); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | *addr = hdr.source; | ||
311 | return sizeof(*addr); | ||
312 | } | ||
313 | |||
314 | static netdev_tx_t | ||
315 | mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev) | ||
316 | { | ||
317 | struct mac802154_sub_if_data *priv; | ||
318 | u8 chan, page; | ||
319 | int rc; | ||
320 | |||
321 | priv = netdev_priv(dev); | ||
322 | |||
323 | spin_lock_bh(&priv->mib_lock); | ||
324 | chan = priv->chan; | ||
325 | page = priv->page; | ||
326 | spin_unlock_bh(&priv->mib_lock); | ||
327 | |||
328 | if (chan == MAC802154_CHAN_NONE || | ||
329 | page >= WPAN_NUM_PAGES || | ||
330 | chan >= WPAN_NUM_CHANNELS) { | ||
331 | kfree_skb(skb); | ||
332 | return NETDEV_TX_OK; | ||
333 | } | ||
334 | |||
335 | rc = mac802154_llsec_encrypt(&priv->sec, skb); | ||
336 | if (rc) { | ||
337 | pr_warn("encryption failed: %i\n", rc); | ||
338 | kfree_skb(skb); | ||
339 | return NETDEV_TX_OK; | ||
340 | } | ||
341 | |||
342 | skb->skb_iif = dev->ifindex; | ||
343 | dev->stats.tx_packets++; | ||
344 | dev->stats.tx_bytes += skb->len; | ||
345 | |||
346 | return mac802154_tx(priv->hw, skb, page, chan); | ||
347 | } | ||
348 | |||
349 | static struct header_ops mac802154_header_ops = { | ||
350 | .create = mac802154_header_create, | ||
351 | .parse = mac802154_header_parse, | ||
352 | }; | ||
353 | |||
354 | static const struct net_device_ops mac802154_wpan_ops = { | ||
355 | .ndo_open = mac802154_wpan_open, | ||
356 | .ndo_stop = mac802154_slave_close, | ||
357 | .ndo_start_xmit = mac802154_wpan_xmit, | ||
358 | .ndo_do_ioctl = mac802154_wpan_ioctl, | ||
359 | .ndo_set_mac_address = mac802154_wpan_mac_addr, | ||
360 | }; | ||
361 | |||
362 | static void mac802154_wpan_free(struct net_device *dev) | ||
363 | { | ||
364 | struct mac802154_sub_if_data *priv = netdev_priv(dev); | ||
365 | |||
366 | mac802154_llsec_destroy(&priv->sec); | ||
367 | |||
368 | free_netdev(dev); | ||
369 | } | ||
370 | |||
371 | void mac802154_wpan_setup(struct net_device *dev) | ||
372 | { | ||
373 | struct mac802154_sub_if_data *priv; | ||
374 | |||
375 | dev->addr_len = IEEE802154_ADDR_LEN; | ||
376 | memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN); | ||
377 | |||
378 | dev->hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN; | ||
379 | dev->header_ops = &mac802154_header_ops; | ||
380 | dev->needed_tailroom = 2 + 16; /* FCS + MIC */ | ||
381 | dev->mtu = IEEE802154_MTU; | ||
382 | dev->tx_queue_len = 300; | ||
383 | dev->type = ARPHRD_IEEE802154; | ||
384 | dev->flags = IFF_NOARP | IFF_BROADCAST; | ||
385 | dev->watchdog_timeo = 0; | ||
386 | |||
387 | dev->destructor = mac802154_wpan_free; | ||
388 | dev->netdev_ops = &mac802154_wpan_ops; | ||
389 | dev->ml_priv = &mac802154_mlme_wpan; | ||
390 | |||
391 | priv = netdev_priv(dev); | ||
392 | priv->type = IEEE802154_DEV_WPAN; | ||
393 | |||
394 | priv->chan = MAC802154_CHAN_NONE; | ||
395 | priv->page = 0; | ||
396 | |||
397 | spin_lock_init(&priv->mib_lock); | ||
398 | mutex_init(&priv->sec_mtx); | ||
399 | |||
400 | get_random_bytes(&priv->bsn, 1); | ||
401 | get_random_bytes(&priv->dsn, 1); | ||
402 | |||
403 | /* defaults per 802.15.4-2011 */ | ||
404 | priv->mac_params.min_be = 3; | ||
405 | priv->mac_params.max_be = 5; | ||
406 | priv->mac_params.csma_retries = 4; | ||
407 | priv->mac_params.frame_retries = -1; /* for compatibility, actual default is 3 */ | ||
408 | |||
409 | priv->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST); | ||
410 | priv->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST); | ||
411 | |||
412 | mac802154_llsec_init(&priv->sec); | ||
413 | } | ||
414 | |||
415 | static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb) | ||
416 | { | ||
417 | return netif_rx_ni(skb); | ||
418 | } | ||
419 | |||
420 | static int | ||
421 | mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb, | ||
422 | const struct ieee802154_hdr *hdr) | ||
423 | { | ||
424 | __le16 span, sshort; | ||
425 | int rc; | ||
426 | |||
427 | pr_debug("getting packet via slave interface %s\n", sdata->dev->name); | ||
428 | |||
429 | spin_lock_bh(&sdata->mib_lock); | ||
430 | |||
431 | span = sdata->pan_id; | ||
432 | sshort = sdata->short_addr; | ||
433 | |||
434 | switch (mac_cb(skb)->dest.mode) { | ||
435 | case IEEE802154_ADDR_NONE: | ||
436 | if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE) | ||
437 | /* FIXME: check if we are PAN coordinator */ | ||
438 | skb->pkt_type = PACKET_OTHERHOST; | ||
439 | else | ||
440 | /* ACK comes with both addresses empty */ | ||
441 | skb->pkt_type = PACKET_HOST; | ||
442 | break; | ||
443 | case IEEE802154_ADDR_LONG: | ||
444 | if (mac_cb(skb)->dest.pan_id != span && | ||
445 | mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST)) | ||
446 | skb->pkt_type = PACKET_OTHERHOST; | ||
447 | else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr) | ||
448 | skb->pkt_type = PACKET_HOST; | ||
449 | else | ||
450 | skb->pkt_type = PACKET_OTHERHOST; | ||
451 | break; | ||
452 | case IEEE802154_ADDR_SHORT: | ||
453 | if (mac_cb(skb)->dest.pan_id != span && | ||
454 | mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST)) | ||
455 | skb->pkt_type = PACKET_OTHERHOST; | ||
456 | else if (mac_cb(skb)->dest.short_addr == sshort) | ||
457 | skb->pkt_type = PACKET_HOST; | ||
458 | else if (mac_cb(skb)->dest.short_addr == | ||
459 | cpu_to_le16(IEEE802154_ADDR_BROADCAST)) | ||
460 | skb->pkt_type = PACKET_BROADCAST; | ||
461 | else | ||
462 | skb->pkt_type = PACKET_OTHERHOST; | ||
463 | break; | ||
464 | default: | ||
465 | spin_unlock_bh(&sdata->mib_lock); | ||
466 | pr_debug("invalid dest mode\n"); | ||
467 | kfree_skb(skb); | ||
468 | return NET_RX_DROP; | ||
469 | } | ||
470 | |||
471 | spin_unlock_bh(&sdata->mib_lock); | ||
472 | |||
473 | skb->dev = sdata->dev; | ||
474 | |||
475 | rc = mac802154_llsec_decrypt(&sdata->sec, skb); | ||
476 | if (rc) { | ||
477 | pr_debug("decryption failed: %i\n", rc); | ||
478 | goto fail; | ||
479 | } | ||
480 | |||
481 | sdata->dev->stats.rx_packets++; | ||
482 | sdata->dev->stats.rx_bytes += skb->len; | ||
483 | |||
484 | switch (mac_cb(skb)->type) { | ||
485 | case IEEE802154_FC_TYPE_DATA: | ||
486 | return mac802154_process_data(sdata->dev, skb); | ||
487 | default: | ||
488 | pr_warn("ieee802154: bad frame received (type = %d)\n", | ||
489 | mac_cb(skb)->type); | ||
490 | goto fail; | ||
491 | } | ||
492 | |||
493 | fail: | ||
494 | kfree_skb(skb); | ||
495 | return NET_RX_DROP; | ||
496 | } | ||
497 | |||
498 | static void mac802154_print_addr(const char *name, | ||
499 | const struct ieee802154_addr *addr) | ||
500 | { | ||
501 | if (addr->mode == IEEE802154_ADDR_NONE) | ||
502 | pr_debug("%s not present\n", name); | ||
503 | |||
504 | pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id)); | ||
505 | if (addr->mode == IEEE802154_ADDR_SHORT) { | ||
506 | pr_debug("%s is short: %04x\n", name, | ||
507 | le16_to_cpu(addr->short_addr)); | ||
508 | } else { | ||
509 | u64 hw = swab64((__force u64) addr->extended_addr); | ||
510 | |||
511 | pr_debug("%s is hardware: %8phC\n", name, &hw); | ||
512 | } | ||
513 | } | ||
514 | |||
515 | static int mac802154_parse_frame_start(struct sk_buff *skb, | ||
516 | struct ieee802154_hdr *hdr) | ||
517 | { | ||
518 | int hlen; | ||
519 | struct ieee802154_mac_cb *cb = mac_cb_init(skb); | ||
520 | |||
521 | hlen = ieee802154_hdr_pull(skb, hdr); | ||
522 | if (hlen < 0) | ||
523 | return -EINVAL; | ||
524 | |||
525 | skb->mac_len = hlen; | ||
526 | |||
527 | pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc), | ||
528 | hdr->seq); | ||
529 | |||
530 | cb->type = hdr->fc.type; | ||
531 | cb->ackreq = hdr->fc.ack_request; | ||
532 | cb->secen = hdr->fc.security_enabled; | ||
533 | |||
534 | mac802154_print_addr("destination", &hdr->dest); | ||
535 | mac802154_print_addr("source", &hdr->source); | ||
536 | |||
537 | cb->source = hdr->source; | ||
538 | cb->dest = hdr->dest; | ||
539 | |||
540 | if (hdr->fc.security_enabled) { | ||
541 | u64 key; | ||
542 | |||
543 | pr_debug("seclevel %i\n", hdr->sec.level); | ||
544 | |||
545 | switch (hdr->sec.key_id_mode) { | ||
546 | case IEEE802154_SCF_KEY_IMPLICIT: | ||
547 | pr_debug("implicit key\n"); | ||
548 | break; | ||
549 | |||
550 | case IEEE802154_SCF_KEY_INDEX: | ||
551 | pr_debug("key %02x\n", hdr->sec.key_id); | ||
552 | break; | ||
553 | |||
554 | case IEEE802154_SCF_KEY_SHORT_INDEX: | ||
555 | pr_debug("key %04x:%04x %02x\n", | ||
556 | le32_to_cpu(hdr->sec.short_src) >> 16, | ||
557 | le32_to_cpu(hdr->sec.short_src) & 0xffff, | ||
558 | hdr->sec.key_id); | ||
559 | break; | ||
560 | |||
561 | case IEEE802154_SCF_KEY_HW_INDEX: | ||
562 | key = swab64((__force u64) hdr->sec.extended_src); | ||
563 | pr_debug("key source %8phC %02x\n", &key, | ||
564 | hdr->sec.key_id); | ||
565 | break; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb) | ||
573 | { | ||
574 | int ret; | ||
575 | struct mac802154_sub_if_data *sdata; | ||
576 | struct ieee802154_hdr hdr; | ||
577 | |||
578 | ret = mac802154_parse_frame_start(skb, &hdr); | ||
579 | if (ret) { | ||
580 | pr_debug("got invalid frame\n"); | ||
581 | kfree_skb(skb); | ||
582 | return; | ||
583 | } | ||
584 | |||
585 | rcu_read_lock(); | ||
586 | list_for_each_entry_rcu(sdata, &priv->slaves, list) { | ||
587 | if (sdata->type != IEEE802154_DEV_WPAN || | ||
588 | !netif_running(sdata->dev)) | ||
589 | continue; | ||
590 | |||
591 | mac802154_subif_frame(sdata, skb, &hdr); | ||
592 | skb = NULL; | ||
593 | break; | ||
594 | } | ||
595 | rcu_read_unlock(); | ||
596 | |||
597 | if (skb) | ||
598 | kfree_skb(skb); | ||
599 | } | ||
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index a761670af31d..4c9e39f04ef8 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o | |||
10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o | 10 | obj-$(CONFIG_WEXT_PRIV) += wext-priv.o |
11 | 11 | ||
12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o | 12 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o |
13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o | 13 | cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o |
14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 14 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o | 15 | cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o |
16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o | 16 | cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 72d81e2154d5..85506f1d0789 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -115,7 +115,7 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) | |||
115 | EXPORT_SYMBOL(cfg80211_chandef_valid); | 115 | EXPORT_SYMBOL(cfg80211_chandef_valid); |
116 | 116 | ||
117 | static void chandef_primary_freqs(const struct cfg80211_chan_def *c, | 117 | static void chandef_primary_freqs(const struct cfg80211_chan_def *c, |
118 | int *pri40, int *pri80) | 118 | u32 *pri40, u32 *pri80) |
119 | { | 119 | { |
120 | int tmp; | 120 | int tmp; |
121 | 121 | ||
@@ -366,6 +366,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | |||
366 | 366 | ||
367 | break; | 367 | break; |
368 | case NL80211_IFTYPE_STATION: | 368 | case NL80211_IFTYPE_STATION: |
369 | case NL80211_IFTYPE_OCB: | ||
369 | case NL80211_IFTYPE_P2P_CLIENT: | 370 | case NL80211_IFTYPE_P2P_CLIENT: |
370 | case NL80211_IFTYPE_MONITOR: | 371 | case NL80211_IFTYPE_MONITOR: |
371 | case NL80211_IFTYPE_AP_VLAN: | 372 | case NL80211_IFTYPE_AP_VLAN: |
@@ -892,6 +893,13 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, | |||
892 | *radar_detect |= BIT(wdev->chandef.width); | 893 | *radar_detect |= BIT(wdev->chandef.width); |
893 | } | 894 | } |
894 | return; | 895 | return; |
896 | case NL80211_IFTYPE_OCB: | ||
897 | if (wdev->chandef.chan) { | ||
898 | *chan = wdev->chandef.chan; | ||
899 | *chanmode = CHAN_MODE_SHARED; | ||
900 | return; | ||
901 | } | ||
902 | break; | ||
895 | case NL80211_IFTYPE_MONITOR: | 903 | case NL80211_IFTYPE_MONITOR: |
896 | case NL80211_IFTYPE_AP_VLAN: | 904 | case NL80211_IFTYPE_AP_VLAN: |
897 | case NL80211_IFTYPE_WDS: | 905 | case NL80211_IFTYPE_WDS: |
diff --git a/net/wireless/core.c b/net/wireless/core.c index f52a4cd7017c..a4d27927aba2 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -86,11 +86,11 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | |||
86 | return &rdev->wiphy; | 86 | return &rdev->wiphy; |
87 | } | 87 | } |
88 | 88 | ||
89 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | 89 | static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev, |
90 | char *newname) | 90 | const char *newname) |
91 | { | 91 | { |
92 | struct cfg80211_registered_device *rdev2; | 92 | struct cfg80211_registered_device *rdev2; |
93 | int wiphy_idx, taken = -1, result, digits; | 93 | int wiphy_idx, taken = -1, digits; |
94 | 94 | ||
95 | ASSERT_RTNL(); | 95 | ASSERT_RTNL(); |
96 | 96 | ||
@@ -109,15 +109,28 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
109 | return -EINVAL; | 109 | return -EINVAL; |
110 | } | 110 | } |
111 | 111 | ||
112 | /* Ensure another device does not already have this name. */ | ||
113 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) | ||
114 | if (strcmp(newname, wiphy_name(&rdev2->wiphy)) == 0) | ||
115 | return -EINVAL; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | ||
121 | char *newname) | ||
122 | { | ||
123 | int result; | ||
124 | |||
125 | ASSERT_RTNL(); | ||
112 | 126 | ||
113 | /* Ignore nop renames */ | 127 | /* Ignore nop renames */ |
114 | if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) | 128 | if (strcmp(newname, wiphy_name(&rdev->wiphy)) == 0) |
115 | return 0; | 129 | return 0; |
116 | 130 | ||
117 | /* Ensure another device does not already have this name. */ | 131 | result = cfg80211_dev_check_name(rdev, newname); |
118 | list_for_each_entry(rdev2, &cfg80211_rdev_list, list) | 132 | if (result < 0) |
119 | if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0) | 133 | return result; |
120 | return -EINVAL; | ||
121 | 134 | ||
122 | result = device_rename(&rdev->wiphy.dev, newname); | 135 | result = device_rename(&rdev->wiphy.dev, newname); |
123 | if (result) | 136 | if (result) |
@@ -309,7 +322,8 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work) | |||
309 | 322 | ||
310 | /* exported functions */ | 323 | /* exported functions */ |
311 | 324 | ||
312 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | 325 | struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, |
326 | const char *requested_name) | ||
313 | { | 327 | { |
314 | static atomic_t wiphy_counter = ATOMIC_INIT(0); | 328 | static atomic_t wiphy_counter = ATOMIC_INIT(0); |
315 | 329 | ||
@@ -346,7 +360,31 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
346 | rdev->wiphy_idx--; | 360 | rdev->wiphy_idx--; |
347 | 361 | ||
348 | /* give it a proper name */ | 362 | /* give it a proper name */ |
349 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); | 363 | if (requested_name && requested_name[0]) { |
364 | int rv; | ||
365 | |||
366 | rtnl_lock(); | ||
367 | rv = cfg80211_dev_check_name(rdev, requested_name); | ||
368 | |||
369 | if (rv < 0) { | ||
370 | rtnl_unlock(); | ||
371 | goto use_default_name; | ||
372 | } | ||
373 | |||
374 | rv = dev_set_name(&rdev->wiphy.dev, "%s", requested_name); | ||
375 | rtnl_unlock(); | ||
376 | if (rv) | ||
377 | goto use_default_name; | ||
378 | } else { | ||
379 | use_default_name: | ||
380 | /* NOTE: This is *probably* safe w/out holding rtnl because of | ||
381 | * the restrictions on phy names. Probably this call could | ||
382 | * fail if some other part of the kernel (re)named a device | ||
383 | * phyX. But, might should add some locking and check return | ||
384 | * value, and use a different name if this one exists? | ||
385 | */ | ||
386 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); | ||
387 | } | ||
350 | 388 | ||
351 | INIT_LIST_HEAD(&rdev->wdev_list); | 389 | INIT_LIST_HEAD(&rdev->wdev_list); |
352 | INIT_LIST_HEAD(&rdev->beacon_registrations); | 390 | INIT_LIST_HEAD(&rdev->beacon_registrations); |
@@ -406,7 +444,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
406 | 444 | ||
407 | return &rdev->wiphy; | 445 | return &rdev->wiphy; |
408 | } | 446 | } |
409 | EXPORT_SYMBOL(wiphy_new); | 447 | EXPORT_SYMBOL(wiphy_new_nm); |
410 | 448 | ||
411 | static int wiphy_verify_combinations(struct wiphy *wiphy) | 449 | static int wiphy_verify_combinations(struct wiphy *wiphy) |
412 | { | 450 | { |
@@ -831,7 +869,22 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
831 | case NL80211_IFTYPE_P2P_GO: | 869 | case NL80211_IFTYPE_P2P_GO: |
832 | __cfg80211_stop_ap(rdev, dev, true); | 870 | __cfg80211_stop_ap(rdev, dev, true); |
833 | break; | 871 | break; |
834 | default: | 872 | case NL80211_IFTYPE_OCB: |
873 | __cfg80211_leave_ocb(rdev, dev); | ||
874 | break; | ||
875 | case NL80211_IFTYPE_WDS: | ||
876 | /* must be handled by mac80211/driver, has no APIs */ | ||
877 | break; | ||
878 | case NL80211_IFTYPE_P2P_DEVICE: | ||
879 | /* cannot happen, has no netdev */ | ||
880 | break; | ||
881 | case NL80211_IFTYPE_AP_VLAN: | ||
882 | case NL80211_IFTYPE_MONITOR: | ||
883 | /* nothing to do */ | ||
884 | break; | ||
885 | case NL80211_IFTYPE_UNSPECIFIED: | ||
886 | case NUM_NL80211_IFTYPES: | ||
887 | /* invalid */ | ||
835 | break; | 888 | break; |
836 | } | 889 | } |
837 | } | 890 | } |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 7e3a3cef7df9..61ee664cf2bd 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -290,6 +290,18 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev, | |||
290 | struct wireless_dev *wdev, | 290 | struct wireless_dev *wdev, |
291 | struct cfg80211_chan_def *chandef); | 291 | struct cfg80211_chan_def *chandef); |
292 | 292 | ||
293 | /* OCB */ | ||
294 | int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev, | ||
295 | struct net_device *dev, | ||
296 | struct ocb_setup *setup); | ||
297 | int cfg80211_join_ocb(struct cfg80211_registered_device *rdev, | ||
298 | struct net_device *dev, | ||
299 | struct ocb_setup *setup); | ||
300 | int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, | ||
301 | struct net_device *dev); | ||
302 | int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, | ||
303 | struct net_device *dev); | ||
304 | |||
293 | /* AP */ | 305 | /* AP */ |
294 | int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, | 306 | int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, |
295 | struct net_device *dev, bool notify); | 307 | struct net_device *dev, bool notify); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5839c85075f1..1a31736914e5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -884,7 +884,12 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
884 | if (!wdev->current_bss) | 884 | if (!wdev->current_bss) |
885 | return -ENOLINK; | 885 | return -ENOLINK; |
886 | break; | 886 | break; |
887 | default: | 887 | case NL80211_IFTYPE_UNSPECIFIED: |
888 | case NL80211_IFTYPE_OCB: | ||
889 | case NL80211_IFTYPE_MONITOR: | ||
890 | case NL80211_IFTYPE_P2P_DEVICE: | ||
891 | case NL80211_IFTYPE_WDS: | ||
892 | case NUM_NL80211_IFTYPES: | ||
888 | return -EINVAL; | 893 | return -EINVAL; |
889 | } | 894 | } |
890 | 895 | ||
@@ -1514,8 +1519,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1514 | if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) | 1519 | if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH) |
1515 | CMD(channel_switch, CHANNEL_SWITCH); | 1520 | CMD(channel_switch, CHANNEL_SWITCH); |
1516 | CMD(set_qos_map, SET_QOS_MAP); | 1521 | CMD(set_qos_map, SET_QOS_MAP); |
1517 | if (rdev->wiphy.flags & | 1522 | if (rdev->wiphy.features & |
1518 | WIPHY_FLAG_SUPPORTS_WMM_ADMISSION) | 1523 | NL80211_FEATURE_SUPPORTS_WMM_ADMISSION) |
1519 | CMD(add_tx_ts, ADD_TX_TS); | 1524 | CMD(add_tx_ts, ADD_TX_TS); |
1520 | } | 1525 | } |
1521 | /* add into the if now */ | 1526 | /* add into the if now */ |
@@ -2605,7 +2610,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
2605 | !(rdev->wiphy.interface_modes & (1 << type))) | 2610 | !(rdev->wiphy.interface_modes & (1 << type))) |
2606 | return -EOPNOTSUPP; | 2611 | return -EOPNOTSUPP; |
2607 | 2612 | ||
2608 | if (type == NL80211_IFTYPE_P2P_DEVICE && info->attrs[NL80211_ATTR_MAC]) { | 2613 | if ((type == NL80211_IFTYPE_P2P_DEVICE || |
2614 | rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) && | ||
2615 | info->attrs[NL80211_ATTR_MAC]) { | ||
2609 | nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC], | 2616 | nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC], |
2610 | ETH_ALEN); | 2617 | ETH_ALEN); |
2611 | if (!is_valid_ether_addr(params.macaddr)) | 2618 | if (!is_valid_ether_addr(params.macaddr)) |
@@ -4398,10 +4405,12 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
4398 | { | 4405 | { |
4399 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4406 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4400 | struct net_device *dev = info->user_ptr[1]; | 4407 | struct net_device *dev = info->user_ptr[1]; |
4401 | u8 *mac_addr = NULL; | 4408 | struct station_del_parameters params; |
4409 | |||
4410 | memset(¶ms, 0, sizeof(params)); | ||
4402 | 4411 | ||
4403 | if (info->attrs[NL80211_ATTR_MAC]) | 4412 | if (info->attrs[NL80211_ATTR_MAC]) |
4404 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 4413 | params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]); |
4405 | 4414 | ||
4406 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 4415 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
4407 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 4416 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
@@ -4412,7 +4421,28 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
4412 | if (!rdev->ops->del_station) | 4421 | if (!rdev->ops->del_station) |
4413 | return -EOPNOTSUPP; | 4422 | return -EOPNOTSUPP; |
4414 | 4423 | ||
4415 | return rdev_del_station(rdev, dev, mac_addr); | 4424 | if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) { |
4425 | params.subtype = | ||
4426 | nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]); | ||
4427 | if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 && | ||
4428 | params.subtype != IEEE80211_STYPE_DEAUTH >> 4) | ||
4429 | return -EINVAL; | ||
4430 | } else { | ||
4431 | /* Default to Deauthentication frame */ | ||
4432 | params.subtype = IEEE80211_STYPE_DEAUTH >> 4; | ||
4433 | } | ||
4434 | |||
4435 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | ||
4436 | params.reason_code = | ||
4437 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | ||
4438 | if (params.reason_code == 0) | ||
4439 | return -EINVAL; /* 0 is reserved */ | ||
4440 | } else { | ||
4441 | /* Default to reason code 2 */ | ||
4442 | params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID; | ||
4443 | } | ||
4444 | |||
4445 | return rdev_del_station(rdev, dev, ¶ms); | ||
4416 | } | 4446 | } |
4417 | 4447 | ||
4418 | static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, | 4448 | static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq, |
@@ -4624,6 +4654,96 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | |||
4624 | return rdev_del_mpath(rdev, dev, dst); | 4654 | return rdev_del_mpath(rdev, dev, dst); |
4625 | } | 4655 | } |
4626 | 4656 | ||
4657 | static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info) | ||
4658 | { | ||
4659 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
4660 | int err; | ||
4661 | struct net_device *dev = info->user_ptr[1]; | ||
4662 | struct mpath_info pinfo; | ||
4663 | struct sk_buff *msg; | ||
4664 | u8 *dst = NULL; | ||
4665 | u8 mpp[ETH_ALEN]; | ||
4666 | |||
4667 | memset(&pinfo, 0, sizeof(pinfo)); | ||
4668 | |||
4669 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
4670 | return -EINVAL; | ||
4671 | |||
4672 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
4673 | |||
4674 | if (!rdev->ops->get_mpp) | ||
4675 | return -EOPNOTSUPP; | ||
4676 | |||
4677 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) | ||
4678 | return -EOPNOTSUPP; | ||
4679 | |||
4680 | err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo); | ||
4681 | if (err) | ||
4682 | return err; | ||
4683 | |||
4684 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
4685 | if (!msg) | ||
4686 | return -ENOMEM; | ||
4687 | |||
4688 | if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0, | ||
4689 | dev, dst, mpp, &pinfo) < 0) { | ||
4690 | nlmsg_free(msg); | ||
4691 | return -ENOBUFS; | ||
4692 | } | ||
4693 | |||
4694 | return genlmsg_reply(msg, info); | ||
4695 | } | ||
4696 | |||
4697 | static int nl80211_dump_mpp(struct sk_buff *skb, | ||
4698 | struct netlink_callback *cb) | ||
4699 | { | ||
4700 | struct mpath_info pinfo; | ||
4701 | struct cfg80211_registered_device *rdev; | ||
4702 | struct wireless_dev *wdev; | ||
4703 | u8 dst[ETH_ALEN]; | ||
4704 | u8 mpp[ETH_ALEN]; | ||
4705 | int path_idx = cb->args[2]; | ||
4706 | int err; | ||
4707 | |||
4708 | err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); | ||
4709 | if (err) | ||
4710 | return err; | ||
4711 | |||
4712 | if (!rdev->ops->dump_mpp) { | ||
4713 | err = -EOPNOTSUPP; | ||
4714 | goto out_err; | ||
4715 | } | ||
4716 | |||
4717 | if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
4718 | err = -EOPNOTSUPP; | ||
4719 | goto out_err; | ||
4720 | } | ||
4721 | |||
4722 | while (1) { | ||
4723 | err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst, | ||
4724 | mpp, &pinfo); | ||
4725 | if (err == -ENOENT) | ||
4726 | break; | ||
4727 | if (err) | ||
4728 | goto out_err; | ||
4729 | |||
4730 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid, | ||
4731 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
4732 | wdev->netdev, dst, mpp, | ||
4733 | &pinfo) < 0) | ||
4734 | goto out; | ||
4735 | |||
4736 | path_idx++; | ||
4737 | } | ||
4738 | |||
4739 | out: | ||
4740 | cb->args[2] = path_idx; | ||
4741 | err = skb->len; | ||
4742 | out_err: | ||
4743 | nl80211_finish_wdev_dump(rdev); | ||
4744 | return err; | ||
4745 | } | ||
4746 | |||
4627 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | 4747 | static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) |
4628 | { | 4748 | { |
4629 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4749 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -5923,7 +6043,6 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5923 | * function is called under RTNL lock, so this should not be a problem. | 6043 | * function is called under RTNL lock, so this should not be a problem. |
5924 | */ | 6044 | */ |
5925 | static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1]; | 6045 | static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1]; |
5926 | u8 radar_detect_width = 0; | ||
5927 | int err; | 6046 | int err; |
5928 | bool need_new_beacon = false; | 6047 | bool need_new_beacon = false; |
5929 | int len, i; | 6048 | int len, i; |
@@ -6059,10 +6178,8 @@ skip_beacons: | |||
6059 | if (err < 0) | 6178 | if (err < 0) |
6060 | return err; | 6179 | return err; |
6061 | 6180 | ||
6062 | if (err > 0) { | 6181 | if (err > 0) |
6063 | radar_detect_width = BIT(params.chandef.width); | ||
6064 | params.radar_required = true; | 6182 | params.radar_required = true; |
6065 | } | ||
6066 | 6183 | ||
6067 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) | 6184 | if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX]) |
6068 | params.block_tx = true; | 6185 | params.block_tx = true; |
@@ -8159,6 +8276,28 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | |||
8159 | return -EINVAL; | 8276 | return -EINVAL; |
8160 | } | 8277 | } |
8161 | 8278 | ||
8279 | static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info) | ||
8280 | { | ||
8281 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8282 | struct net_device *dev = info->user_ptr[1]; | ||
8283 | struct ocb_setup setup = {}; | ||
8284 | int err; | ||
8285 | |||
8286 | err = nl80211_parse_chandef(rdev, info, &setup.chandef); | ||
8287 | if (err) | ||
8288 | return err; | ||
8289 | |||
8290 | return cfg80211_join_ocb(rdev, dev, &setup); | ||
8291 | } | ||
8292 | |||
8293 | static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info) | ||
8294 | { | ||
8295 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
8296 | struct net_device *dev = info->user_ptr[1]; | ||
8297 | |||
8298 | return cfg80211_leave_ocb(rdev, dev); | ||
8299 | } | ||
8300 | |||
8162 | static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | 8301 | static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) |
8163 | { | 8302 | { |
8164 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 8303 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -9444,7 +9583,7 @@ static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info) | |||
9444 | u16 admitted_time = 0; | 9583 | u16 admitted_time = 0; |
9445 | int err; | 9584 | int err; |
9446 | 9585 | ||
9447 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)) | 9586 | if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)) |
9448 | return -EOPNOTSUPP; | 9587 | return -EOPNOTSUPP; |
9449 | 9588 | ||
9450 | if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] || | 9589 | if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] || |
@@ -9460,12 +9599,10 @@ static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info) | |||
9460 | return -EINVAL; | 9599 | return -EINVAL; |
9461 | 9600 | ||
9462 | /* WMM uses TIDs 0-7 even for TSPEC */ | 9601 | /* WMM uses TIDs 0-7 even for TSPEC */ |
9463 | if (tsid < IEEE80211_FIRST_TSPEC_TSID) { | 9602 | if (tsid >= IEEE80211_FIRST_TSPEC_TSID) { |
9464 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)) | ||
9465 | return -EINVAL; | ||
9466 | } else { | ||
9467 | /* TODO: handle 802.11 TSPEC/admission control | 9603 | /* TODO: handle 802.11 TSPEC/admission control |
9468 | * need more attributes for that (e.g. BA session requirement) | 9604 | * need more attributes for that (e.g. BA session requirement); |
9605 | * change the WMM adminssion test above to allow both then | ||
9469 | */ | 9606 | */ |
9470 | return -EINVAL; | 9607 | return -EINVAL; |
9471 | } | 9608 | } |
@@ -9782,6 +9919,15 @@ static const struct genl_ops nl80211_ops[] = { | |||
9782 | NL80211_FLAG_NEED_RTNL, | 9919 | NL80211_FLAG_NEED_RTNL, |
9783 | }, | 9920 | }, |
9784 | { | 9921 | { |
9922 | .cmd = NL80211_CMD_GET_MPP, | ||
9923 | .doit = nl80211_get_mpp, | ||
9924 | .dumpit = nl80211_dump_mpp, | ||
9925 | .policy = nl80211_policy, | ||
9926 | .flags = GENL_ADMIN_PERM, | ||
9927 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
9928 | NL80211_FLAG_NEED_RTNL, | ||
9929 | }, | ||
9930 | { | ||
9785 | .cmd = NL80211_CMD_SET_MPATH, | 9931 | .cmd = NL80211_CMD_SET_MPATH, |
9786 | .doit = nl80211_set_mpath, | 9932 | .doit = nl80211_set_mpath, |
9787 | .policy = nl80211_policy, | 9933 | .policy = nl80211_policy, |
@@ -10095,6 +10241,22 @@ static const struct genl_ops nl80211_ops[] = { | |||
10095 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 10241 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
10096 | NL80211_FLAG_NEED_RTNL, | 10242 | NL80211_FLAG_NEED_RTNL, |
10097 | }, | 10243 | }, |
10244 | { | ||
10245 | .cmd = NL80211_CMD_JOIN_OCB, | ||
10246 | .doit = nl80211_join_ocb, | ||
10247 | .policy = nl80211_policy, | ||
10248 | .flags = GENL_ADMIN_PERM, | ||
10249 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
10250 | NL80211_FLAG_NEED_RTNL, | ||
10251 | }, | ||
10252 | { | ||
10253 | .cmd = NL80211_CMD_LEAVE_OCB, | ||
10254 | .doit = nl80211_leave_ocb, | ||
10255 | .policy = nl80211_policy, | ||
10256 | .flags = GENL_ADMIN_PERM, | ||
10257 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
10258 | NL80211_FLAG_NEED_RTNL, | ||
10259 | }, | ||
10098 | #ifdef CONFIG_PM | 10260 | #ifdef CONFIG_PM |
10099 | { | 10261 | { |
10100 | .cmd = NL80211_CMD_GET_WOWLAN, | 10262 | .cmd = NL80211_CMD_GET_WOWLAN, |
diff --git a/net/wireless/ocb.c b/net/wireless/ocb.c new file mode 100644 index 000000000000..c00d4a792319 --- /dev/null +++ b/net/wireless/ocb.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * OCB mode implementation | ||
3 | * | ||
4 | * Copyright: (c) 2014 Czech Technical University in Prague | ||
5 | * (c) 2014 Volkswagen Group Research | ||
6 | * Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz> | ||
7 | * Funded by: Volkswagen Group Research | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/ieee80211.h> | ||
15 | #include <net/cfg80211.h> | ||
16 | #include "nl80211.h" | ||
17 | #include "core.h" | ||
18 | #include "rdev-ops.h" | ||
19 | |||
20 | int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev, | ||
21 | struct net_device *dev, | ||
22 | struct ocb_setup *setup) | ||
23 | { | ||
24 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
25 | int err; | ||
26 | |||
27 | ASSERT_WDEV_LOCK(wdev); | ||
28 | |||
29 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB) | ||
30 | return -EOPNOTSUPP; | ||
31 | |||
32 | if (WARN_ON(!setup->chandef.chan)) | ||
33 | return -EINVAL; | ||
34 | |||
35 | err = rdev_join_ocb(rdev, dev, setup); | ||
36 | if (!err) | ||
37 | wdev->chandef = setup->chandef; | ||
38 | |||
39 | return err; | ||
40 | } | ||
41 | |||
42 | int cfg80211_join_ocb(struct cfg80211_registered_device *rdev, | ||
43 | struct net_device *dev, | ||
44 | struct ocb_setup *setup) | ||
45 | { | ||
46 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
47 | int err; | ||
48 | |||
49 | wdev_lock(wdev); | ||
50 | err = __cfg80211_join_ocb(rdev, dev, setup); | ||
51 | wdev_unlock(wdev); | ||
52 | |||
53 | return err; | ||
54 | } | ||
55 | |||
56 | int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, | ||
57 | struct net_device *dev) | ||
58 | { | ||
59 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
60 | int err; | ||
61 | |||
62 | ASSERT_WDEV_LOCK(wdev); | ||
63 | |||
64 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB) | ||
65 | return -EOPNOTSUPP; | ||
66 | |||
67 | if (!rdev->ops->leave_ocb) | ||
68 | return -EOPNOTSUPP; | ||
69 | |||
70 | err = rdev_leave_ocb(rdev, dev); | ||
71 | if (!err) | ||
72 | memset(&wdev->chandef, 0, sizeof(wdev->chandef)); | ||
73 | |||
74 | return err; | ||
75 | } | ||
76 | |||
77 | int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev, | ||
78 | struct net_device *dev) | ||
79 | { | ||
80 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
81 | int err; | ||
82 | |||
83 | wdev_lock(wdev); | ||
84 | err = __cfg80211_leave_ocb(rdev, dev); | ||
85 | wdev_unlock(wdev); | ||
86 | |||
87 | return err; | ||
88 | } | ||
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index f6d457d6a558..1b3864cd50ca 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h | |||
@@ -178,11 +178,12 @@ static inline int rdev_add_station(struct cfg80211_registered_device *rdev, | |||
178 | } | 178 | } |
179 | 179 | ||
180 | static inline int rdev_del_station(struct cfg80211_registered_device *rdev, | 180 | static inline int rdev_del_station(struct cfg80211_registered_device *rdev, |
181 | struct net_device *dev, u8 *mac) | 181 | struct net_device *dev, |
182 | struct station_del_parameters *params) | ||
182 | { | 183 | { |
183 | int ret; | 184 | int ret; |
184 | trace_rdev_del_station(&rdev->wiphy, dev, mac); | 185 | trace_rdev_del_station(&rdev->wiphy, dev, params); |
185 | ret = rdev->ops->del_station(&rdev->wiphy, dev, mac); | 186 | ret = rdev->ops->del_station(&rdev->wiphy, dev, params); |
186 | trace_rdev_return_int(&rdev->wiphy, ret); | 187 | trace_rdev_return_int(&rdev->wiphy, ret); |
187 | return ret; | 188 | return ret; |
188 | } | 189 | } |
@@ -263,6 +264,18 @@ static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev, | |||
263 | 264 | ||
264 | } | 265 | } |
265 | 266 | ||
267 | static inline int rdev_get_mpp(struct cfg80211_registered_device *rdev, | ||
268 | struct net_device *dev, u8 *dst, u8 *mpp, | ||
269 | struct mpath_info *pinfo) | ||
270 | { | ||
271 | int ret; | ||
272 | |||
273 | trace_rdev_get_mpp(&rdev->wiphy, dev, dst, mpp); | ||
274 | ret = rdev->ops->get_mpp(&rdev->wiphy, dev, dst, mpp, pinfo); | ||
275 | trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo); | ||
276 | return ret; | ||
277 | } | ||
278 | |||
266 | static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev, | 279 | static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev, |
267 | struct net_device *dev, int idx, u8 *dst, | 280 | struct net_device *dev, int idx, u8 *dst, |
268 | u8 *next_hop, struct mpath_info *pinfo) | 281 | u8 *next_hop, struct mpath_info *pinfo) |
@@ -271,7 +284,20 @@ static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev, | |||
271 | int ret; | 284 | int ret; |
272 | trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop); | 285 | trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop); |
273 | ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop, | 286 | ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop, |
274 | pinfo); | 287 | pinfo); |
288 | trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo); | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | static inline int rdev_dump_mpp(struct cfg80211_registered_device *rdev, | ||
293 | struct net_device *dev, int idx, u8 *dst, | ||
294 | u8 *mpp, struct mpath_info *pinfo) | ||
295 | |||
296 | { | ||
297 | int ret; | ||
298 | |||
299 | trace_rdev_dump_mpp(&rdev->wiphy, dev, idx, dst, mpp); | ||
300 | ret = rdev->ops->dump_mpp(&rdev->wiphy, dev, idx, dst, mpp, pinfo); | ||
275 | trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo); | 301 | trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo); |
276 | return ret; | 302 | return ret; |
277 | } | 303 | } |
@@ -322,6 +348,27 @@ static inline int rdev_leave_mesh(struct cfg80211_registered_device *rdev, | |||
322 | return ret; | 348 | return ret; |
323 | } | 349 | } |
324 | 350 | ||
351 | static inline int rdev_join_ocb(struct cfg80211_registered_device *rdev, | ||
352 | struct net_device *dev, | ||
353 | struct ocb_setup *setup) | ||
354 | { | ||
355 | int ret; | ||
356 | trace_rdev_join_ocb(&rdev->wiphy, dev, setup); | ||
357 | ret = rdev->ops->join_ocb(&rdev->wiphy, dev, setup); | ||
358 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
359 | return ret; | ||
360 | } | ||
361 | |||
362 | static inline int rdev_leave_ocb(struct cfg80211_registered_device *rdev, | ||
363 | struct net_device *dev) | ||
364 | { | ||
365 | int ret; | ||
366 | trace_rdev_leave_ocb(&rdev->wiphy, dev); | ||
367 | ret = rdev->ops->leave_ocb(&rdev->wiphy, dev); | ||
368 | trace_rdev_return_int(&rdev->wiphy, ret); | ||
369 | return ret; | ||
370 | } | ||
371 | |||
325 | static inline int rdev_change_bss(struct cfg80211_registered_device *rdev, | 372 | static inline int rdev_change_bss(struct cfg80211_registered_device *rdev, |
326 | struct net_device *dev, | 373 | struct net_device *dev, |
327 | struct bss_parameters *params) | 374 | struct bss_parameters *params) |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index dc1668ff543b..0ab3711c79a0 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -80,9 +80,18 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
80 | if (!request) | 80 | if (!request) |
81 | return -ENOMEM; | 81 | return -ENOMEM; |
82 | 82 | ||
83 | if (wdev->conn->params.channel) | 83 | if (wdev->conn->params.channel) { |
84 | enum ieee80211_band band = wdev->conn->params.channel->band; | ||
85 | struct ieee80211_supported_band *sband = | ||
86 | wdev->wiphy->bands[band]; | ||
87 | |||
88 | if (!sband) { | ||
89 | kfree(request); | ||
90 | return -EINVAL; | ||
91 | } | ||
84 | request->channels[0] = wdev->conn->params.channel; | 92 | request->channels[0] = wdev->conn->params.channel; |
85 | else { | 93 | request->rates[band] = (1 << sband->n_bitrates) - 1; |
94 | } else { | ||
86 | int i = 0, j; | 95 | int i = 0, j; |
87 | enum ieee80211_band band; | 96 | enum ieee80211_band band; |
88 | struct ieee80211_supported_band *bands; | 97 | struct ieee80211_supported_band *bands; |
diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 625a6e6d1168..277a85df910e 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h | |||
@@ -600,6 +600,11 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ibss, | |||
600 | TP_ARGS(wiphy, netdev) | 600 | TP_ARGS(wiphy, netdev) |
601 | ); | 601 | ); |
602 | 602 | ||
603 | DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ocb, | ||
604 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), | ||
605 | TP_ARGS(wiphy, netdev) | ||
606 | ); | ||
607 | |||
603 | DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa, | 608 | DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa, |
604 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), | 609 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), |
605 | TP_ARGS(wiphy, netdev) | 610 | TP_ARGS(wiphy, netdev) |
@@ -680,9 +685,34 @@ DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt, | |||
680 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) | 685 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac)) |
681 | ); | 686 | ); |
682 | 687 | ||
683 | DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_station, | 688 | DECLARE_EVENT_CLASS(station_del, |
684 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac), | 689 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, |
685 | TP_ARGS(wiphy, netdev, mac) | 690 | struct station_del_parameters *params), |
691 | TP_ARGS(wiphy, netdev, params), | ||
692 | TP_STRUCT__entry( | ||
693 | WIPHY_ENTRY | ||
694 | NETDEV_ENTRY | ||
695 | MAC_ENTRY(sta_mac) | ||
696 | __field(u8, subtype) | ||
697 | __field(u16, reason_code) | ||
698 | ), | ||
699 | TP_fast_assign( | ||
700 | WIPHY_ASSIGN; | ||
701 | NETDEV_ASSIGN; | ||
702 | MAC_ASSIGN(sta_mac, params->mac); | ||
703 | __entry->subtype = params->subtype; | ||
704 | __entry->reason_code = params->reason_code; | ||
705 | ), | ||
706 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT | ||
707 | ", subtype: %u, reason_code: %u", | ||
708 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac), | ||
709 | __entry->subtype, __entry->reason_code) | ||
710 | ); | ||
711 | |||
712 | DEFINE_EVENT(station_del, rdev_del_station, | ||
713 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
714 | struct station_del_parameters *params), | ||
715 | TP_ARGS(wiphy, netdev, params) | ||
686 | ); | 716 | ); |
687 | 717 | ||
688 | DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station, | 718 | DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station, |
@@ -801,6 +831,51 @@ TRACE_EVENT(rdev_dump_mpath, | |||
801 | MAC_PR_ARG(next_hop)) | 831 | MAC_PR_ARG(next_hop)) |
802 | ); | 832 | ); |
803 | 833 | ||
834 | TRACE_EVENT(rdev_get_mpp, | ||
835 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
836 | u8 *dst, u8 *mpp), | ||
837 | TP_ARGS(wiphy, netdev, dst, mpp), | ||
838 | TP_STRUCT__entry( | ||
839 | WIPHY_ENTRY | ||
840 | NETDEV_ENTRY | ||
841 | MAC_ENTRY(dst) | ||
842 | MAC_ENTRY(mpp) | ||
843 | ), | ||
844 | TP_fast_assign( | ||
845 | WIPHY_ASSIGN; | ||
846 | NETDEV_ASSIGN; | ||
847 | MAC_ASSIGN(dst, dst); | ||
848 | MAC_ASSIGN(mpp, mpp); | ||
849 | ), | ||
850 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT | ||
851 | ", mpp: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG, | ||
852 | MAC_PR_ARG(dst), MAC_PR_ARG(mpp)) | ||
853 | ); | ||
854 | |||
855 | TRACE_EVENT(rdev_dump_mpp, | ||
856 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx, | ||
857 | u8 *dst, u8 *mpp), | ||
858 | TP_ARGS(wiphy, netdev, idx, mpp, dst), | ||
859 | TP_STRUCT__entry( | ||
860 | WIPHY_ENTRY | ||
861 | NETDEV_ENTRY | ||
862 | MAC_ENTRY(dst) | ||
863 | MAC_ENTRY(mpp) | ||
864 | __field(int, idx) | ||
865 | ), | ||
866 | TP_fast_assign( | ||
867 | WIPHY_ASSIGN; | ||
868 | NETDEV_ASSIGN; | ||
869 | MAC_ASSIGN(dst, dst); | ||
870 | MAC_ASSIGN(mpp, mpp); | ||
871 | __entry->idx = idx; | ||
872 | ), | ||
873 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: " | ||
874 | MAC_PR_FMT ", mpp: " MAC_PR_FMT, | ||
875 | WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst), | ||
876 | MAC_PR_ARG(mpp)) | ||
877 | ); | ||
878 | |||
804 | TRACE_EVENT(rdev_return_int_mpath_info, | 879 | TRACE_EVENT(rdev_return_int_mpath_info, |
805 | TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo), | 880 | TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo), |
806 | TP_ARGS(wiphy, ret, pinfo), | 881 | TP_ARGS(wiphy, ret, pinfo), |
@@ -1246,6 +1321,22 @@ TRACE_EVENT(rdev_join_ibss, | |||
1246 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid) | 1321 | WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid) |
1247 | ); | 1322 | ); |
1248 | 1323 | ||
1324 | TRACE_EVENT(rdev_join_ocb, | ||
1325 | TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, | ||
1326 | const struct ocb_setup *setup), | ||
1327 | TP_ARGS(wiphy, netdev, setup), | ||
1328 | TP_STRUCT__entry( | ||
1329 | WIPHY_ENTRY | ||
1330 | NETDEV_ENTRY | ||
1331 | ), | ||
1332 | TP_fast_assign( | ||
1333 | WIPHY_ASSIGN; | ||
1334 | NETDEV_ASSIGN; | ||
1335 | ), | ||
1336 | TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, | ||
1337 | WIPHY_PR_ARG, NETDEV_PR_ARG) | ||
1338 | ); | ||
1339 | |||
1249 | TRACE_EVENT(rdev_set_wiphy_params, | 1340 | TRACE_EVENT(rdev_set_wiphy_params, |
1250 | TP_PROTO(struct wiphy *wiphy, u32 changed), | 1341 | TP_PROTO(struct wiphy *wiphy, u32 changed), |
1251 | TP_ARGS(wiphy, changed), | 1342 | TP_ARGS(wiphy, changed), |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 5e233a577d0f..d0ac795445b7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -442,7 +442,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
442 | break; | 442 | break; |
443 | case cpu_to_le16(0): | 443 | case cpu_to_le16(0): |
444 | if (iftype != NL80211_IFTYPE_ADHOC && | 444 | if (iftype != NL80211_IFTYPE_ADHOC && |
445 | iftype != NL80211_IFTYPE_STATION) | 445 | iftype != NL80211_IFTYPE_STATION && |
446 | iftype != NL80211_IFTYPE_OCB) | ||
446 | return -1; | 447 | return -1; |
447 | break; | 448 | break; |
448 | } | 449 | } |
@@ -519,6 +520,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
519 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 520 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
520 | hdrlen = 24; | 521 | hdrlen = 24; |
521 | break; | 522 | break; |
523 | case NL80211_IFTYPE_OCB: | ||
522 | case NL80211_IFTYPE_ADHOC: | 524 | case NL80211_IFTYPE_ADHOC: |
523 | /* DA SA BSSID */ | 525 | /* DA SA BSSID */ |
524 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 526 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -937,6 +939,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
937 | if (dev->ieee80211_ptr->use_4addr) | 939 | if (dev->ieee80211_ptr->use_4addr) |
938 | break; | 940 | break; |
939 | /* fall through */ | 941 | /* fall through */ |
942 | case NL80211_IFTYPE_OCB: | ||
940 | case NL80211_IFTYPE_P2P_CLIENT: | 943 | case NL80211_IFTYPE_P2P_CLIENT: |
941 | case NL80211_IFTYPE_ADHOC: | 944 | case NL80211_IFTYPE_ADHOC: |
942 | dev->priv_flags |= IFF_DONT_BRIDGE; | 945 | dev->priv_flags |= IFF_DONT_BRIDGE; |