Blame view

net/ieee802154/6lowpan_rtnl.c 17.3 KB
d57fec84f   Alexander Aring   6lowpan: fix some...
1
  /* Copyright 2011, Siemens AG
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
2
3
   * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
   */
d57fec84f   Alexander Aring   6lowpan: fix some...
4
  /* Based on patches from Jon Smirl <jonsmirl@gmail.com>
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
5
6
7
8
9
10
11
12
13
14
   * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2
   * as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
   */
  
  /* Jon's code is based on 6lowpan implementation for Contiki which is:
   * Copyright (c) 2008, Swedish Institute of Computer Science.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   * 3. Neither the name of the Institute nor the names of its contributors
   *    may be used to endorse or promote products derived from this software
   *    without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   */
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
45
46
47
48
49
50
51
52
  #include <linux/bitops.h>
  #include <linux/if_arp.h>
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/netdevice.h>
  #include <net/af_ieee802154.h>
  #include <net/ieee802154.h>
  #include <net/ieee802154_netdev.h>
cefc8c8a7   Alexander Aring   6lowpan: move 6lo...
53
  #include <net/6lowpan.h>
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
54
  #include <net/ipv6.h>
7240cdec6   Alexander Aring   6lowpan: handling...
55
  #include "reassembly.h"
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
56

44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
57
  static LIST_HEAD(lowpan_devices);
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
58
59
60
61
  /* private device info */
  struct lowpan_dev_info {
  	struct net_device	*real_dev; /* real WPAN device ptr */
  	struct mutex		dev_list_mtx; /* mutex for list ops */
02600d0de   Alexander Aring   6lowpan: change t...
62
  	__be16			fragment_tag;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  };
  
  struct lowpan_dev_record {
  	struct net_device *ldev;
  	struct list_head list;
  };
  
  static inline struct
  lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
  {
  	return netdev_priv(dev);
  }
  
  static inline void lowpan_address_flip(u8 *src, u8 *dest)
  {
  	int i;
  	for (i = 0; i < IEEE802154_ADDR_LEN; i++)
  		(dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
  }
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
82
83
84
  static int lowpan_header_create(struct sk_buff *skb,
  			   struct net_device *dev,
  			   unsigned short type, const void *_daddr,
95c961747   Eric Dumazet   net: cleanup unsi...
85
  			   const void *_saddr, unsigned int len)
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
86
  {
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
87
88
  	const u8 *saddr = _saddr;
  	const u8 *daddr = _daddr;
e6278d920   Phoebe Buckheister   mac802154: use he...
89
  	struct ieee802154_addr sa, da;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
90

fc4e98dbb   Alexander Aring   6lowpan: use stac...
91
92
93
  	/* TODO:
  	 * if this package isn't ipv6 one, where should it be routed?
  	 */
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
94
95
  	if (type != ETH_P_IPV6)
  		return 0;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
96

44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
97
98
  	if (!saddr)
  		saddr = dev->dev_addr;
841a5ec72   Alexander Aring   6lowpan: fix/move...
99
100
  	raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
  	raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
101

8df8c56a5   Jukka Rissanen   6lowpan: Moving g...
102
  	lowpan_header_compress(skb, dev, type, daddr, saddr, len);
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
103

d57fec84f   Alexander Aring   6lowpan: fix some...
104
  	/* NOTE1: I'm still unsure about the fact that compression and WPAN
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
105
106
107
  	 * header are created here and not later in the xmit. So wait for
  	 * an opinion of net maintainers.
  	 */
d57fec84f   Alexander Aring   6lowpan: fix some...
108
  	/* NOTE2: to be absolutely correct, we must derive PANid information
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
109
110
111
  	 * from MAC subif of the 'dev' and 'real_dev' network devices, but
  	 * this isn't implemented in mainline yet, so currently we assign 0xff
  	 */
8df8c56a5   Jukka Rissanen   6lowpan: Moving g...
112
113
  	mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
  	mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
58ef67c31   Tony Cheneau   6lowpan: use shor...
114

8df8c56a5   Jukka Rissanen   6lowpan: Moving g...
115
  	/* prepare wpan address data */
e6278d920   Phoebe Buckheister   mac802154: use he...
116
117
118
  	sa.mode = IEEE802154_ADDR_LONG;
  	sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
  	sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
43de7aa6a   Tony Cheneau   6lowpan: use the ...
119

8df8c56a5   Jukka Rissanen   6lowpan: Moving g...
120
  	/* intra-PAN communications */
b70ab2e87   Phoebe Buckheister   ieee802154: enfor...
121
  	da.pan_id = sa.pan_id;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
122

d57fec84f   Alexander Aring   6lowpan: fix some...
123
  	/* if the destination address is the broadcast address, use the
8df8c56a5   Jukka Rissanen   6lowpan: Moving g...
124
125
126
  	 * corresponding short address
  	 */
  	if (lowpan_is_addr_broadcast(daddr)) {
e6278d920   Phoebe Buckheister   mac802154: use he...
127
128
  		da.mode = IEEE802154_ADDR_SHORT;
  		da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
8df8c56a5   Jukka Rissanen   6lowpan: Moving g...
129
  	} else {
e6278d920   Phoebe Buckheister   mac802154: use he...
130
131
  		da.mode = IEEE802154_ADDR_LONG;
  		da.extended_addr = ieee802154_devaddr_from_raw(daddr);
f333a15a3   Tony Cheneau   6lowpan: always e...
132

8df8c56a5   Jukka Rissanen   6lowpan: Moving g...
133
134
  		/* request acknowledgment */
  		mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
135
  	}
8df8c56a5   Jukka Rissanen   6lowpan: Moving g...
136
137
  
  	return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
d1d7358e9   Phoebe Buckheister   ieee802154: add p...
138
  			type, (void *)&da, (void *)&sa, 0);
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
139
  }
8df8c56a5   Jukka Rissanen   6lowpan: Moving g...
140
141
  static int lowpan_give_skb_to_devices(struct sk_buff *skb,
  					struct net_device *dev)
0c446212c   Alan Ott   6lowpan: Refactor...
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  {
  	struct lowpan_dev_record *entry;
  	struct sk_buff *skb_cp;
  	int stat = NET_RX_SUCCESS;
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(entry, &lowpan_devices, list)
  		if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
  			skb_cp = skb_copy(skb, GFP_ATOMIC);
  			if (!skb_cp) {
  				stat = -ENOMEM;
  				break;
  			}
  
  			skb_cp->dev = entry->ldev;
  			stat = netif_rx(skb_cp);
  		}
  	rcu_read_unlock();
  
  	return stat;
  }
ae531b947   Phoebe Buckheister   ieee802154: use i...
163
  static int process_data(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
164
  {
8df8c56a5   Jukka Rissanen   6lowpan: Moving g...
165
  	u8 iphc0, iphc1;
ae531b947   Phoebe Buckheister   ieee802154: use i...
166
167
  	struct ieee802154_addr_sa sa, da;
  	void *sap, *dap;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
168

841a5ec72   Alexander Aring   6lowpan: fix/move...
169
  	raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
170
171
172
  	/* at least two bytes will be used for the encoding */
  	if (skb->len < 2)
  		goto drop;
c5d3687f6   alex.bluesman.smirnov@gmail.com   6lowpan: read dat...
173
174
175
  
  	if (lowpan_fetch_skb_u8(skb, &iphc0))
  		goto drop;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
176

c5d3687f6   alex.bluesman.smirnov@gmail.com   6lowpan: read dat...
177
178
  	if (lowpan_fetch_skb_u8(skb, &iphc1))
  		goto drop;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
179

ae531b947   Phoebe Buckheister   ieee802154: use i...
180
181
  	ieee802154_addr_to_sa(&sa, &hdr->source);
  	ieee802154_addr_to_sa(&da, &hdr->dest);
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
182

ae531b947   Phoebe Buckheister   ieee802154: use i...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  	if (sa.addr_type == IEEE802154_ADDR_SHORT)
  		sap = &sa.short_addr;
  	else
  		sap = &sa.hwaddr;
  
  	if (da.addr_type == IEEE802154_ADDR_SHORT)
  		dap = &da.short_addr;
  	else
  		dap = &da.hwaddr;
  
  	return lowpan_process_data(skb, skb->dev, sap, sa.addr_type,
  				   IEEE802154_ADDR_LEN, dap, da.addr_type,
  				   IEEE802154_ADDR_LEN, iphc0, iphc1,
  				   lowpan_give_skb_to_devices);
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
197

44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
198
  drop:
90d0963d1   Dan Carpenter   6LoWPAN: use kfre...
199
  	kfree_skb(skb);
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
200
201
  	return -EINVAL;
  }
42c362955   alex.bluesman.smirnov@gmail.com   6lowpan: revert '...
202
203
204
205
206
207
208
209
210
211
212
213
  static int lowpan_set_address(struct net_device *dev, void *p)
  {
  	struct sockaddr *sa = p;
  
  	if (netif_running(dev))
  		return -EBUSY;
  
  	/* TODO: validate addr */
  	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
  
  	return 0;
  }
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
214
215
  static int
  lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
d57fec84f   Alexander Aring   6lowpan: fix some...
216
  		     int mlen, int plen, int offset, int type)
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
217
218
  {
  	struct sk_buff *frag;
545f3613a   Alexander Aring   6lowpan: remove u...
219
  	int hlen;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
220

d991b98f5   Tony Cheneau   6lowpan: fix firs...
221
222
  	hlen = (type == LOWPAN_DISPATCH_FRAG1) ?
  			LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
223

841a5ec72   Alexander Aring   6lowpan: fix/move...
224
  	raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
225

b614442f3   Alexander Aring   6lowpan: use netd...
226
227
  	frag = netdev_alloc_skb(skb->dev,
  				hlen + mlen + plen + IEEE802154_MFR_SIZE);
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
228
229
230
231
  	if (!frag)
  		return -ENOMEM;
  
  	frag->priority = skb->priority;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
232
233
  
  	/* copy header, MFR and payload */
3582b900a   Alexander Aring   6lowpan: cleanup ...
234
235
  	skb_put(frag, mlen);
  	skb_copy_to_linear_data(frag, skb_mac_header(skb), mlen);
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
236

3582b900a   Alexander Aring   6lowpan: cleanup ...
237
238
239
240
241
242
  	skb_put(frag, hlen);
  	skb_copy_to_linear_data_offset(frag, mlen, head, hlen);
  
  	skb_put(frag, plen);
  	skb_copy_to_linear_data_offset(frag, mlen + hlen,
  				       skb_network_header(skb) + offset, plen);
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
243

841a5ec72   Alexander Aring   6lowpan: fix/move...
244
  	raw_dump_table(__func__, " raw fragment dump", frag->data, frag->len);
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
245

545f3613a   Alexander Aring   6lowpan: remove u...
246
  	return dev_queue_xmit(frag);
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
247
248
249
  }
  
  static int
d4ac32365   Tony Cheneau   6lowpan: store fr...
250
  lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
251
  {
96cb3eb7a   Alexander Aring   6lowpan: fix frag...
252
253
  	int err;
  	u16 dgram_offset, dgram_size, payload_length, header_length,
02600d0de   Alexander Aring   6lowpan: change t...
254
255
  	    lowpan_size, frag_plen, offset;
  	__be16 tag;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
256
  	u8 head[5];
3e69162ea   Alexander Aring   6lowpan: set and ...
257
  	header_length = skb->mac_len;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
258
  	payload_length = skb->len - header_length;
d4ac32365   Tony Cheneau   6lowpan: store fr...
259
  	tag = lowpan_dev_info(dev)->fragment_tag++;
96cb3eb7a   Alexander Aring   6lowpan: fix frag...
260
261
262
  	lowpan_size = skb_network_header_len(skb);
  	dgram_size = lowpan_uncompress_size(skb, &dgram_offset) -
  		     header_length;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
263
264
  
  	/* first fragment header */
96cb3eb7a   Alexander Aring   6lowpan: fix frag...
265
266
  	head[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x7);
  	head[1] = dgram_size & 0xff;
b6f82fc05   Alexander Aring   6lowpan: use memc...
267
  	memcpy(head + 2, &tag, sizeof(tag));
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
268

96cb3eb7a   Alexander Aring   6lowpan: fix frag...
269
270
271
272
273
274
  	/* calc the nearest payload length(divided to 8) for first fragment
  	 * which fits into a IEEE802154_MTU
  	 */
  	frag_plen = round_down(IEEE802154_MTU - header_length -
  			       LOWPAN_FRAG1_HEAD_SIZE - lowpan_size -
  			       IEEE802154_MFR_SIZE, 8);
d991b98f5   Tony Cheneau   6lowpan: fix firs...
275

96cb3eb7a   Alexander Aring   6lowpan: fix frag...
276
277
278
  	err = lowpan_fragment_xmit(skb, head, header_length,
  				   frag_plen + lowpan_size, 0,
  				   LOWPAN_DISPATCH_FRAG1);
9da2924c4   Tony Cheneau   6lowpan: add debu...
279
280
281
  	if (err) {
  		pr_debug("%s unable to send FRAG1 packet (tag: %d)",
  			 __func__, tag);
d991b98f5   Tony Cheneau   6lowpan: fix firs...
282
  		goto exit;
9da2924c4   Tony Cheneau   6lowpan: add debu...
283
  	}
d991b98f5   Tony Cheneau   6lowpan: fix firs...
284

96cb3eb7a   Alexander Aring   6lowpan: fix frag...
285
286
  	offset = lowpan_size + frag_plen;
  	dgram_offset += frag_plen;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
287
288
289
290
  
  	/* next fragment header */
  	head[0] &= ~LOWPAN_DISPATCH_FRAG1;
  	head[0] |= LOWPAN_DISPATCH_FRAGN;
96cb3eb7a   Alexander Aring   6lowpan: fix frag...
291
292
  	frag_plen = round_down(IEEE802154_MTU - header_length -
  			       LOWPAN_FRAGN_HEAD_SIZE - IEEE802154_MFR_SIZE, 8);
53cb5717b   Alexander Aring   6lowpan: remove u...
293
  	while (payload_length - offset > 0) {
96cb3eb7a   Alexander Aring   6lowpan: fix frag...
294
  		int len = frag_plen;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
295

96cb3eb7a   Alexander Aring   6lowpan: fix frag...
296
  		head[4] = dgram_offset >> 3;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
297
298
299
  
  		if (payload_length - offset < len)
  			len = payload_length - offset;
96cb3eb7a   Alexander Aring   6lowpan: fix frag...
300
301
  		err = lowpan_fragment_xmit(skb, head, header_length, len,
  					   offset, LOWPAN_DISPATCH_FRAGN);
9da2924c4   Tony Cheneau   6lowpan: add debu...
302
  		if (err) {
d57fec84f   Alexander Aring   6lowpan: fix some...
303
304
305
  			pr_debug("%s unable to send a FRAGN packet. (tag: %d, offset: %d)
  ",
  				 __func__, tag, offset);
d991b98f5   Tony Cheneau   6lowpan: fix firs...
306
  			goto exit;
9da2924c4   Tony Cheneau   6lowpan: add debu...
307
  		}
d991b98f5   Tony Cheneau   6lowpan: fix firs...
308

719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
309
  		offset += len;
96cb3eb7a   Alexander Aring   6lowpan: fix frag...
310
  		dgram_offset += len;
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
311
  	}
d991b98f5   Tony Cheneau   6lowpan: fix firs...
312
  exit:
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
313
314
  	return err;
  }
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
315
316
  static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
  {
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
317
  	int err = -1;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
318

e71094f98   alex.bluesman.smirnov@gmail.com   6lowpan: remove e...
319
320
  	pr_debug("package xmit
  ");
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
321
322
323
  
  	skb->dev = lowpan_dev_info(dev)->real_dev;
  	if (skb->dev == NULL) {
e71094f98   alex.bluesman.smirnov@gmail.com   6lowpan: remove e...
324
325
  		pr_debug("ERROR: no real wpan device found
  ");
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
326
327
  		goto error;
  	}
b333b7e6e   Alan Ott   6lowpan: consider...
328
329
  	/* Send directly if less than the MTU minus the 2 checksum bytes. */
  	if (skb->len <= IEEE802154_MTU - IEEE802154_MFR_SIZE) {
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
330
  		err = dev_queue_xmit(skb);
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
331
332
  		goto out;
  	}
e71094f98   alex.bluesman.smirnov@gmail.com   6lowpan: remove e...
333
334
  	pr_debug("frame is too big, fragmentation is needed
  ");
d4ac32365   Tony Cheneau   6lowpan: store fr...
335
  	err = lowpan_skb_fragmentation(skb, dev);
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
336
337
338
  error:
  	dev_kfree_skb(skb);
  out:
fc52eea4c   Alan Ott   6lowpan: handle d...
339
  	if (err)
e71094f98   alex.bluesman.smirnov@gmail.com   6lowpan: remove e...
340
341
  		pr_debug("ERROR: xmit failed
  ");
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
342

fc52eea4c   Alan Ott   6lowpan: handle d...
343
  	return (err < 0) ? NET_XMIT_DROP : err;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
344
  }
0848e4043   alex.bluesman.smirnov@gmail.com   6lowpan: fix segm...
345
346
347
348
349
  static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)
  {
  	struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
  	return ieee802154_mlme_ops(real_dev)->get_phy(real_dev);
  }
b70ab2e87   Phoebe Buckheister   ieee802154: enfor...
350
  static __le16 lowpan_get_pan_id(const struct net_device *dev)
0848e4043   alex.bluesman.smirnov@gmail.com   6lowpan: fix segm...
351
352
353
354
  {
  	struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
  	return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev);
  }
b70ab2e87   Phoebe Buckheister   ieee802154: enfor...
355
  static __le16 lowpan_get_short_addr(const struct net_device *dev)
0848e4043   alex.bluesman.smirnov@gmail.com   6lowpan: fix segm...
356
357
358
359
  {
  	struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
  	return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev);
  }
c7d0ab28b   Tony Cheneau   6lowpan: obtain I...
360
361
362
363
364
  static u8 lowpan_get_dsn(const struct net_device *dev)
  {
  	struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
  	return ieee802154_mlme_ops(real_dev)->get_dsn(real_dev);
  }
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
365
366
367
  static struct header_ops lowpan_header_ops = {
  	.create	= lowpan_header_create,
  };
20e7c4e80   Eric Dumazet   6lowpan: fix lock...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  static struct lock_class_key lowpan_tx_busylock;
  static struct lock_class_key lowpan_netdev_xmit_lock_key;
  
  static void lowpan_set_lockdep_class_one(struct net_device *dev,
  					 struct netdev_queue *txq,
  					 void *_unused)
  {
  	lockdep_set_class(&txq->_xmit_lock,
  			  &lowpan_netdev_xmit_lock_key);
  }
  
  
  static int lowpan_dev_init(struct net_device *dev)
  {
  	netdev_for_each_tx_queue(dev, lowpan_set_lockdep_class_one, NULL);
  	dev->qdisc_tx_busylock = &lowpan_tx_busylock;
  	return 0;
  }
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
386
  static const struct net_device_ops lowpan_netdev_ops = {
20e7c4e80   Eric Dumazet   6lowpan: fix lock...
387
  	.ndo_init		= lowpan_dev_init,
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
388
  	.ndo_start_xmit		= lowpan_xmit,
42c362955   alex.bluesman.smirnov@gmail.com   6lowpan: revert '...
389
  	.ndo_set_mac_address	= lowpan_set_address,
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
390
  };
0848e4043   alex.bluesman.smirnov@gmail.com   6lowpan: fix segm...
391
392
393
394
  static struct ieee802154_mlme_ops lowpan_mlme = {
  	.get_pan_id = lowpan_get_pan_id,
  	.get_phy = lowpan_get_phy,
  	.get_short_addr = lowpan_get_short_addr,
c7d0ab28b   Tony Cheneau   6lowpan: obtain I...
395
  	.get_dsn = lowpan_get_dsn,
0848e4043   alex.bluesman.smirnov@gmail.com   6lowpan: fix segm...
396
  };
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
397
398
  static void lowpan_setup(struct net_device *dev)
  {
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
399
400
401
  	dev->addr_len		= IEEE802154_ADDR_LEN;
  	memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
  	dev->type		= ARPHRD_IEEE802154;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
402
403
404
405
406
  	/* Frame Control + Sequence Number + Address fields + Security Header */
  	dev->hard_header_len	= 2 + 1 + 20 + 14;
  	dev->needed_tailroom	= 2; /* FCS */
  	dev->mtu		= 1281;
  	dev->tx_queue_len	= 0;
4d039f684   alex.bluesman.smirnov@gmail.com   6LoWPAN: set prop...
407
  	dev->flags		= IFF_BROADCAST | IFF_MULTICAST;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
408
409
410
411
  	dev->watchdog_timeo	= 0;
  
  	dev->netdev_ops		= &lowpan_netdev_ops;
  	dev->header_ops		= &lowpan_header_ops;
0848e4043   alex.bluesman.smirnov@gmail.com   6lowpan: fix segm...
412
  	dev->ml_priv		= &lowpan_mlme;
a2dc375e1   Alan Ott   6lowpan: handle N...
413
  	dev->destructor		= free_netdev;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
414
415
416
417
  }
  
  static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[])
  {
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
418
419
420
421
422
423
424
425
426
427
  	if (tb[IFLA_ADDRESS]) {
  		if (nla_len(tb[IFLA_ADDRESS]) != IEEE802154_ADDR_LEN)
  			return -EINVAL;
  	}
  	return 0;
  }
  
  static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
  	struct packet_type *pt, struct net_device *orig_dev)
  {
ae531b947   Phoebe Buckheister   ieee802154: use i...
428
  	struct ieee802154_hdr hdr;
7240cdec6   Alexander Aring   6lowpan: handling...
429
  	int ret;
a437d2744   Alan Ott   6lowpan: Make a c...
430

8cfad496c   Phoebe Buckheister   ieee802154: prope...
431
432
433
  	skb = skb_share_check(skb, GFP_ATOMIC);
  	if (!skb)
  		goto drop;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
434
  	if (!netif_running(dev))
7240cdec6   Alexander Aring   6lowpan: handling...
435
  		goto drop_skb;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
436
437
  
  	if (dev->type != ARPHRD_IEEE802154)
7240cdec6   Alexander Aring   6lowpan: handling...
438
  		goto drop_skb;
ae531b947   Phoebe Buckheister   ieee802154: use i...
439
440
  	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
  		goto drop_skb;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
441
  	/* check that it's our buffer */
ee21c7e0d   Alan Ott   6lowpan: Handle u...
442
  	if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
8cfad496c   Phoebe Buckheister   ieee802154: prope...
443
444
  		skb->protocol = htons(ETH_P_IPV6);
  		skb->pkt_type = PACKET_HOST;
ee21c7e0d   Alan Ott   6lowpan: Handle u...
445
446
  
  		/* Pull off the 1-byte of 6lowpan header. */
8cfad496c   Phoebe Buckheister   ieee802154: prope...
447
  		skb_pull(skb, 1);
ee21c7e0d   Alan Ott   6lowpan: Handle u...
448

8cfad496c   Phoebe Buckheister   ieee802154: prope...
449
  		ret = lowpan_give_skb_to_devices(skb, NULL);
7240cdec6   Alexander Aring   6lowpan: handling...
450
451
  		if (ret == NET_RX_DROP)
  			goto drop;
ee21c7e0d   Alan Ott   6lowpan: Handle u...
452
453
454
  	} else {
  		switch (skb->data[0] & 0xe0) {
  		case LOWPAN_DISPATCH_IPHC:	/* ipv6 datagram */
8cfad496c   Phoebe Buckheister   ieee802154: prope...
455
  			ret = process_data(skb, &hdr);
7240cdec6   Alexander Aring   6lowpan: handling...
456
457
458
  			if (ret == NET_RX_DROP)
  				goto drop;
  			break;
ee21c7e0d   Alan Ott   6lowpan: Handle u...
459
  		case LOWPAN_DISPATCH_FRAG1:	/* first fragment header */
8cfad496c   Phoebe Buckheister   ieee802154: prope...
460
  			ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
7240cdec6   Alexander Aring   6lowpan: handling...
461
  			if (ret == 1) {
8cfad496c   Phoebe Buckheister   ieee802154: prope...
462
  				ret = process_data(skb, &hdr);
7240cdec6   Alexander Aring   6lowpan: handling...
463
464
465
466
  				if (ret == NET_RX_DROP)
  					goto drop;
  			}
  			break;
ee21c7e0d   Alan Ott   6lowpan: Handle u...
467
  		case LOWPAN_DISPATCH_FRAGN:	/* next fragments headers */
8cfad496c   Phoebe Buckheister   ieee802154: prope...
468
  			ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
7240cdec6   Alexander Aring   6lowpan: handling...
469
  			if (ret == 1) {
8cfad496c   Phoebe Buckheister   ieee802154: prope...
470
  				ret = process_data(skb, &hdr);
7240cdec6   Alexander Aring   6lowpan: handling...
471
472
473
  				if (ret == NET_RX_DROP)
  					goto drop;
  			}
ee21c7e0d   Alan Ott   6lowpan: Handle u...
474
475
476
477
  			break;
  		default:
  			break;
  		}
719269afb   alex.bluesman.smirnov@gmail.com   6LoWPAN: add frag...
478
  	}
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
479
480
  
  	return NET_RX_SUCCESS;
7240cdec6   Alexander Aring   6lowpan: handling...
481
  drop_skb:
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
482
  	kfree_skb(skb);
7240cdec6   Alexander Aring   6lowpan: handling...
483
  drop:
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
484
485
486
487
488
489
490
491
  	return NET_RX_DROP;
  }
  
  static int lowpan_newlink(struct net *src_net, struct net_device *dev,
  			  struct nlattr *tb[], struct nlattr *data[])
  {
  	struct net_device *real_dev;
  	struct lowpan_dev_record *entry;
e71094f98   alex.bluesman.smirnov@gmail.com   6lowpan: remove e...
492
493
  	pr_debug("adding new link
  ");
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
494
495
496
497
498
499
500
  
  	if (!tb[IFLA_LINK])
  		return -EINVAL;
  	/* find and hold real wpan device */
  	real_dev = dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
  	if (!real_dev)
  		return -ENODEV;
78032f9b3   Dan Carpenter   6lowpan: release ...
501
502
  	if (real_dev->type != ARPHRD_IEEE802154) {
  		dev_put(real_dev);
7adac1ec8   Alan Ott   6lowpan: Only mak...
503
  		return -EINVAL;
78032f9b3   Dan Carpenter   6lowpan: release ...
504
  	}
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
505
506
507
  
  	lowpan_dev_info(dev)->real_dev = real_dev;
  	mutex_init(&lowpan_dev_info(dev)->dev_list_mtx);
d57fec84f   Alexander Aring   6lowpan: fix some...
508
  	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
dc00fd444   Dan Carpenter   6LoWPAN: call dev...
509
510
511
  	if (!entry) {
  		dev_put(real_dev);
  		lowpan_dev_info(dev)->real_dev = NULL;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
512
  		return -ENOMEM;
dc00fd444   Dan Carpenter   6LoWPAN: call dev...
513
  	}
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
514
515
  
  	entry->ldev = dev;
ab2d95df9   Alan Ott   6lowpan: Sync def...
516
517
  	/* Set the lowpan harware address to the wpan hardware address. */
  	memcpy(dev->dev_addr, real_dev->dev_addr, IEEE802154_ADDR_LEN);
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  	mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
  	INIT_LIST_HEAD(&entry->list);
  	list_add_tail(&entry->list, &lowpan_devices);
  	mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
  
  	register_netdevice(dev);
  
  	return 0;
  }
  
  static void lowpan_dellink(struct net_device *dev, struct list_head *head)
  {
  	struct lowpan_dev_info *lowpan_dev = lowpan_dev_info(dev);
  	struct net_device *real_dev = lowpan_dev->real_dev;
8deff4af8   alex.bluesman.smirnov@gmail.com   6lowpan: clean up...
532
  	struct lowpan_dev_record *entry, *tmp;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
533
534
535
536
  
  	ASSERT_RTNL();
  
  	mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
aec9db355   Dan Carpenter   6LoWPAN: use the ...
537
  	list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
538
539
540
541
  		if (entry->ldev == dev) {
  			list_del(&entry->list);
  			kfree(entry);
  		}
aec9db355   Dan Carpenter   6LoWPAN: use the ...
542
  	}
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
  	mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
  
  	mutex_destroy(&lowpan_dev_info(dev)->dev_list_mtx);
  
  	unregister_netdevice_queue(dev, head);
  
  	dev_put(real_dev);
  }
  
  static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
  	.kind		= "lowpan",
  	.priv_size	= sizeof(struct lowpan_dev_info),
  	.setup		= lowpan_setup,
  	.newlink	= lowpan_newlink,
  	.dellink	= lowpan_dellink,
  	.validate	= lowpan_validate,
  };
  
  static inline int __init lowpan_netlink_init(void)
  {
  	return rtnl_link_register(&lowpan_link_ops);
  }
a07fdcecc   David S. Miller   6lowpan: Remove _...
565
  static inline void lowpan_netlink_fini(void)
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
566
567
568
  {
  	rtnl_link_unregister(&lowpan_link_ops);
  }
a2dc375e1   Alan Ott   6lowpan: handle N...
569
  static int lowpan_device_event(struct notifier_block *unused,
351638e7d   Jiri Pirko   net: pass info st...
570
  			       unsigned long event, void *ptr)
a2dc375e1   Alan Ott   6lowpan: handle N...
571
  {
351638e7d   Jiri Pirko   net: pass info st...
572
  	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
a2dc375e1   Alan Ott   6lowpan: handle N...
573
574
575
576
577
578
579
580
581
582
583
584
585
  	LIST_HEAD(del_list);
  	struct lowpan_dev_record *entry, *tmp;
  
  	if (dev->type != ARPHRD_IEEE802154)
  		goto out;
  
  	if (event == NETDEV_UNREGISTER) {
  		list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
  			if (lowpan_dev_info(entry->ldev)->real_dev == dev)
  				lowpan_dellink(entry->ldev, &del_list);
  		}
  
  		unregister_netdevice_many(&del_list);
4c835019a   Peter Senna Tschudin   net/ieee802154/6l...
586
  	}
a2dc375e1   Alan Ott   6lowpan: handle N...
587
588
589
590
591
592
593
594
  
  out:
  	return NOTIFY_DONE;
  }
  
  static struct notifier_block lowpan_dev_notifier = {
  	.notifier_call = lowpan_device_event,
  };
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
595
  static struct packet_type lowpan_packet_type = {
ec633eb5f   Joe Perches   ieee802154: Conve...
596
  	.type = htons(ETH_P_IEEE802154),
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
597
598
599
600
601
602
  	.func = lowpan_rcv,
  };
  
  static int __init lowpan_init_module(void)
  {
  	int err = 0;
7240cdec6   Alexander Aring   6lowpan: handling...
603
  	err = lowpan_net_frag_init();
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
604
605
  	if (err < 0)
  		goto out;
7240cdec6   Alexander Aring   6lowpan: handling...
606
607
608
  	err = lowpan_netlink_init();
  	if (err < 0)
  		goto out_frag;
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
609
  	dev_add_pack(&lowpan_packet_type);
a2dc375e1   Alan Ott   6lowpan: handle N...
610
611
  
  	err = register_netdevice_notifier(&lowpan_dev_notifier);
7240cdec6   Alexander Aring   6lowpan: handling...
612
613
614
615
616
617
618
619
620
621
  	if (err < 0)
  		goto out_pack;
  
  	return 0;
  
  out_pack:
  	dev_remove_pack(&lowpan_packet_type);
  	lowpan_netlink_fini();
  out_frag:
  	lowpan_net_frag_exit();
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
622
623
624
625
626
627
  out:
  	return err;
  }
  
  static void __exit lowpan_cleanup_module(void)
  {
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
628
629
630
  	lowpan_netlink_fini();
  
  	dev_remove_pack(&lowpan_packet_type);
33c34c5e9   alex.bluesman.smirnov@gmail.com   6lowpan: rework f...
631

7240cdec6   Alexander Aring   6lowpan: handling...
632
  	lowpan_net_frag_exit();
a2dc375e1   Alan Ott   6lowpan: handle N...
633

7240cdec6   Alexander Aring   6lowpan: handling...
634
  	unregister_netdevice_notifier(&lowpan_dev_notifier);
44331fe2a   Alexander Smirnov   IEEE802.15.4: 6Lo...
635
636
637
638
639
640
  }
  
  module_init(lowpan_init_module);
  module_exit(lowpan_cleanup_module);
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_RTNL_LINK("lowpan");