Index: linux-2.4.35.4/net/atm/br2684.c =================================================================== --- linux-2.4.35.4.orig/net/atm/br2684.c +++ linux-2.4.35.4/net/atm/br2684.c @@ -55,36 +55,55 @@ static void skb_debug(const struct sk_bu #define skb_debug(skb) do {} while (0) #endif +#define BR2684_LLC_LEN 3 +#define BR2684_SNAP_LEN 3 +#define BR2684_ETHERTYPE_LEN 2 +#define BR2684_PID_LEN 2 +#define BR2684_PAD_LEN 2 + +static unsigned char llc_common[] = { 0xaa, 0xaa, 0x03 }; +static unsigned char snap_bridged[] = { 0x00, 0x80, 0xc2 }; +static unsigned char snap_routed[] = { 0x00, 0x00, 0x00 }; +static unsigned char pid_ipv4[] = { 0x00, 0x07 }; +static unsigned char ethertype_ipv4[] = { 0x08, 0x00 }; +static unsigned char ethertype_ipv6[] = { 0x86, 0xdd }; +static unsigned char pad_bridged[] = { 0x00, 0x00 }; + static unsigned char llc_oui_pid_pad[] = { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 }; +static unsigned char llc_oui_ipv6[] = + { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x86, 0xdd }; +static unsigned char llc_oui_ipv4[] = + { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00 }; #define PADLEN (2) 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 br2684_dev *brdev; /* keep old push,pop functions for chaining */ - void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); + 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; + enum br2684_payload payload; struct list_head brvccs; #ifdef CONFIG_ATM_BR2684_IPFILTER struct br2684_filter filter; -#endif /* CONFIG_ATM_BR2684_IPFILTER */ +#endif /* CONFIG_ATM_BR2684_IPFILTER */ #ifndef FASTER_VERSION unsigned copies_needed, copies_failed; -#endif /* FASTER_VERSION */ +#endif /* FASTER_VERSION */ }; struct br2684_dev { 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; }; @@ -173,24 +192,84 @@ static int br2684_xmit_vcc(struct sk_buf } skb = skb2; } - skb_push(skb, minheadroom); - if (brvcc->encaps == e_llc) - memcpy(skb->data, llc_oui_pid_pad, 10); - else - memset(skb->data, 0, 2); -#endif /* FASTER_VERSION */ + + /* This skb_push is a problem: routed packets need less headroom than + * bridged packets. + */ + +/* skb_push(skb, minheadroom); */ + if (brvcc->encaps == e_llc) { + int offset = 0; + int actual_headroom; + + actual_headroom = + BR2684_LLC_LEN + + BR2684_SNAP_LEN + + ((brvcc->payload == p_bridged) ? + (BR2684_PID_LEN + BR2684_PAD_LEN) : + BR2684_ETHERTYPE_LEN); + + skb_push(skb, actual_headroom); + memcpy(skb->data, llc_common, BR2684_LLC_LEN); + offset += BR2684_LLC_LEN; + + if (brvcc->payload == p_bridged) { + memcpy(skb->data + offset, snap_bridged, + BR2684_SNAP_LEN); + offset += BR2684_SNAP_LEN; + /* pid_ipv4 is poorly named. should probably be + * pid_ethernet + */ + memcpy(skb->data + offset, pid_ipv4, + BR2684_PID_LEN); + offset += BR2684_PID_LEN; + memcpy(skb->data + offset, pad_bridged, + BR2684_PAD_LEN); + offset += BR2684_PAD_LEN; + } else if (brvcc->payload == p_routed) { + unsigned short prot = + __constant_ntohs(skb->protocol); + memcpy(skb->data + offset, snap_routed, + BR2684_SNAP_LEN); + offset += BR2684_SNAP_LEN; + + switch (prot) { + case ETH_P_IP: + memcpy(skb->data + offset, + ethertype_ipv4, + BR2684_ETHERTYPE_LEN); + break; + case ETH_P_IPV6: + memcpy(skb->data + offset, + ethertype_ipv6, + BR2684_ETHERTYPE_LEN); + break; + default: + dev_kfree_skb(skb); + return 0; + } + offset += BR2684_ETHERTYPE_LEN; + + } + } else { + skb_push(skb, 2); + if (brvcc->payload == p_bridged) + memset(skb->data, 0, 2); + } +#endif /* FASTER_VERSION */ skb_debug(skb); ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; - DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev); + DPRINTK("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. - */ + layer whether the skb point it supplied wasn't freed yet. + now, it always is. + */ dev_kfree_skb(skb); return 0; - } + } atomic_add(skb->truesize, &atmvcc->sk->wmem_alloc); ATM_SKB(skb)->atm_options = atmvcc->atm_options; brdev->stats.tx_packets++; @@ -428,18 +507,39 @@ static void br2684_push(struct atm_vcc * atm_return(atmvcc, skb->truesize); DPRINTK("skb from brdev %p\n", brdev); if (brvcc->encaps == e_llc) { + /* accept packets that have "ipv[46]" in the snap header */ + /* 8 - 2 == sizeof(llc_oui_ipv6) - BR2684_ETHERTYPE_LEN */ + if (memcmp(skb->data, llc_oui_ipv6, 8 - 2) == 0) { + plen = sizeof(llc_oui_ipv6); + + if (memcmp(skb->data + 6, ethertype_ipv6, 2) == 0) + skb->protocol = + __constant_htons(ETH_P_IPV6); + else if (memcmp(skb->data + 6, ethertype_ipv4, 2) + == 0) + skb->protocol = __constant_htons(ETH_P_IP); + else { + brdev->stats.rx_errors++; + dev_kfree_skb(skb); + return; + } + skb_pull(skb, plen); + skb->nh.raw = skb->data; + 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) */ - if (memcmp(skb->data, llc_oui_pid_pad, 7)) { + else if (memcmp(skb->data, llc_oui_pid_pad, 7) == 0) { + skb_pull(skb, plen - ETH_HLEN); + skb->protocol = + eth_type_trans(skb, &brdev->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 */ @@ -448,13 +548,14 @@ static void br2684_push(struct atm_vcc * dev_kfree_skb(skb); return; } + skb_pull(skb, plen - ETH_HLEN); + skb->protocol = eth_type_trans(skb, &brdev->net_dev); } if (skb->len < plen) { brdev->stats.rx_errors++; dev_kfree_skb(skb); /* dev_ not needed? */ return; } - #ifdef FASTER_VERSION /* FIXME: tcpdump shows that pointer to mac header is 2 bytes earlier, than should be. What else should I set? */ @@ -465,30 +566,29 @@ static void br2684_push(struct atm_vcc * skb->protocol = ((u16 *) skb->data)[-1]; #else /* some protocols might require this: */ skb->protocol = br_type_trans(skb, &brdev->net_dev); -#endif /* CONFIG_BR2684_FAST_TRANS */ +#endif /* CONFIG_BR2684_FAST_TRANS */ #else - skb_pull(skb, plen - ETH_HLEN); - skb->protocol = eth_type_trans(skb, &brdev->net_dev); -#endif /* FASTER_VERSION */ + /* skb_pull(skb, plen - ETH_HLEN); */ + /* skb->protocol = eth_type_trans(skb, &brdev->net_dev); */ +#endif /* FASTER_VERSION */ #ifdef CONFIG_ATM_BR2684_IPFILTER if (packet_fails_filter(skb->protocol, brvcc, skb)) { brdev->stats.rx_dropped++; dev_kfree_skb(skb); return; } -#endif /* CONFIG_ATM_BR2684_IPFILTER */ +#endif /* CONFIG_ATM_BR2684_IPFILTER */ skb->dev = &brdev->net_dev; - ATM_SKB(skb)->vcc = atmvcc; /* needed ? */ + /* ATM_SKB(skb)->vcc = atmvcc; *//* needed ? */ DPRINTK("received packet's protocol: %x\n", ntohs(skb->protocol)); skb_debug(skb); - if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */ + if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */ brdev->stats.rx_dropped++; dev_kfree_skb(skb); return; } brdev->stats.rx_packets++; brdev->stats.rx_bytes += skb->len; - memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(skb); } @@ -525,10 +625,10 @@ Note: we do not have explicit unassign, err = -EEXIST; goto error; } - 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) { + 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) { err = -EINVAL; goto error; } @@ -554,18 +654,21 @@ Note: we do not have explicit unassign, brvcc->atmvcc = atmvcc; atmvcc->user_back = brvcc; brvcc->encaps = (enum br2684_encaps) be.encaps; + brvcc->payload = (enum br2684_payload) be.payload; brvcc->old_push = atmvcc->push; barrier(); atmvcc->push = br2684_push; skb_queue_head_init(©); skb_migrate(&atmvcc->sk->receive_queue, ©); while ((skb = skb_dequeue(©))) { +#ifdef notdef BRPRIV(skb->dev)->stats.rx_bytes -= skb->len; BRPRIV(skb->dev)->stats.rx_packets--; +#endif br2684_push(atmvcc, skb); } return 0; - error: + error: write_unlock_irq(&devs_lock); MOD_DEC_USE_COUNT; return err; @@ -608,12 +711,25 @@ static int br2684_create(unsigned long a if (ni.ifname[0] != '\0') { memcpy(brdev->net_dev.name, ni.ifname, - sizeof(brdev->net_dev.name)); - brdev->net_dev.name[sizeof(brdev->net_dev.name) - 1] = '\0'; + sizeof(brdev->net_dev.name)); + brdev->net_dev.name[sizeof(brdev->net_dev.name) - 1] = + '\0'; } else sprintf(brdev->net_dev.name, "nas%d", brdev->number); DPRINTK("registered netdev %s\n", brdev->net_dev.name); - ether_setup(&brdev->net_dev); + if (ni.payload == p_routed) { + brdev->net_dev.hard_header_len = 0; + brdev->net_dev.addr_len = 0; + brdev->net_dev.mtu = 1500; + + /* Type PPP seems most suitable */ + brdev->net_dev.type = ARPHRD_PPP; + brdev->net_dev.flags = + IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; + brdev->net_dev.tx_queue_len = 100; + } else { + ether_setup(&brdev->net_dev); + } brdev->mac_was_set = 0; #ifdef FASTER_VERSION my_eth_header = brdev->net_dev.hard_header; @@ -677,12 +793,11 @@ static int br2684_ioctl(struct atm_vcc * err = br2684_setfilt(atmvcc, arg); MOD_DEC_USE_COUNT; return err; -#endif /* CONFIG_ATM_BR2684_IPFILTER */ +#endif /* CONFIG_ATM_BR2684_IPFILTER */ } return -ENOIOCTLCMD; } -#ifdef CONFIG_PROC_FS /* Never put more than 256 bytes in at once */ static int br2684_proc_engine(loff_t pos, char *buf) { @@ -692,52 +807,62 @@ static int br2684_proc_engine(loff_t pos list_for_each(lhd, &br2684_devs) { brdev = list_entry_brdev(lhd); if (pos-- == 0) - return sprintf(buf, "dev %.16s: num=%d, mac=%02X:%02X:" - "%02X:%02X:%02X:%02X (%s)\n", brdev->net_dev.name, - brdev->number, - brdev->net_dev.dev_addr[0], - brdev->net_dev.dev_addr[1], - brdev->net_dev.dev_addr[2], - brdev->net_dev.dev_addr[3], - brdev->net_dev.dev_addr[4], - brdev->net_dev.dev_addr[5], - brdev->mac_was_set ? "set" : "auto"); + return sprintf(buf, + "dev %.16s: num=%d, mac=%02X:%02X:" + "%02X:%02X:%02X:%02X (%s)\n", + brdev->net_dev.name, brdev->number, + brdev->net_dev.dev_addr[0], + brdev->net_dev.dev_addr[1], + brdev->net_dev.dev_addr[2], + brdev->net_dev.dev_addr[3], + brdev->net_dev.dev_addr[4], + brdev->net_dev.dev_addr[5], + brdev-> + mac_was_set ? "set" : "auto"); list_for_each(lhc, &brdev->brvccs) { brvcc = list_entry_brvcc(lhc); if (pos-- == 0) - return sprintf(buf, " vcc %d.%d.%d: encaps=%s" + return sprintf(buf, + " vcc %d.%d.%d: encaps=%s" + ", payload=%s" #ifndef FASTER_VERSION - ", failed copies %u/%u" -#endif /* FASTER_VERSION */ - "\n", brvcc->atmvcc->dev->number, - brvcc->atmvcc->vpi, brvcc->atmvcc->vci, - (brvcc->encaps == e_llc) ? "LLC" : "VC" + ", failed copies %u/%u" +#endif /* FASTER_VERSION */ + "\n", + brvcc->atmvcc->dev->number, + brvcc->atmvcc->vpi, + brvcc->atmvcc->vci, + (brvcc->encaps == + e_llc) ? "LLC" : "VC", + (brvcc->payload == + p_bridged) ? "bridged" : + "routed" #ifndef FASTER_VERSION - , brvcc->copies_failed - , brvcc->copies_needed -#endif /* FASTER_VERSION */ + , brvcc->copies_failed, + brvcc->copies_needed +#endif /* FASTER_VERSION */ ); #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 && pos-- == 0) - return sprintf(buf, " filter=%d.%d.%d.%d/" - "%d.%d.%d.%d\n", bs(prefix), bs(netmask)); + return sprintf(buf, + " filter=%d.%d.%d.%d/" + "%d.%d.%d.%d\n", bs(prefix), + bs(netmask)); #undef bs #undef b1 -#endif /* CONFIG_ATM_BR2684_IPFILTER */ +#endif /* CONFIG_ATM_BR2684_IPFILTER */ } } return 0; } static ssize_t br2684_proc_read(struct file *file, char *buf, size_t count, - loff_t *pos) + loff_t * pos) { unsigned long page; int len = 0, x, left; - loff_t n = *pos; - page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; @@ -746,7 +871,7 @@ static ssize_t br2684_proc_read(struct f left = count; read_lock(&devs_lock); for (;;) { - x = br2684_proc_engine(n, &((char *) page)[len]); + x = br2684_proc_engine(*pos, &((char *) page)[len]); if (x == 0) break; if (x > left) @@ -761,12 +886,11 @@ static ssize_t br2684_proc_read(struct f } len += x; left -= x; - n++; + (*pos)++; if (left < 256) break; } read_unlock(&devs_lock); - *pos = n; if (len > 0 && copy_to_user(buf, (char *) page, len)) len = -EFAULT; free_page(page); @@ -774,23 +898,20 @@ static ssize_t br2684_proc_read(struct f } static struct file_operations br2684_proc_operations = { - read: br2684_proc_read, + read:br2684_proc_read, }; extern struct proc_dir_entry *atm_proc_root; /* from proc.c */ -#endif /* CONFIG_PROC_FS */ /* the following avoids some spurious warnings from the compiler */ #define UNUSED __attribute__((unused)) static int __init UNUSED 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_operations; -#endif /* CONFIG_PROC_FS */ br2684_ioctl_set(br2684_ioctl); return 0; } @@ -799,9 +920,7 @@ static void __exit UNUSED br2684_exit(vo { struct br2684_dev *brdev; br2684_ioctl_set(NULL); -#ifdef CONFIG_PROC_FS remove_proc_entry("br2684", atm_proc_root); -#endif /* CONFIG_PROC_FS */ while (!list_empty(&br2684_devs)) { brdev = list_entry_brdev(br2684_devs.next); unregister_netdev(&brdev->net_dev); Index: linux-2.4.35.4/net/atm/common.c =================================================================== --- linux-2.4.35.4.orig/net/atm/common.c +++ linux-2.4.35.4/net/atm/common.c @@ -158,6 +158,7 @@ void br2684_ioctl_set(int (*hook)(struct } #ifdef CONFIG_ATM_BR2684_MODULE EXPORT_SYMBOL(br2684_ioctl_set); +EXPORT_SYMBOL(br2684_ioctl_hook); #endif #endif Index: linux-2.4.35.4/include/linux/atmbr2684.h =================================================================== --- linux-2.4.35.4.orig/include/linux/atmbr2684.h +++ linux-2.4.35.4/include/linux/atmbr2684.h @@ -3,6 +3,7 @@ #include <linux/atm.h> #include <linux/if.h> /* For IFNAMSIZ */ +#include <linux/if_ether.h> /* ETH_P_* */ /* * Type of media we're bridging (ethernet, token ring, etc) Currently only @@ -36,15 +37,24 @@ #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_* */ + char ifname[IFNAMSIZ]; + int mtu; + int payload; /* bridged or routed */ }; /* @@ -68,16 +78,17 @@ struct br2684_if_spec { * 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 payload; /* BR2684_PAYLOAD_* */ + 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 */ }; /* @@ -95,7 +106,12 @@ struct br2684_filter_set { 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 */ +#endif /* _LINUX_ATMBR2684_H */