1
1
/*
2
- Experimental ethernet netdevice using ATM AAL5 as underlying carrier
3
- (RFC1483 obsoleted by RFC2684) for Linux 2.4
4
- Author: Marcell GAL, 2000, XDSL Ltd, Hungary
2
+ Ethernet netdevice using ATM AAL5 as underlying carrier
3
+ (RFC1483 obsoleted by RFC2684) for Linux
4
+ Authors: Marcell GAL, 2000, XDSL Ltd, Hungary
5
+ Eric Kinzie, 2006-2007, US Naval Research Laboratory
5
6
*/
6
7
7
8
#include <linux/module.h>
@@ -39,9 +40,27 @@ static void skb_debug(const struct sk_buff *skb)
39
40
#define skb_debug (skb ) do {} while (0)
40
41
#endif
41
42
43
+ #define BR2684_ETHERTYPE_LEN 2
44
+ #define BR2684_PAD_LEN 2
45
+
46
+ #define LLC 0xaa, 0xaa, 0x03
47
+ #define SNAP_BRIDGED 0x00, 0x80, 0xc2
48
+ #define SNAP_ROUTED 0x00, 0x00, 0x00
49
+ #define PID_ETHERNET 0x00, 0x07
50
+ #define ETHERTYPE_IPV4 0x08, 0x00
51
+ #define ETHERTYPE_IPV6 0x86, 0xdd
52
+ #define PAD_BRIDGED 0x00, 0x00
53
+
54
+ static unsigned char ethertype_ipv4 [] =
55
+ { ETHERTYPE_IPV4 };
56
+ static unsigned char ethertype_ipv6 [] =
57
+ { ETHERTYPE_IPV6 };
42
58
static unsigned char llc_oui_pid_pad [] =
43
- { 0xAA , 0xAA , 0x03 , 0x00 , 0x80 , 0xC2 , 0x00 , 0x07 , 0x00 , 0x00 };
44
- #define PADLEN (2)
59
+ { LLC , SNAP_BRIDGED , PID_ETHERNET , PAD_BRIDGED };
60
+ static unsigned char llc_oui_ipv4 [] =
61
+ { LLC , SNAP_ROUTED , ETHERTYPE_IPV4 };
62
+ static unsigned char llc_oui_ipv6 [] =
63
+ { LLC , SNAP_ROUTED , ETHERTYPE_IPV6 };
45
64
46
65
enum br2684_encaps {
47
66
e_vc = BR2684_ENCAPS_VC ,
@@ -69,6 +88,7 @@ struct br2684_dev {
69
88
struct list_head brvccs ; /* one device <=> one vcc (before xmas) */
70
89
struct net_device_stats stats ;
71
90
int mac_was_set ;
91
+ enum br2684_payload payload ;
72
92
};
73
93
74
94
/*
@@ -136,6 +156,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
136
156
{
137
157
struct atm_vcc * atmvcc ;
138
158
int minheadroom = (brvcc -> encaps == e_llc ) ? 10 : 2 ;
159
+
139
160
if (skb_headroom (skb ) < minheadroom ) {
140
161
struct sk_buff * skb2 = skb_realloc_headroom (skb , minheadroom );
141
162
brvcc -> copies_needed ++ ;
@@ -146,11 +167,32 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
146
167
}
147
168
skb = skb2 ;
148
169
}
149
- skb_push (skb , minheadroom );
150
- if (brvcc -> encaps == e_llc )
151
- skb_copy_to_linear_data (skb , llc_oui_pid_pad , 10 );
152
- else
153
- memset (skb -> data , 0 , 2 );
170
+
171
+ if (brvcc -> encaps == e_llc ) {
172
+ if (brdev -> payload == p_bridged ) {
173
+ skb_push (skb , sizeof (llc_oui_pid_pad ));
174
+ skb_copy_to_linear_data (skb , llc_oui_pid_pad , sizeof (llc_oui_pid_pad ));
175
+ } else if (brdev -> payload == p_routed ) {
176
+ unsigned short prot = ntohs (skb -> protocol );
177
+
178
+ skb_push (skb , sizeof (llc_oui_ipv4 ));
179
+ switch (prot ) {
180
+ case ETH_P_IP :
181
+ skb_copy_to_linear_data (skb , llc_oui_ipv4 , sizeof (llc_oui_ipv4 ));
182
+ break ;
183
+ case ETH_P_IPV6 :
184
+ skb_copy_to_linear_data (skb , llc_oui_ipv6 , sizeof (llc_oui_ipv6 ));
185
+ break ;
186
+ default :
187
+ dev_kfree_skb (skb );
188
+ return 0 ;
189
+ }
190
+ }
191
+ } else {
192
+ skb_push (skb , 2 );
193
+ if (brdev -> payload == p_bridged )
194
+ memset (skb -> data , 0 , 2 );
195
+ }
154
196
skb_debug (skb );
155
197
156
198
ATM_SKB (skb )-> vcc = atmvcc = brvcc -> atmvcc ;
@@ -299,7 +341,6 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
299
341
struct br2684_vcc * brvcc = BR2684_VCC (atmvcc );
300
342
struct net_device * net_dev = brvcc -> device ;
301
343
struct br2684_dev * brdev = BRPRIV (net_dev );
302
- int plen = sizeof (llc_oui_pid_pad ) + ETH_HLEN ;
303
344
304
345
pr_debug ("br2684_push\n" );
305
346
@@ -320,35 +361,50 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
320
361
atm_return (atmvcc , skb -> truesize );
321
362
pr_debug ("skb from brdev %p\n" , brdev );
322
363
if (brvcc -> encaps == e_llc ) {
364
+
365
+ if (skb -> len > 7 && skb -> data [7 ] == 0x01 )
366
+ __skb_trim (skb , skb -> len - 4 );
367
+
368
+ /* accept packets that have "ipv[46]" in the snap header */
369
+ if ((skb -> len >= (sizeof (llc_oui_ipv4 )))
370
+ && (memcmp (skb -> data , llc_oui_ipv4 , sizeof (llc_oui_ipv4 ) - BR2684_ETHERTYPE_LEN ) == 0 )) {
371
+ if (memcmp (skb -> data + 6 , ethertype_ipv6 , sizeof (ethertype_ipv6 )) == 0 )
372
+ skb -> protocol = __constant_htons (ETH_P_IPV6 );
373
+ else if (memcmp (skb -> data + 6 , ethertype_ipv4 , sizeof (ethertype_ipv4 )) == 0 )
374
+ skb -> protocol = __constant_htons (ETH_P_IP );
375
+ else {
376
+ brdev -> stats .rx_errors ++ ;
377
+ dev_kfree_skb (skb );
378
+ return ;
379
+ }
380
+ skb_pull (skb , sizeof (llc_oui_ipv4 ));
381
+ skb_reset_network_header (skb );
382
+ skb -> pkt_type = PACKET_HOST ;
383
+
323
384
/* let us waste some time for checking the encapsulation.
324
385
Note, that only 7 char is checked so frames with a valid FCS
325
386
are also accepted (but FCS is not checked of course) */
326
- if (memcmp (skb -> data , llc_oui_pid_pad , 7 )) {
387
+ } else if ((skb -> len >= sizeof (llc_oui_pid_pad )) &&
388
+ (memcmp (skb -> data , llc_oui_pid_pad , 7 ) == 0 )) {
389
+ skb_pull (skb , sizeof (llc_oui_pid_pad ));
390
+ skb -> protocol = eth_type_trans (skb , net_dev );
391
+ } else {
327
392
brdev -> stats .rx_errors ++ ;
328
393
dev_kfree_skb (skb );
329
394
return ;
330
395
}
331
396
332
- /* Strip FCS if present */
333
- if (skb -> len > 7 && skb -> data [7 ] == 0x01 )
334
- __skb_trim (skb , skb -> len - 4 );
335
397
} else {
336
- plen = PADLEN + ETH_HLEN ; /* pad, dstmac,srcmac, ethtype */
337
398
/* first 2 chars should be 0 */
338
399
if (* ((u16 * ) (skb -> data )) != 0 ) {
339
400
brdev -> stats .rx_errors ++ ;
340
401
dev_kfree_skb (skb );
341
402
return ;
342
403
}
343
- }
344
- if (skb -> len < plen ) {
345
- brdev -> stats .rx_errors ++ ;
346
- dev_kfree_skb (skb ); /* dev_ not needed? */
347
- return ;
404
+ skb_pull (skb , BR2684_PAD_LEN + ETH_HLEN ); /* pad, dstmac, srcmac, ethtype */
405
+ skb -> protocol = eth_type_trans (skb , net_dev );
348
406
}
349
407
350
- skb_pull (skb , plen - ETH_HLEN );
351
- skb -> protocol = eth_type_trans (skb , net_dev );
352
408
#ifdef CONFIG_ATM_BR2684_IPFILTER
353
409
if (unlikely (packet_fails_filter (skb -> protocol , brvcc , skb ))) {
354
410
brdev -> stats .rx_dropped ++ ;
@@ -482,25 +538,52 @@ static void br2684_setup(struct net_device *netdev)
482
538
INIT_LIST_HEAD (& brdev -> brvccs );
483
539
}
484
540
541
+ static void br2684_setup_routed (struct net_device * netdev )
542
+ {
543
+ struct br2684_dev * brdev = BRPRIV (netdev );
544
+ brdev -> net_dev = netdev ;
545
+
546
+ netdev -> hard_header_len = 0 ;
547
+ my_eth_mac_addr = netdev -> set_mac_address ;
548
+ netdev -> set_mac_address = br2684_mac_addr ;
549
+ netdev -> hard_start_xmit = br2684_start_xmit ;
550
+ netdev -> get_stats = br2684_get_stats ;
551
+ netdev -> addr_len = 0 ;
552
+ netdev -> mtu = 1500 ;
553
+ netdev -> type = ARPHRD_PPP ;
554
+ netdev -> flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST ;
555
+ netdev -> tx_queue_len = 100 ;
556
+ INIT_LIST_HEAD (& brdev -> brvccs );
557
+ }
558
+
485
559
static int br2684_create (void __user * arg )
486
560
{
487
561
int err ;
488
562
struct net_device * netdev ;
489
563
struct br2684_dev * brdev ;
490
564
struct atm_newif_br2684 ni ;
565
+ enum br2684_payload payload ;
491
566
492
567
pr_debug ("br2684_create\n" );
493
568
494
569
if (copy_from_user (& ni , arg , sizeof ni )) {
495
570
return - EFAULT ;
496
571
}
572
+
573
+ if (ni .media & BR2684_FLAG_ROUTED )
574
+ payload = p_routed ;
575
+ else
576
+ payload = p_bridged ;
577
+ ni .media &= 0xffff ; /* strip flags */
578
+
497
579
if (ni .media != BR2684_MEDIA_ETHERNET || ni .mtu != 1500 ) {
498
580
return - EINVAL ;
499
581
}
500
582
501
583
netdev = alloc_netdev (sizeof (struct br2684_dev ),
502
584
ni .ifname [0 ] ? ni .ifname : "nas%d" ,
503
- br2684_setup );
585
+ (payload == p_routed ) ?
586
+ br2684_setup_routed : br2684_setup );
504
587
if (!netdev )
505
588
return - ENOMEM ;
506
589
@@ -516,6 +599,7 @@ static int br2684_create(void __user *arg)
516
599
}
517
600
518
601
write_lock_irq (& devs_lock );
602
+ brdev -> payload = payload ;
519
603
brdev -> number = list_empty (& br2684_devs ) ? 1 :
520
604
BRPRIV (list_entry_brdev (br2684_devs .prev ))-> number + 1 ;
521
605
list_add_tail (& brdev -> br2684_devs , & br2684_devs );
@@ -601,14 +685,14 @@ static int br2684_seq_show(struct seq_file *seq, void *v)
601
685
brdev -> mac_was_set ? "set" : "auto" );
602
686
603
687
list_for_each_entry (brvcc , & brdev -> brvccs , brvccs ) {
604
- seq_printf (seq , " vcc %d.%d.%d: encaps=%s"
605
- ", failed copies %u/%u"
606
- "\n" , brvcc -> atmvcc -> dev -> number ,
607
- brvcc -> atmvcc -> vpi , brvcc -> atmvcc -> vci ,
608
- (brvcc -> encaps == e_llc ) ? "LLC" : "VC"
609
- , brvcc -> copies_failed
610
- , brvcc -> copies_needed
611
- );
688
+ seq_printf (seq , " vcc %d.%d.%d: encaps=%s payload=%s "
689
+ ", failed copies %u/%u"
690
+ "\n" , brvcc -> atmvcc -> dev -> number ,
691
+ brvcc -> atmvcc -> vpi , brvcc -> atmvcc -> vci ,
692
+ (brvcc -> encaps == e_llc ) ? "LLC" : "VC" ,
693
+ ( brdev -> payload == p_bridged ) ? "bridged" : "routed" ,
694
+ brvcc -> copies_failed ,
695
+ brvcc -> copies_needed );
612
696
#ifdef CONFIG_ATM_BR2684_IPFILTER
613
697
#define b1 (var , byte ) ((u8 *) &brvcc->filter.var)[byte]
614
698
#define bs (var ) b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3)
0 commit comments