From: Florian Fainelli Date: Wed, 2 Apr 2008 13:00:06 +0000 (+0000) Subject: Add routed support to br2684 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=add755735aec58378331cb82a6634ca4eb5ee8d7;p=openwrt%2Fstaging%2Fdangole.git Add routed support to br2684 Signed-off-by: Juan I. Gonzalez SVN-Revision: 10710 --- diff --git a/package/br2684ctl/files/br2684ctl b/package/br2684ctl/files/br2684ctl index b121c7a4a5..b31373ffc5 100755 --- a/package/br2684ctl/files/br2684ctl +++ b/package/br2684ctl/files/br2684ctl @@ -14,11 +14,16 @@ start_daemon() { config_get vpi "$cfg" vpi config_get vci "$cfg" vci config_get encaps "$cfg" encaps + config_get payload "cfg" payload case "$encaps" in 1|vc) encaps=1;; *) encaps=0;; esac - br2684ctl -b -c "$unit" -e "$encaps" -a "${atmdev:+$atmdev.}${vpi:-8}.${vci:-35}" + case "$payload" in + 1|bridged) payload=1;; + *) payload=0;; + esac + br2684ctl -b -c "$unit" -e "$encaps" -p "$payload" -a "${atmdev:+$atmdev.}${vpi:-8}.${vci:-35}" } start() { diff --git a/package/br2684ctl/patches/101-routed_support.patch b/package/br2684ctl/patches/101-routed_support.patch new file mode 100644 index 0000000000..8c73a43648 --- /dev/null +++ b/package/br2684ctl/patches/101-routed_support.patch @@ -0,0 +1,301 @@ +diff -Nu br2684ctl-20040226.orig/br2684ctl.c br2684ctl.orig/br2684ctl.c +--- br2684ctl-20040226.orig/br2684ctl.c 2008-03-25 22:26:59.000000000 +0000 ++++ br2684ctl.orig/br2684ctl.c 2008-03-31 10:11:06.000000000 +0100 +@@ -10,6 +10,10 @@ + #include + #include + #include ++#ifndef BR2684_FLAG_ROUTED ++#warning "Kernel missing routed support for br2684" ++#define BR2684_FLAG_ROUTED (1<<16) /* payload is routed, not bridged */ ++#endif + + /* Written by Marcell GAL to make use of the */ + /* ioctls defined in the br2684... kernel patch */ +@@ -28,26 +32,35 @@ + #define LOG_OPTION LOG_PERROR|LOG_PID + #define LOG_FACILITY LOG_LOCAL2 + ++struct br2684_params { ++ int itfnum; ++ int encap; ++ int sndbuf; ++ int payload; ++ char *astr; /* temporary */ ++ struct atm_qos reqqos; ++}; ++ + + int lastsock, lastitf; + + +-void fatal(const char *str, int i) ++void fatal(const char *str, int err) + { +- syslog (LOG_ERR,"Fatal: %s",str); ++ syslog (LOG_ERR,"Fatal: %s; %s", str, strerror(err)); + exit(-2); + }; + + + void exitFunc(void) + { +- syslog (LOG_NOTICE,"Daemon terminated\n"); ++ syslog (LOG_NOTICE,"Daemon terminated"); + } + + + void int_signal(int dummy) + { +- syslog (LOG_INFO,"Killed by a signal\n"); ++ syslog (LOG_INFO,"Killed by a signal"); + exit(0); + } + +@@ -58,7 +71,7 @@ + + if (num < 0) return -1; + +- snprintf(name, 20, "/var/run/nas%d.pid", num); ++ snprintf(name, 32, "/var/run/br2684ctl-nas%d.pid", num); + pidfile = fopen(name, "w"); + if (pidfile == NULL) return -1; + fprintf(pidfile, "%d", getpid()); +@@ -67,9 +80,9 @@ + return 0; + } + +-int create_br(char *nstr) ++int create_br(int itfnum, int payload) + { +- int num, err; ++ int err; + + if(lastsock<0) { + lastsock = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5); +@@ -78,31 +91,36 @@ + syslog(LOG_ERR, "socket creation failed: %s",strerror(errno)); + } else { + /* create the device with ioctl: */ +- num=atoi(nstr); +- if( num>=0 && num<1234567890){ ++ if( itfnum>=0 && itfnum<1234567890){ + struct atm_newif_br2684 ni; + ni.backend_num = ATM_BACKEND_BR2684; + ni.media = BR2684_MEDIA_ETHERNET; ++#ifdef BR2684_FLAG_ROUTED ++ if (payload == 0) ++ ni.media |= BR2684_FLAG_ROUTED; ++#endif + ni.mtu = 1500; +- sprintf(ni.ifname, "nas%d", num); ++ sprintf(ni.ifname, "nas%d", itfnum); + err=ioctl (lastsock, ATM_NEWBACKENDIF, &ni); + + if (err == 0) +- syslog(LOG_NOTICE, "Interface \"%s\" created sucessfully\n",ni.ifname); ++ syslog(LOG_NOTICE, "Interface \"%s\" created sucessfully",ni.ifname); + else +- syslog(LOG_INFO, "Interface \"%s\" could not be created, reason: %s\n", ++ syslog(LOG_INFO, "Interface \"%s\" could not be created, reason: %s", + ni.ifname, + strerror(errno)); +- lastitf=num; /* even if we didn't create, because existed, assign_vcc wil want to know it! */ ++ lastitf=itfnum; /* even if we didn't create, because existed, ++ assign_vcc wil want to know it! */ + } else { +- syslog(LOG_ERR,"err: strange interface number %d", num ); ++ syslog(LOG_ERR,"err: strange interface number %d", itfnum ); + } + } + return 0; + } + + +-int assign_vcc(char *astr, int encap, int bufsize, struct atm_qos qos) ++int assign_vcc(char *astr, int encap, int payload, ++ int bufsize, struct atm_qos qos) + { + int err; + struct sockaddr_atmpvc addr; +@@ -112,21 +130,17 @@ + memset(&addr, 0, sizeof(addr)); + err=text2atm(astr,(struct sockaddr *)(&addr), sizeof(addr), T2A_PVC); + if (err!=0) +- syslog(LOG_ERR,"Could not parse ATM parameters (error=%d)\n",err); ++ syslog(LOG_ERR,"Could not parse ATM parameters (error=%d)",err); + +-#if 0 +- addr.sap_family = AF_ATMPVC; +- addr.sap_addr.itf = itf; +- addr.sap_addr.vpi = 0; +- addr.sap_addr.vci = vci; +-#endif +- syslog(LOG_NOTICE,"Communicating over ATM %d.%d.%d, encapsulation: %s\n", addr.sap_addr.itf, ++ syslog(LOG_NOTICE,"Communicating over ATM %d.%d.%d, encapsulation: %s", ++ addr.sap_addr.itf, + addr.sap_addr.vpi, + addr.sap_addr.vci, + encap?"VC mux":"LLC"); + + if ((fd = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5)) < 0) +- syslog(LOG_ERR,"failed to create socket %d, reason: %s", errno,strerror(errno)); ++ syslog(LOG_ERR,"failed to create socket %d, reason: %s", ++ errno,strerror(errno)); + + if (qos.aal == 0) { + qos.aal = ATM_AAL5; +@@ -137,7 +151,7 @@ + } + + if ( (err=setsockopt(fd,SOL_SOCKET,SO_SNDBUF, &bufsize ,sizeof(bufsize))) ) +- syslog(LOG_ERR,"setsockopt SO_SNDBUF: (%d) %s\n",err, strerror(err)); ++ syslog(LOG_ERR,"setsockopt SO_SNDBUF: (%d) %s",err, strerror(err)); + + if (setsockopt(fd, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0) + syslog(LOG_ERR,"setsockopt SO_ATMQOS %d", errno); +@@ -145,7 +159,7 @@ + err = connect(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_atmpvc)); + + if (err < 0) +- fatal("failed to connect on socket", err); ++ fatal("failed to connect on socket", errno); + + /* attach the vcc to device: */ + +@@ -169,10 +183,30 @@ + return fd ; + } + ++void start_interface(struct br2684_params* params) ++{ ++ if (params->astr==NULL) { ++ syslog(LOG_ERR, "Required ATM parameters not specified."); ++ exit(1); ++ } ++ ++ create_br(params->itfnum, params->payload); ++ assign_vcc(params->astr, params->encap, params->payload, params->sndbuf, ++ params->reqqos); ++} ++ + + void usage(char *s) + { +- printf("usage: %s [-b] [[-c number] [-e 0|1] [-s sndbuf] [-q qos] [-a [itf.]vpi.vci]*]*\n", s); ++ printf("usage: %s [-b] [[-c number] [-e 0|1] [-s sndbuf] [-q qos] [-p 0|1] " ++ "[-a [itf.]vpi.vci]*]*\n" ++ " -b = run in background (daemonize)\n" ++ " -c = use interface nas\n" ++ " -e 0|1 = encapsulation (0=LLC, 1=VC Mux)\n" ++ " -p 0|1 = payload type (0=routed,1=bridged)\n" ++ " -s = set sndbuf (send buffer) size (default 8192)\n" ++ " -a [itf.]vpi.vci = ATM interface no, VPI, VCI\n", ++ s); + exit(1); + } + +@@ -180,47 +214,63 @@ + + int main (int argc, char **argv) + { +- int c, background=0, encap=0, sndbuf=8192; +- struct atm_qos reqqos; +- int itfnum; ++ int c, background=0; ++ ++ struct br2684_params params; ++ params.itfnum=-1; ++ params.encap=0; ++ params.sndbuf=8192; ++ params.payload=1; ++ params.astr=NULL; ++ memset(¶ms.reqqos, 0, sizeof(params.reqqos)); ++ + lastsock=-1; + lastitf=0; + + /* st qos to 0 */ +- memset(&reqqos, 0, sizeof(reqqos)); + + openlog (LOG_NAME,LOG_OPTION,LOG_FACILITY); + if (argc>1) +- while ((c = getopt(argc, argv,"q:a:bc:e:s:?h")) !=EOF) ++ while ((c = getopt(argc, argv,"q:a:bc:e:s:p:?h")) !=EOF) + switch (c) { + case 'q': + printf ("optarg : %s",optarg); +- if (text2qos(optarg,&reqqos,0)) fprintf(stderr,"QOS parameter invalid\n"); ++ if (text2qos(optarg,¶ms.reqqos,0)) ++ fprintf(stderr,"QOS parameter invalid\n"); + break; + case 'a': +- assign_vcc(optarg, encap, sndbuf, reqqos); ++ params.astr=optarg; + break; + case 'b': + background=1; + break; + case 'c': +- create_br(optarg); +- itfnum = atoi(optarg); ++ /* temporary, to make it work with multiple interfaces: */ ++ if (params.itfnum>=0) start_interface(¶ms); ++ params.itfnum= atoi(optarg); + break; + case 'e': +- encap=(atoi(optarg)); +- if(encap<0){ +- syslog (LOG_ERR, "invalid encapsulation: %s:\n",optarg); +- encap=0; ++ params.encap=(atoi(optarg)); ++ if(params.encap<0){ ++ syslog (LOG_ERR, "invalid encapsulation: %s:",optarg); ++ params.encap=0; + } + break; + case 's': +- sndbuf=(atoi(optarg)); +- if(sndbuf<0){ +- syslog(LOG_ERR, "Invalid sndbuf: %s, using size of 8192 instead\n",optarg); +- sndbuf=8192; ++ params.sndbuf=(atoi(optarg)); ++ if(params.sndbuf<0){ ++ syslog(LOG_ERR, "Invalid sndbuf: %s, using size of 8192 instead", ++ optarg); ++ params.sndbuf=8192; + } + break; ++ case 'p': /* payload type: routed (0) or bridged (1) */ ++#ifdef BR2684_FLAG_ROUTED ++ params.payload = atoi(optarg); ++ break; ++#else ++ syslog(LOG_ERR, "payload option not supported."); ++#endif + case '?': + case 'h': + default: +@@ -231,6 +281,8 @@ + + if (argc != optind) usage(argv[0]); + ++ start_interface(¶ms); ++ + if(lastsock>=0) close(lastsock); + + if (background) { +@@ -268,11 +275,11 @@ + + } + +- create_pidfile(itfnum); ++ create_pidfile(params.itfnum); + signal(SIGINT, int_signal); + signal(SIGTERM, int_signal); + +- syslog (LOG_INFO, "RFC 1483/2684 bridge daemon started\n"); ++ syslog (LOG_INFO, "RFC 1483/2684 bridge daemon started"); + atexit (exitFunc); + + while (1) pause(); /* to keep the sockets... */ diff --git a/target/linux/generic-2.6/patches-2.6.24/601-br2684-routed-support.patch b/target/linux/generic-2.6/patches-2.6.24/601-br2684-routed-support.patch new file mode 100644 index 0000000000..88a27f3f73 --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.24/601-br2684-routed-support.patch @@ -0,0 +1,730 @@ +diff -Nur linux-2.6.24.2/include/linux/atmbr2684.h linux-2.6.24.2-copy/include/linux/atmbr2684.h +--- linux-2.6.24.2/include/linux/atmbr2684.h 2008-02-11 05:51:11.000000000 +0000 ++++ linux-2.6.24.2-copy/include/linux/atmbr2684.h 2008-03-27 01:08:42.000000000 +0000 +@@ -14,6 +14,9 @@ + #define BR2684_MEDIA_FDDI (3) + #define BR2684_MEDIA_802_6 (4) /* 802.6 */ + ++ /* used only at device creation: */ ++#define BR2684_FLAG_ROUTED (1<<16) /* payload is routed, not bridged */ ++ + /* + * Is there FCS inbound on this VC? This currently isn't supported. + */ +@@ -36,15 +39,22 @@ + #define BR2684_ENCAPS_AUTODETECT (2) /* Unsuported */ + + /* ++ * Is this VC bridged or routed? ++ */ ++ ++#define BR2684_PAYLOAD_ROUTED (0) ++#define BR2684_PAYLOAD_BRIDGED (1) ++ ++/* + * This is for the ATM_NEWBACKENDIF call - these are like socket families: + * the first element of the structure is the backend number and the rest + * is per-backend specific + */ + struct atm_newif_br2684 { +- atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */ +- int media; /* BR2684_MEDIA_* */ +- char ifname[IFNAMSIZ]; +- int mtu; ++ atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */ ++ int media; /* BR2684_MEDIA_*, flags in upper bits */ ++ char ifname[IFNAMSIZ]; ++ int mtu; + }; + + /* +@@ -55,10 +65,10 @@ + #define BR2684_FIND_BYNUM (1) + #define BR2684_FIND_BYIFNAME (2) + struct br2684_if_spec { +- int method; /* BR2684_FIND_* */ ++ int method; /* BR2684_FIND_* */ + union { +- char ifname[IFNAMSIZ]; +- int devnum; ++ char ifname[IFNAMSIZ]; ++ int devnum; + } spec; + }; + +@@ -68,16 +78,16 @@ + * is per-backend specific + */ + struct atm_backend_br2684 { +- atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */ ++ atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */ + struct br2684_if_spec ifspec; +- int fcs_in; /* BR2684_FCSIN_* */ +- int fcs_out; /* BR2684_FCSOUT_* */ +- int fcs_auto; /* 1: fcs_{in,out} disabled if no FCS rx'ed */ +- int encaps; /* BR2684_ENCAPS_* */ +- int has_vpiid; /* 1: use vpn_id - Unsupported */ +- __u8 vpn_id[7]; +- int send_padding; /* unsupported */ +- int min_size; /* we will pad smaller packets than this */ ++ int fcs_in; /* BR2684_FCSIN_* */ ++ int fcs_out; /* BR2684_FCSOUT_* */ ++ int fcs_auto; /* 1: fcs_{in,out} disabled if no FCS rx'ed */ ++ int encaps; /* BR2684_ENCAPS_* */ ++ int has_vpiid; /* 1: use vpn_id - Unsupported */ ++ __u8 vpn_id[7]; ++ int send_padding; /* unsupported */ ++ int min_size; /* we will pad smaller packets than this */ + }; + + /* +@@ -86,8 +96,8 @@ + * efficient per-if in/out filters, this support will be removed + */ + struct br2684_filter { +- __be32 prefix; /* network byte order */ +- __be32 netmask; /* 0 = disable filter */ ++ __be32 prefix; /* network byte order */ ++ __be32 netmask; /* 0 = disable filter */ + }; + + struct br2684_filter_set { +@@ -95,7 +105,13 @@ + struct br2684_filter filter; + }; + ++enum br2684_payload { ++ p_routed = BR2684_PAYLOAD_ROUTED, ++ p_bridged = BR2684_PAYLOAD_BRIDGED, ++}; ++ + #define BR2684_SETFILT _IOW( 'a', ATMIOC_BACKEND + 0, \ + struct br2684_filter_set) + + #endif /* _LINUX_ATMBR2684_H */ ++ +diff -Nur linux-2.6.24.2/net/atm/br2684.c linux-2.6.24.2-copy/net/atm/br2684.c +--- linux-2.6.24.2/net/atm/br2684.c 2008-02-11 05:51:11.000000000 +0000 ++++ linux-2.6.24.2-copy/net/atm/br2684.c 2008-03-27 03:24:17.000000000 +0000 +@@ -1,8 +1,10 @@ + /* +-Experimental ethernet netdevice using ATM AAL5 as underlying carrier +-(RFC1483 obsoleted by RFC2684) for Linux 2.4 +-Author: Marcell GAL, 2000, XDSL Ltd, Hungary +-*/ ++ * Ethernet netdevice using ATM AAL5 as underlying carrier ++ * (RFC1483 obsoleted by RFC2684) for Linux ++ * ++ * Authors: Marcell GAL, 2000, XDSL Ltd, Hungary ++ * Eric Kinzie, 2006-2007, US Naval Research Laboratory ++ */ + + #include + #include +@@ -39,21 +41,35 @@ + #define skb_debug(skb) do {} while (0) + #endif + ++#define BR2684_ETHERTYPE_LEN 2 ++#define BR2684_PAD_LEN 2 ++ ++#define LLC 0xaa, 0xaa, 0x03 ++#define SNAP_BRIDGED 0x00, 0x80, 0xc2 ++#define SNAP_ROUTED 0x00, 0x00, 0x00 ++#define PID_ETHERNET 0x00, 0x07 ++#define ETHERTYPE_IPV4 0x08, 0x00 ++#define ETHERTYPE_IPV6 0x86, 0xdd ++#define PAD_BRIDGED 0x00, 0x00 ++ ++static unsigned char ethertype_ipv4[] = { ETHERTYPE_IPV4 }; ++static unsigned char ethertype_ipv6[] = { ETHERTYPE_IPV6 }; + static unsigned char llc_oui_pid_pad[] = +- { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 }; +-#define PADLEN (2) ++ { LLC, SNAP_BRIDGED, PID_ETHERNET, PAD_BRIDGED }; ++static unsigned char llc_oui_ipv4[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV4 }; ++static unsigned char llc_oui_ipv6[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV6 }; + + enum br2684_encaps { +- e_vc = BR2684_ENCAPS_VC, ++ e_vc = BR2684_ENCAPS_VC, + e_llc = BR2684_ENCAPS_LLC, + }; + + struct br2684_vcc { +- struct atm_vcc *atmvcc; ++ struct atm_vcc *atmvcc; + struct net_device *device; +- /* keep old push,pop functions for chaining */ +- void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); +- /* void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); */ ++ /* keep old push, pop functions for chaining */ ++ void (*old_push) (struct atm_vcc * vcc, struct sk_buff * skb); ++ /* void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); */ + enum br2684_encaps encaps; + struct list_head brvccs; + #ifdef CONFIG_ATM_BR2684_IPFILTER +@@ -66,9 +82,10 @@ + struct net_device *net_dev; + struct list_head br2684_devs; + int number; +- struct list_head brvccs; /* one device <=> one vcc (before xmas) */ ++ struct list_head brvccs; /* one device <=> one vcc (before xmas) */ + struct net_device_stats stats; + int mac_was_set; ++ enum br2684_payload payload; + }; + + /* +@@ -84,7 +101,7 @@ + + static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev) + { +- return (struct br2684_dev *) net_dev->priv; ++ return (struct br2684_dev *)net_dev->priv; + } + + static inline struct net_device *list_entry_brdev(const struct list_head *le) +@@ -94,7 +111,7 @@ + + static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc) + { +- return (struct br2684_vcc *) (atmvcc->user_back); ++ return (struct br2684_vcc *)(atmvcc->user_back); + } + + static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le) +@@ -132,10 +149,11 @@ + * otherwise false + */ + static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev, +- struct br2684_vcc *brvcc) ++ struct br2684_vcc *brvcc) + { + struct atm_vcc *atmvcc; + int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2; ++ + if (skb_headroom(skb) < minheadroom) { + struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom); + brvcc->copies_needed++; +@@ -146,23 +164,48 @@ + } + skb = skb2; + } +- skb_push(skb, minheadroom); +- if (brvcc->encaps == e_llc) +- skb_copy_to_linear_data(skb, llc_oui_pid_pad, 10); +- else +- memset(skb->data, 0, 2); ++ ++ if (brvcc->encaps == e_llc) { ++ if (brdev->payload == p_bridged) { ++ skb_push(skb, sizeof(llc_oui_pid_pad)); ++ skb_copy_to_linear_data(skb, llc_oui_pid_pad, ++ sizeof(llc_oui_pid_pad)); ++ } else if (brdev->payload == p_routed) { ++ unsigned short prot = ntohs(skb->protocol); ++ ++ skb_push(skb, sizeof(llc_oui_ipv4)); ++ switch (prot) { ++ case ETH_P_IP: ++ skb_copy_to_linear_data(skb, llc_oui_ipv4, ++ sizeof(llc_oui_ipv4)); ++ break; ++ case ETH_P_IPV6: ++ skb_copy_to_linear_data(skb, llc_oui_ipv6, ++ sizeof(llc_oui_ipv6)); ++ break; ++ default: ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ } ++ } else { ++ skb_push(skb, 2); ++ if (brdev->payload == p_bridged) ++ memset(skb->data, 0, 2); ++ } + skb_debug(skb); + + ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; + pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev); + if (!atm_may_send(atmvcc, skb->truesize)) { +- /* we free this here for now, because we cannot know in a higher +- layer whether the skb point it supplied wasn't freed yet. +- now, it always is. +- */ ++ /* ++ * We free this here for now, because we cannot know in a higher ++ * layer whether the skb pointer it supplied wasn't freed yet. ++ * Now, it always is. ++ */ + dev_kfree_skb(skb); + return 0; +- } ++ } + atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc); + ATM_SKB(skb)->atm_options = atmvcc->atm_options; + brdev->stats.tx_packets++; +@@ -172,10 +215,9 @@ + } + + static inline struct br2684_vcc *pick_outgoing_vcc(struct sk_buff *skb, +- struct br2684_dev *brdev) ++ struct br2684_dev *brdev) + { +- return list_empty(&brdev->brvccs) ? NULL : +- list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */ ++ return list_empty(&brdev->brvccs) ? NULL : list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */ + } + + static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) +@@ -199,11 +241,10 @@ + /* + * We should probably use netif_*_queue() here, but that + * involves added complication. We need to walk before +- * we can run ++ * we can run. ++ * ++ * Don't free here! this pointer might be no longer valid! + */ +- /* don't free here! this pointer might be no longer valid! +- dev_kfree_skb(skb); +- */ + brdev->stats.tx_errors++; + brdev->stats.tx_fifo_errors++; + } +@@ -217,12 +258,11 @@ + return &BRPRIV(dev)->stats; + } + +- + /* + * We remember when the MAC gets set, so we don't override it later with + * the ESI of the ATM card of the first VC + */ +-static int (*my_eth_mac_addr)(struct net_device *, void *); ++static int (*my_eth_mac_addr) (struct net_device *, void *); + static int br2684_mac_addr(struct net_device *dev, void *p) + { + int err = my_eth_mac_addr(dev, p); +@@ -233,7 +273,7 @@ + + #ifdef CONFIG_ATM_BR2684_IPFILTER + /* this IOCTL is experimental. */ +-static int br2684_setfilt(struct atm_vcc *atmvcc, void __user *arg) ++static int br2684_setfilt(struct atm_vcc *atmvcc, void __user * arg) + { + struct br2684_vcc *brvcc; + struct br2684_filter_set fs; +@@ -243,13 +283,12 @@ + if (fs.ifspec.method != BR2684_FIND_BYNOTHING) { + /* + * This is really a per-vcc thing, but we can also search +- * by device ++ * by device. + */ + struct br2684_dev *brdev; + read_lock(&devs_lock); + brdev = BRPRIV(br2684_find_dev(&fs.ifspec)); +- if (brdev == NULL || list_empty(&brdev->brvccs) || +- brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */ ++ if (brdev == NULL || list_empty(&brdev->brvccs) || brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */ + brvcc = NULL; + else + brvcc = list_entry_brvcc(brdev->brvccs.next); +@@ -267,15 +306,16 @@ + packet_fails_filter(__be16 type, struct br2684_vcc *brvcc, struct sk_buff *skb) + { + if (brvcc->filter.netmask == 0) +- return 0; /* no filter in place */ ++ return 0; /* no filter in place */ + if (type == htons(ETH_P_IP) && +- (((struct iphdr *) (skb->data))->daddr & brvcc->filter. ++ (((struct iphdr *)(skb->data))->daddr & brvcc->filter. + netmask) == brvcc->filter.prefix) + return 0; + if (type == htons(ETH_P_ARP)) + return 0; +- /* TODO: we should probably filter ARPs too.. don't want to have +- * them returning values that don't make sense, or is that ok? ++ /* ++ * TODO: we should probably filter ARPs too.. don't want to have ++ * them returning values that don't make sense, or is that ok? + */ + return 1; /* drop */ + } +@@ -299,7 +339,6 @@ + struct br2684_vcc *brvcc = BR2684_VCC(atmvcc); + struct net_device *net_dev = brvcc->device; + struct br2684_dev *brdev = BRPRIV(net_dev); +- int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN; + + pr_debug("br2684_push\n"); + +@@ -320,35 +359,58 @@ + atm_return(atmvcc, skb->truesize); + pr_debug("skb from brdev %p\n", brdev); + if (brvcc->encaps == e_llc) { +- /* let us waste some time for checking the encapsulation. +- Note, that only 7 char is checked so frames with a valid FCS +- are also accepted (but FCS is not checked of course) */ +- if (memcmp(skb->data, llc_oui_pid_pad, 7)) { ++ ++ if (skb->len > 7 && skb->data[7] == 0x01) ++ __skb_trim(skb, skb->len - 4); ++ ++ /* accept packets that have "ipv[46]" in the snap header */ ++ if ((skb->len >= (sizeof(llc_oui_ipv4))) ++ && ++ (memcmp ++ (skb->data, llc_oui_ipv4, ++ sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) { ++ if (memcmp ++ (skb->data + 6, ethertype_ipv6, ++ sizeof(ethertype_ipv6)) == 0) ++ skb->protocol = __constant_htons(ETH_P_IPV6); ++ else if (memcmp ++ (skb->data + 6, ethertype_ipv4, ++ sizeof(ethertype_ipv4)) == 0) ++ skb->protocol = __constant_htons(ETH_P_IP); ++ else { ++ brdev->stats.rx_errors++; ++ dev_kfree_skb(skb); ++ return; ++ } ++ skb_pull(skb, sizeof(llc_oui_ipv4)); ++ skb_reset_network_header(skb); ++ skb->pkt_type = PACKET_HOST; ++ /* ++ * Let us waste some time for checking the encapsulation. ++ * Note, that only 7 char is checked so frames with a valid FCS ++ * are also accepted (but FCS is not checked of course). ++ */ ++ } else if ((skb->len >= sizeof(llc_oui_pid_pad)) && ++ (memcmp(skb->data, llc_oui_pid_pad, 7) == 0)) { ++ skb_pull(skb, sizeof(llc_oui_pid_pad)); ++ skb->protocol = eth_type_trans(skb, net_dev); ++ } else { + brdev->stats.rx_errors++; + dev_kfree_skb(skb); + return; + } + +- /* Strip FCS if present */ +- if (skb->len > 7 && skb->data[7] == 0x01) +- __skb_trim(skb, skb->len - 4); + } else { +- plen = PADLEN + ETH_HLEN; /* pad, dstmac,srcmac, ethtype */ + /* first 2 chars should be 0 */ + if (*((u16 *) (skb->data)) != 0) { + brdev->stats.rx_errors++; + dev_kfree_skb(skb); + return; + } +- } +- if (skb->len < plen) { +- brdev->stats.rx_errors++; +- dev_kfree_skb(skb); /* dev_ not needed? */ +- return; ++ skb_pull(skb, BR2684_PAD_LEN + ETH_HLEN); /* pad, dstmac, srcmac, ethtype */ ++ skb->protocol = eth_type_trans(skb, net_dev); + } + +- skb_pull(skb, plen - ETH_HLEN); +- skb->protocol = eth_type_trans(skb, net_dev); + #ifdef CONFIG_ATM_BR2684_IPFILTER + if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb))) { + brdev->stats.rx_dropped++; +@@ -372,11 +434,12 @@ + netif_rx(skb); + } + +-static int br2684_regvcc(struct atm_vcc *atmvcc, void __user *arg) ++/* ++ * Assign a vcc to a dev ++ * Note: we do not have explicit unassign, but look at _push() ++ */ ++static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) + { +-/* assign a vcc to a dev +-Note: we do not have explicit unassign, but look at _push() +-*/ + int err; + struct br2684_vcc *brvcc; + struct sk_buff *skb; +@@ -395,7 +458,7 @@ + net_dev = br2684_find_dev(&be.ifspec); + if (net_dev == NULL) { + printk(KERN_ERR +- "br2684: tried to attach to non-existant device\n"); ++ "br2684: tried to attach to non-existant device\n"); + err = -ENXIO; + goto error; + } +@@ -411,13 +474,15 @@ + } + if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO || + be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps != +- BR2684_ENCAPS_VC && be.encaps != BR2684_ENCAPS_LLC) || +- be.min_size != 0) { ++ BR2684_ENCAPS_VC ++ && be.encaps != ++ BR2684_ENCAPS_LLC) ++ || be.min_size != 0) { + err = -EINVAL; + goto error; + } +- pr_debug("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, +- brvcc); ++ pr_debug("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, ++ be.encaps, brvcc); + if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) { + unsigned char *esi = atmvcc->dev->esi; + if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5]) +@@ -430,7 +495,7 @@ + brvcc->device = net_dev; + brvcc->atmvcc = atmvcc; + atmvcc->user_back = brvcc; +- brvcc->encaps = (enum br2684_encaps) be.encaps; ++ brvcc->encaps = (enum br2684_encaps)be.encaps; + brvcc->old_push = atmvcc->push; + barrier(); + atmvcc->push = br2684_push; +@@ -461,7 +526,7 @@ + } + __module_get(THIS_MODULE); + return 0; +- error: ++ error: + write_unlock_irq(&devs_lock); + kfree(brvcc); + return err; +@@ -482,25 +547,52 @@ + INIT_LIST_HEAD(&brdev->brvccs); + } + +-static int br2684_create(void __user *arg) ++static void br2684_setup_routed(struct net_device *netdev) ++{ ++ struct br2684_dev *brdev = BRPRIV(netdev); ++ brdev->net_dev = netdev; ++ ++ netdev->hard_header_len = 0; ++ my_eth_mac_addr = netdev->set_mac_address; ++ netdev->set_mac_address = br2684_mac_addr; ++ netdev->hard_start_xmit = br2684_start_xmit; ++ netdev->get_stats = br2684_get_stats; ++ netdev->addr_len = 0; ++ netdev->mtu = 1500; ++ netdev->type = ARPHRD_PPP; ++ netdev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; ++ netdev->tx_queue_len = 100; ++ INIT_LIST_HEAD(&brdev->brvccs); ++} ++ ++static int br2684_create(void __user * arg) + { + int err; + struct net_device *netdev; + struct br2684_dev *brdev; + struct atm_newif_br2684 ni; ++ enum br2684_payload payload; + + pr_debug("br2684_create\n"); + + if (copy_from_user(&ni, arg, sizeof ni)) { + return -EFAULT; + } ++ ++ if (ni.media & BR2684_FLAG_ROUTED) ++ payload = p_routed; ++ else ++ payload = p_bridged; ++ ni.media &= 0xffff; /* strip flags */ ++ + if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) { + return -EINVAL; + } + + netdev = alloc_netdev(sizeof(struct br2684_dev), + ni.ifname[0] ? ni.ifname : "nas%d", +- br2684_setup); ++ (payload == p_routed) ? ++ br2684_setup_routed : br2684_setup); + if (!netdev) + return -ENOMEM; + +@@ -516,6 +608,7 @@ + } + + write_lock_irq(&devs_lock); ++ brdev->payload = payload; + brdev->number = list_empty(&br2684_devs) ? 1 : + BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1; + list_add_tail(&brdev->br2684_devs, &br2684_devs); +@@ -528,16 +621,16 @@ + * -ENOIOCTLCMD for any unrecognized ioctl + */ + static int br2684_ioctl(struct socket *sock, unsigned int cmd, +- unsigned long arg) ++ unsigned long arg) + { + struct atm_vcc *atmvcc = ATM_SD(sock); + void __user *argp = (void __user *)arg; ++ atm_backend_t b; + + int err; +- switch(cmd) { ++ switch (cmd) { + case ATM_SETBACKEND: +- case ATM_NEWBACKENDIF: { +- atm_backend_t b; ++ case ATM_NEWBACKENDIF: + err = get_user(b, (atm_backend_t __user *) argp); + if (err) + return -EFAULT; +@@ -549,7 +642,6 @@ + return br2684_regvcc(atmvcc, argp); + else + return br2684_create(argp); +- } + #ifdef CONFIG_ATM_BR2684_IPFILTER + case BR2684_SETFILT: + if (atmvcc->push != br2684_push) +@@ -557,6 +649,7 @@ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + err = br2684_setfilt(atmvcc, argp); ++ + return err; + #endif /* CONFIG_ATM_BR2684_IPFILTER */ + } +@@ -564,24 +657,25 @@ + } + + static struct atm_ioctl br2684_ioctl_ops = { +- .owner = THIS_MODULE, +- .ioctl = br2684_ioctl, ++ .owner = THIS_MODULE, ++ .ioctl = br2684_ioctl, + }; + +- + #ifdef CONFIG_PROC_FS +-static void *br2684_seq_start(struct seq_file *seq, loff_t *pos) ++static void *br2684_seq_start(struct seq_file *seq, loff_t * pos) ++ __acquires(devs_lock) + { + read_lock(&devs_lock); + return seq_list_start(&br2684_devs, *pos); + } + +-static void *br2684_seq_next(struct seq_file *seq, void *v, loff_t *pos) ++static void *br2684_seq_next(struct seq_file *seq, void *v, loff_t * pos) + { + return seq_list_next(v, &br2684_devs, pos); + } + + static void br2684_seq_stop(struct seq_file *seq, void *v) ++ __releases(devs_lock) + { + read_unlock(&devs_lock); + } +@@ -589,7 +683,7 @@ + static int br2684_seq_show(struct seq_file *seq, void *v) + { + const struct br2684_dev *brdev = list_entry(v, struct br2684_dev, +- br2684_devs); ++ br2684_devs); + const struct net_device *net_dev = brdev->net_dev; + const struct br2684_vcc *brvcc; + DECLARE_MAC_BUF(mac); +@@ -601,21 +695,19 @@ + brdev->mac_was_set ? "set" : "auto"); + + list_for_each_entry(brvcc, &brdev->brvccs, brvccs) { +- seq_printf(seq, " vcc %d.%d.%d: encaps=%s" +- ", failed copies %u/%u" +- "\n", brvcc->atmvcc->dev->number, +- brvcc->atmvcc->vpi, brvcc->atmvcc->vci, +- (brvcc->encaps == e_llc) ? "LLC" : "VC" +- , brvcc->copies_failed +- , brvcc->copies_needed +- ); ++ seq_printf(seq, " vcc %d.%d.%d: encaps=%s payload=%s" ++ ", failed copies %u/%u" ++ "\n", brvcc->atmvcc->dev->number, ++ brvcc->atmvcc->vpi, brvcc->atmvcc->vci, ++ (brvcc->encaps == e_llc) ? "LLC" : "VC", ++ (brdev->payload == p_bridged) ? "bridged" : "routed", ++ brvcc->copies_failed, brvcc->copies_needed); + #ifdef CONFIG_ATM_BR2684_IPFILTER + #define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte] + #define bs(var) b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3) +- if (brvcc->filter.netmask != 0) +- seq_printf(seq, " filter=%d.%d.%d.%d/" +- "%d.%d.%d.%d\n", +- bs(prefix), bs(netmask)); ++ if (brvcc->filter.netmask != 0) ++ seq_printf(seq, " filter=%d.%d.%d.%d/" ++ "%d.%d.%d.%d\n", bs(prefix), bs(netmask)); + #undef bs + #undef b1 + #endif /* CONFIG_ATM_BR2684_IPFILTER */ +@@ -625,9 +717,9 @@ + + static const struct seq_operations br2684_seq_ops = { + .start = br2684_seq_start, +- .next = br2684_seq_next, +- .stop = br2684_seq_stop, +- .show = br2684_seq_show, ++ .next = br2684_seq_next, ++ .stop = br2684_seq_stop, ++ .show = br2684_seq_show, + }; + + static int br2684_proc_open(struct inode *inode, struct file *file) +@@ -636,26 +728,28 @@ + } + + static const struct file_operations br2684_proc_ops = { +- .owner = THIS_MODULE, +- .open = br2684_proc_open, +- .read = seq_read, +- .llseek = seq_lseek, ++ .owner = THIS_MODULE, ++ .open = br2684_proc_open, ++ .read = seq_read, ++ .llseek = seq_lseek, + .release = seq_release, + }; + + extern struct proc_dir_entry *atm_proc_root; /* from proc.c */ +-#endif ++#endif /* CONFIG_PROC_FS */ + + static int __init br2684_init(void) + { + #ifdef CONFIG_PROC_FS + struct proc_dir_entry *p; ++ + if ((p = create_proc_entry("br2684", 0, atm_proc_root)) == NULL) +- return -ENOMEM; +- p->proc_fops = &br2684_proc_ops; ++ return -ENOMEM; ++ p->proc_fops = &br2684_proc_ops; + #endif +- register_atm_ioctl(&br2684_ioctl_ops); +- return 0; ++ register_atm_ioctl(&br2684_ioctl_ops); ++ return 0; ++ + } + + static void __exit br2684_exit(void) +@@ -689,3 +783,4 @@ + MODULE_AUTHOR("Marcell GAL"); + MODULE_DESCRIPTION("RFC2684 bridged protocols over ATM/AAL5"); + MODULE_LICENSE("GPL"); ++