@@ -92,6 +92,7 @@ static int lowpan_header_create(struct sk_buff *skb,
92
92
const u8 * saddr = _saddr ;
93
93
const u8 * daddr = _daddr ;
94
94
struct ieee802154_addr sa , da ;
95
+ struct ieee802154_mac_cb * cb = mac_cb_init (skb );
95
96
96
97
/* TODO:
97
98
* if this package isn't ipv6 one, where should it be routed?
@@ -115,8 +116,7 @@ static int lowpan_header_create(struct sk_buff *skb,
115
116
* from MAC subif of the 'dev' and 'real_dev' network devices, but
116
117
* this isn't implemented in mainline yet, so currently we assign 0xff
117
118
*/
118
- mac_cb (skb )-> flags = IEEE802154_FC_TYPE_DATA ;
119
- mac_cb (skb )-> seq = ieee802154_mlme_ops (dev )-> get_dsn (dev );
119
+ cb -> type = IEEE802154_FC_TYPE_DATA ;
120
120
121
121
/* prepare wpan address data */
122
122
sa .mode = IEEE802154_ADDR_LONG ;
@@ -135,11 +135,10 @@ static int lowpan_header_create(struct sk_buff *skb,
135
135
} else {
136
136
da .mode = IEEE802154_ADDR_LONG ;
137
137
da .extended_addr = ieee802154_devaddr_from_raw (daddr );
138
-
139
- /* request acknowledgment */
140
- mac_cb (skb )-> flags |= MAC_CB_FLAG_ACKREQ ;
141
138
}
142
139
140
+ cb -> ackreq = !lowpan_is_addr_broadcast (daddr );
141
+
143
142
return dev_hard_header (skb , lowpan_dev_info (dev )-> real_dev ,
144
143
type , (void * )& da , (void * )& sa , 0 );
145
144
}
@@ -221,139 +220,149 @@ static int lowpan_set_address(struct net_device *dev, void *p)
221
220
return 0 ;
222
221
}
223
222
224
- static int
225
- lowpan_fragment_xmit (struct sk_buff * skb , u8 * head ,
226
- int mlen , int plen , int offset , int type )
223
+ static struct sk_buff *
224
+ lowpan_alloc_frag (struct sk_buff * skb , int size ,
225
+ const struct ieee802154_hdr * master_hdr )
227
226
{
227
+ struct net_device * real_dev = lowpan_dev_info (skb -> dev )-> real_dev ;
228
228
struct sk_buff * frag ;
229
- int hlen ;
230
-
231
- hlen = (type == LOWPAN_DISPATCH_FRAG1 ) ?
232
- LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE ;
233
-
234
- raw_dump_inline (__func__ , "6lowpan fragment header" , head , hlen );
229
+ int rc ;
230
+
231
+ frag = alloc_skb (real_dev -> hard_header_len +
232
+ real_dev -> needed_tailroom + size ,
233
+ GFP_ATOMIC );
234
+
235
+ if (likely (frag )) {
236
+ frag -> dev = real_dev ;
237
+ frag -> priority = skb -> priority ;
238
+ skb_reserve (frag , real_dev -> hard_header_len );
239
+ skb_reset_network_header (frag );
240
+ * mac_cb (frag ) = * mac_cb (skb );
241
+
242
+ rc = dev_hard_header (frag , real_dev , 0 , & master_hdr -> dest ,
243
+ & master_hdr -> source , size );
244
+ if (rc < 0 ) {
245
+ kfree_skb (frag );
246
+ return ERR_PTR (- rc );
247
+ }
248
+ } else {
249
+ frag = ERR_PTR (ENOMEM );
250
+ }
235
251
236
- frag = netdev_alloc_skb (skb -> dev ,
237
- hlen + mlen + plen + IEEE802154_MFR_SIZE );
238
- if (!frag )
239
- return - ENOMEM ;
252
+ return frag ;
253
+ }
240
254
241
- frag -> priority = skb -> priority ;
255
+ static int
256
+ lowpan_xmit_fragment (struct sk_buff * skb , const struct ieee802154_hdr * wpan_hdr ,
257
+ u8 * frag_hdr , int frag_hdrlen ,
258
+ int offset , int len )
259
+ {
260
+ struct sk_buff * frag ;
242
261
243
- /* copy header, MFR and payload */
244
- skb_put (frag , mlen );
245
- skb_copy_to_linear_data (frag , skb_mac_header (skb ), mlen );
262
+ raw_dump_inline (__func__ , " fragment header" , frag_hdr , frag_hdrlen );
246
263
247
- skb_put (frag , hlen );
248
- skb_copy_to_linear_data_offset (frag , mlen , head , hlen );
264
+ frag = lowpan_alloc_frag (skb , frag_hdrlen + len , wpan_hdr );
265
+ if (IS_ERR (frag ))
266
+ return - PTR_ERR (frag );
249
267
250
- skb_put (frag , plen );
251
- skb_copy_to_linear_data_offset (frag , mlen + hlen ,
252
- skb_network_header (skb ) + offset , plen );
268
+ memcpy (skb_put (frag , frag_hdrlen ), frag_hdr , frag_hdrlen );
269
+ memcpy (skb_put (frag , len ), skb_network_header (skb ) + offset , len );
253
270
254
- raw_dump_table (__func__ , " raw fragment dump" , frag -> data , frag -> len );
271
+ raw_dump_table (__func__ , " fragment dump" , frag -> data , frag -> len );
255
272
256
273
return dev_queue_xmit (frag );
257
274
}
258
275
259
276
static int
260
- lowpan_skb_fragmentation (struct sk_buff * skb , struct net_device * dev )
277
+ lowpan_xmit_fragmented (struct sk_buff * skb , struct net_device * dev ,
278
+ const struct ieee802154_hdr * wpan_hdr )
261
279
{
262
- int err ;
263
- u16 dgram_offset , dgram_size , payload_length , header_length ,
264
- lowpan_size , frag_plen , offset ;
265
- __be16 tag ;
266
- u8 head [5 ];
267
-
268
- header_length = skb -> mac_len ;
269
- payload_length = skb -> len - header_length ;
270
- tag = lowpan_dev_info (dev )-> fragment_tag ++ ;
271
- lowpan_size = skb_network_header_len (skb );
280
+ u16 dgram_size , dgram_offset ;
281
+ __be16 frag_tag ;
282
+ u8 frag_hdr [5 ];
283
+ int frag_cap , frag_len , payload_cap , rc ;
284
+ int skb_unprocessed , skb_offset ;
285
+
272
286
dgram_size = lowpan_uncompress_size (skb , & dgram_offset ) -
273
- header_length ;
287
+ skb -> mac_len ;
288
+ frag_tag = lowpan_dev_info (dev )-> fragment_tag ++ ;
274
289
275
- /* first fragment header */
276
- head [0 ] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8 ) & 0x7 );
277
- head [1 ] = dgram_size & 0xff ;
278
- memcpy (head + 2 , & tag , sizeof (tag ));
290
+ frag_hdr [0 ] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8 ) & 0x07 );
291
+ frag_hdr [1 ] = dgram_size & 0xff ;
292
+ memcpy (frag_hdr + 2 , & frag_tag , sizeof (frag_tag ));
279
293
280
- /* calc the nearest payload length(divided to 8) for first fragment
281
- * which fits into a IEEE802154_MTU
282
- */
283
- frag_plen = round_down (IEEE802154_MTU - header_length -
284
- LOWPAN_FRAG1_HEAD_SIZE - lowpan_size -
285
- IEEE802154_MFR_SIZE , 8 );
286
-
287
- err = lowpan_fragment_xmit (skb , head , header_length ,
288
- frag_plen + lowpan_size , 0 ,
289
- LOWPAN_DISPATCH_FRAG1 );
290
- if (err ) {
291
- pr_debug ("%s unable to send FRAG1 packet (tag: %d)" ,
292
- __func__ , tag );
293
- goto exit ;
294
- }
294
+ payload_cap = ieee802154_max_payload (wpan_hdr );
295
295
296
- offset = lowpan_size + frag_plen ;
297
- dgram_offset += frag_plen ;
296
+ frag_len = round_down ( payload_cap - LOWPAN_FRAG1_HEAD_SIZE -
297
+ skb_network_header_len ( skb ), 8 ) ;
298
298
299
- /* next fragment header */
300
- head [0 ] &= ~LOWPAN_DISPATCH_FRAG1 ;
301
- head [0 ] |= LOWPAN_DISPATCH_FRAGN ;
299
+ skb_offset = skb_network_header_len (skb );
300
+ skb_unprocessed = skb -> len - skb -> mac_len - skb_offset ;
302
301
303
- frag_plen = round_down (IEEE802154_MTU - header_length -
304
- LOWPAN_FRAGN_HEAD_SIZE - IEEE802154_MFR_SIZE , 8 );
302
+ rc = lowpan_xmit_fragment (skb , wpan_hdr , frag_hdr ,
303
+ LOWPAN_FRAG1_HEAD_SIZE , 0 ,
304
+ frag_len + skb_network_header_len (skb ));
305
+ if (rc ) {
306
+ pr_debug ("%s unable to send FRAG1 packet (tag: %d)" ,
307
+ __func__ , frag_tag );
308
+ goto err ;
309
+ }
305
310
306
- while (payload_length - offset > 0 ) {
307
- int len = frag_plen ;
311
+ frag_hdr [0 ] &= ~LOWPAN_DISPATCH_FRAG1 ;
312
+ frag_hdr [0 ] |= LOWPAN_DISPATCH_FRAGN ;
313
+ frag_cap = round_down (payload_cap - LOWPAN_FRAGN_HEAD_SIZE , 8 );
308
314
309
- head [4 ] = dgram_offset >> 3 ;
315
+ while (skb_unprocessed >= frag_cap ) {
316
+ dgram_offset += frag_len ;
317
+ skb_offset += frag_len ;
318
+ skb_unprocessed -= frag_len ;
319
+ frag_len = min (frag_cap , skb_unprocessed );
310
320
311
- if (payload_length - offset < len )
312
- len = payload_length - offset ;
321
+ frag_hdr [4 ] = dgram_offset >> 3 ;
313
322
314
- err = lowpan_fragment_xmit (skb , head , header_length , len ,
315
- offset , LOWPAN_DISPATCH_FRAGN );
316
- if (err ) {
323
+ rc = lowpan_xmit_fragment (skb , wpan_hdr , frag_hdr ,
324
+ LOWPAN_FRAGN_HEAD_SIZE , skb_offset ,
325
+ frag_len );
326
+ if (rc ) {
317
327
pr_debug ("%s unable to send a FRAGN packet. (tag: %d, offset: %d)\n" ,
318
- __func__ , tag , offset );
319
- goto exit ;
328
+ __func__ , frag_tag , skb_offset );
329
+ goto err ;
320
330
}
321
-
322
- offset += len ;
323
- dgram_offset += len ;
324
331
}
325
332
326
- exit :
327
- return err ;
333
+ consume_skb (skb );
334
+ return NET_XMIT_SUCCESS ;
335
+
336
+ err :
337
+ kfree_skb (skb );
338
+ return rc ;
328
339
}
329
340
330
341
static netdev_tx_t lowpan_xmit (struct sk_buff * skb , struct net_device * dev )
331
342
{
332
- int err = -1 ;
343
+ struct ieee802154_hdr wpan_hdr ;
344
+ int max_single ;
333
345
334
346
pr_debug ("package xmit\n" );
335
347
336
- skb -> dev = lowpan_dev_info (dev )-> real_dev ;
337
- if (skb -> dev == NULL ) {
338
- pr_debug ("ERROR: no real wpan device found\n" );
339
- goto error ;
348
+ if (ieee802154_hdr_peek (skb , & wpan_hdr ) < 0 ) {
349
+ kfree_skb (skb );
350
+ return NET_XMIT_DROP ;
340
351
}
341
352
342
- /* Send directly if less than the MTU minus the 2 checksum bytes. */
343
- if (skb -> len <= IEEE802154_MTU - IEEE802154_MFR_SIZE ) {
344
- err = dev_queue_xmit (skb );
345
- goto out ;
346
- }
353
+ max_single = ieee802154_max_payload (& wpan_hdr );
347
354
348
- pr_debug ("frame is too big, fragmentation is needed\n" );
349
- err = lowpan_skb_fragmentation (skb , dev );
350
- error :
351
- dev_kfree_skb (skb );
352
- out :
353
- if (err )
354
- pr_debug ("ERROR: xmit failed\n" );
355
+ if (skb_tail_pointer (skb ) - skb_network_header (skb ) <= max_single ) {
356
+ skb -> dev = lowpan_dev_info (dev )-> real_dev ;
357
+ return dev_queue_xmit (skb );
358
+ } else {
359
+ netdev_tx_t rc ;
360
+
361
+ pr_debug ("frame is too big, fragmentation is needed\n" );
362
+ rc = lowpan_xmit_fragmented (skb , dev , & wpan_hdr );
355
363
356
- return (err < 0 ) ? NET_XMIT_DROP : err ;
364
+ return rc < 0 ? NET_XMIT_DROP : rc ;
365
+ }
357
366
}
358
367
359
368
static struct wpan_phy * lowpan_get_phy (const struct net_device * dev )
0 commit comments