aboutsummaryrefslogtreecommitdiffstats
path: root/net/atm/br2684.c
diff options
context:
space:
mode:
authorEric Kinzie <ekinzie@cmf.nrl.navy.mil>2007-12-31 02:17:53 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:00:13 -0500
commit097b19a9987204b898299260ee3ebff4cf716800 (patch)
tree03e8d7e60e7b5d2bc2987ebbce7a7a132519311b /net/atm/br2684.c
parent900092a45e73fc192c223761b85005503a813975 (diff)
[ATM]: [br2864] routed support
Signed-off-by: Chas Williams <chas@cmf.nrl.navy.mil> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/atm/br2684.c')
-rw-r--r--net/atm/br2684.c148
1 files changed, 116 insertions, 32 deletions
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index ba6428f204f9..d9bb2a16b7cb 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -1,7 +1,8 @@
1/* 1/*
2Experimental ethernet netdevice using ATM AAL5 as underlying carrier 2Ethernet netdevice using ATM AAL5 as underlying carrier
3(RFC1483 obsoleted by RFC2684) for Linux 2.4 3(RFC1483 obsoleted by RFC2684) for Linux
4Author: Marcell GAL, 2000, XDSL Ltd, Hungary 4Authors: Marcell GAL, 2000, XDSL Ltd, Hungary
5 Eric Kinzie, 2006-2007, US Naval Research Laboratory
5*/ 6*/
6 7
7#include <linux/module.h> 8#include <linux/module.h>
@@ -39,9 +40,27 @@ static void skb_debug(const struct sk_buff *skb)
39#define skb_debug(skb) do {} while (0) 40#define skb_debug(skb) do {} while (0)
40#endif 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
54static unsigned char ethertype_ipv4[] =
55 { ETHERTYPE_IPV4 };
56static unsigned char ethertype_ipv6[] =
57 { ETHERTYPE_IPV6 };
42static unsigned char llc_oui_pid_pad[] = 58static unsigned char llc_oui_pid_pad[] =
43 { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 }; 59 { LLC, SNAP_BRIDGED, PID_ETHERNET, PAD_BRIDGED };
44#define PADLEN (2) 60static unsigned char llc_oui_ipv4[] =
61 { LLC, SNAP_ROUTED, ETHERTYPE_IPV4 };
62static unsigned char llc_oui_ipv6[] =
63 { LLC, SNAP_ROUTED, ETHERTYPE_IPV6 };
45 64
46enum br2684_encaps { 65enum br2684_encaps {
47 e_vc = BR2684_ENCAPS_VC, 66 e_vc = BR2684_ENCAPS_VC,
@@ -69,6 +88,7 @@ struct br2684_dev {
69 struct list_head brvccs; /* one device <=> one vcc (before xmas) */ 88 struct list_head brvccs; /* one device <=> one vcc (before xmas) */
70 struct net_device_stats stats; 89 struct net_device_stats stats;
71 int mac_was_set; 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 struct atm_vcc *atmvcc; 157 struct atm_vcc *atmvcc;
138 int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2; 158 int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2;
159
139 if (skb_headroom(skb) < minheadroom) { 160 if (skb_headroom(skb) < minheadroom) {
140 struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom); 161 struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom);
141 brvcc->copies_needed++; 162 brvcc->copies_needed++;
@@ -146,11 +167,32 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
146 } 167 }
147 skb = skb2; 168 skb = skb2;
148 } 169 }
149 skb_push(skb, minheadroom); 170
150 if (brvcc->encaps == e_llc) 171 if (brvcc->encaps == e_llc) {
151 skb_copy_to_linear_data(skb, llc_oui_pid_pad, 10); 172 if (brdev->payload == p_bridged) {
152 else 173 skb_push(skb, sizeof(llc_oui_pid_pad));
153 memset(skb->data, 0, 2); 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 skb_debug(skb); 196 skb_debug(skb);
155 197
156 ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; 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 struct br2684_vcc *brvcc = BR2684_VCC(atmvcc); 341 struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);
300 struct net_device *net_dev = brvcc->device; 342 struct net_device *net_dev = brvcc->device;
301 struct br2684_dev *brdev = BRPRIV(net_dev); 343 struct br2684_dev *brdev = BRPRIV(net_dev);
302 int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN;
303 344
304 pr_debug("br2684_push\n"); 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 atm_return(atmvcc, skb->truesize); 361 atm_return(atmvcc, skb->truesize);
321 pr_debug("skb from brdev %p\n", brdev); 362 pr_debug("skb from brdev %p\n", brdev);
322 if (brvcc->encaps == e_llc) { 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 /* let us waste some time for checking the encapsulation. 384 /* let us waste some time for checking the encapsulation.
324 Note, that only 7 char is checked so frames with a valid FCS 385 Note, that only 7 char is checked so frames with a valid FCS
325 are also accepted (but FCS is not checked of course) */ 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 brdev->stats.rx_errors++; 392 brdev->stats.rx_errors++;
328 dev_kfree_skb(skb); 393 dev_kfree_skb(skb);
329 return; 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 } else { 397 } else {
336 plen = PADLEN + ETH_HLEN; /* pad, dstmac,srcmac, ethtype */
337 /* first 2 chars should be 0 */ 398 /* first 2 chars should be 0 */
338 if (*((u16 *) (skb->data)) != 0) { 399 if (*((u16 *) (skb->data)) != 0) {
339 brdev->stats.rx_errors++; 400 brdev->stats.rx_errors++;
340 dev_kfree_skb(skb); 401 dev_kfree_skb(skb);
341 return; 402 return;
342 } 403 }
343 } 404 skb_pull(skb, BR2684_PAD_LEN + ETH_HLEN); /* pad, dstmac, srcmac, ethtype */
344 if (skb->len < plen) { 405 skb->protocol = eth_type_trans(skb, net_dev);
345 brdev->stats.rx_errors++;
346 dev_kfree_skb(skb); /* dev_ not needed? */
347 return;
348 } 406 }
349 407
350 skb_pull(skb, plen - ETH_HLEN);
351 skb->protocol = eth_type_trans(skb, net_dev);
352#ifdef CONFIG_ATM_BR2684_IPFILTER 408#ifdef CONFIG_ATM_BR2684_IPFILTER
353 if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb))) { 409 if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb))) {
354 brdev->stats.rx_dropped++; 410 brdev->stats.rx_dropped++;
@@ -482,25 +538,52 @@ static void br2684_setup(struct net_device *netdev)
482 INIT_LIST_HEAD(&brdev->brvccs); 538 INIT_LIST_HEAD(&brdev->brvccs);
483} 539}
484 540
541static 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
485static int br2684_create(void __user *arg) 559static int br2684_create(void __user *arg)
486{ 560{
487 int err; 561 int err;
488 struct net_device *netdev; 562 struct net_device *netdev;
489 struct br2684_dev *brdev; 563 struct br2684_dev *brdev;
490 struct atm_newif_br2684 ni; 564 struct atm_newif_br2684 ni;
565 enum br2684_payload payload;
491 566
492 pr_debug("br2684_create\n"); 567 pr_debug("br2684_create\n");
493 568
494 if (copy_from_user(&ni, arg, sizeof ni)) { 569 if (copy_from_user(&ni, arg, sizeof ni)) {
495 return -EFAULT; 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 if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) { 579 if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) {
498 return -EINVAL; 580 return -EINVAL;
499 } 581 }
500 582
501 netdev = alloc_netdev(sizeof(struct br2684_dev), 583 netdev = alloc_netdev(sizeof(struct br2684_dev),
502 ni.ifname[0] ? ni.ifname : "nas%d", 584 ni.ifname[0] ? ni.ifname : "nas%d",
503 br2684_setup); 585 (payload == p_routed) ?
586 br2684_setup_routed : br2684_setup);
504 if (!netdev) 587 if (!netdev)
505 return -ENOMEM; 588 return -ENOMEM;
506 589
@@ -516,6 +599,7 @@ static int br2684_create(void __user *arg)
516 } 599 }
517 600
518 write_lock_irq(&devs_lock); 601 write_lock_irq(&devs_lock);
602 brdev->payload = payload;
519 brdev->number = list_empty(&br2684_devs) ? 1 : 603 brdev->number = list_empty(&br2684_devs) ? 1 :
520 BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1; 604 BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
521 list_add_tail(&brdev->br2684_devs, &br2684_devs); 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 brdev->mac_was_set ? "set" : "auto"); 685 brdev->mac_was_set ? "set" : "auto");
602 686
603 list_for_each_entry(brvcc, &brdev->brvccs, brvccs) { 687 list_for_each_entry(brvcc, &brdev->brvccs, brvccs) {
604 seq_printf(seq, " vcc %d.%d.%d: encaps=%s" 688 seq_printf(seq, " vcc %d.%d.%d: encaps=%s payload=%s"
605 ", failed copies %u/%u" 689 ", failed copies %u/%u"
606 "\n", brvcc->atmvcc->dev->number, 690 "\n", brvcc->atmvcc->dev->number,
607 brvcc->atmvcc->vpi, brvcc->atmvcc->vci, 691 brvcc->atmvcc->vpi, brvcc->atmvcc->vci,
608 (brvcc->encaps == e_llc) ? "LLC" : "VC" 692 (brvcc->encaps == e_llc) ? "LLC" : "VC",
609 , brvcc->copies_failed 693 (brdev->payload == p_bridged) ? "bridged" : "routed",
610 , brvcc->copies_needed 694 brvcc->copies_failed,
611 ); 695 brvcc->copies_needed);
612#ifdef CONFIG_ATM_BR2684_IPFILTER 696#ifdef CONFIG_ATM_BR2684_IPFILTER
613#define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte] 697#define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte]
614#define bs(var) b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3) 698#define bs(var) b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3)