[ATM]: [br2864] routed support
Signed-off-by: Chas Williams <chas@cmf.nrl.navy.mil> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
900092a45e
commit
097b19a998
|
@ -14,6 +14,9 @@
|
||||||
#define BR2684_MEDIA_FDDI (3)
|
#define BR2684_MEDIA_FDDI (3)
|
||||||
#define BR2684_MEDIA_802_6 (4) /* 802.6 */
|
#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.
|
* Is there FCS inbound on this VC? This currently isn't supported.
|
||||||
*/
|
*/
|
||||||
|
@ -35,6 +38,14 @@
|
||||||
#define BR2684_ENCAPS_LLC (1)
|
#define BR2684_ENCAPS_LLC (1)
|
||||||
#define BR2684_ENCAPS_AUTODETECT (2) /* Unsuported */
|
#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:
|
* 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
|
* the first element of the structure is the backend number and the rest
|
||||||
|
@ -42,7 +53,7 @@
|
||||||
*/
|
*/
|
||||||
struct atm_newif_br2684 {
|
struct atm_newif_br2684 {
|
||||||
atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */
|
atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */
|
||||||
int media; /* BR2684_MEDIA_* */
|
int media; /* BR2684_MEDIA_*, flags in upper bits */
|
||||||
char ifname[IFNAMSIZ];
|
char ifname[IFNAMSIZ];
|
||||||
int mtu;
|
int mtu;
|
||||||
};
|
};
|
||||||
|
@ -95,6 +106,11 @@ struct br2684_filter_set {
|
||||||
struct br2684_filter filter;
|
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, \
|
#define BR2684_SETFILT _IOW( 'a', ATMIOC_BACKEND + 0, \
|
||||||
struct br2684_filter_set)
|
struct br2684_filter_set)
|
||||||
|
|
||||||
|
|
148
net/atm/br2684.c
148
net/atm/br2684.c
|
@ -1,7 +1,8 @@
|
||||||
/*
|
/*
|
||||||
Experimental ethernet netdevice using ATM AAL5 as underlying carrier
|
Ethernet netdevice using ATM AAL5 as underlying carrier
|
||||||
(RFC1483 obsoleted by RFC2684) for Linux 2.4
|
(RFC1483 obsoleted by RFC2684) for Linux
|
||||||
Author: Marcell GAL, 2000, XDSL Ltd, Hungary
|
Authors: Marcell GAL, 2000, XDSL Ltd, Hungary
|
||||||
|
Eric Kinzie, 2006-2007, US Naval Research Laboratory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
@ -39,9 +40,27 @@ static void skb_debug(const struct sk_buff *skb)
|
||||||
#define skb_debug(skb) do {} while (0)
|
#define skb_debug(skb) do {} while (0)
|
||||||
#endif
|
#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[] =
|
static unsigned char llc_oui_pid_pad[] =
|
||||||
{ 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 };
|
{ LLC, SNAP_BRIDGED, PID_ETHERNET, PAD_BRIDGED };
|
||||||
#define PADLEN (2)
|
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 {
|
enum br2684_encaps {
|
||||||
e_vc = BR2684_ENCAPS_VC,
|
e_vc = BR2684_ENCAPS_VC,
|
||||||
|
@ -69,6 +88,7 @@ struct br2684_dev {
|
||||||
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;
|
struct net_device_stats stats;
|
||||||
int mac_was_set;
|
int mac_was_set;
|
||||||
|
enum br2684_payload payload;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -136,6 +156,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
|
||||||
{
|
{
|
||||||
struct atm_vcc *atmvcc;
|
struct atm_vcc *atmvcc;
|
||||||
int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2;
|
int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2;
|
||||||
|
|
||||||
if (skb_headroom(skb) < minheadroom) {
|
if (skb_headroom(skb) < minheadroom) {
|
||||||
struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom);
|
struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom);
|
||||||
brvcc->copies_needed++;
|
brvcc->copies_needed++;
|
||||||
|
@ -146,11 +167,32 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
|
||||||
}
|
}
|
||||||
skb = skb2;
|
skb = skb2;
|
||||||
}
|
}
|
||||||
skb_push(skb, minheadroom);
|
|
||||||
if (brvcc->encaps == e_llc)
|
if (brvcc->encaps == e_llc) {
|
||||||
skb_copy_to_linear_data(skb, llc_oui_pid_pad, 10);
|
if (brdev->payload == p_bridged) {
|
||||||
else
|
skb_push(skb, sizeof(llc_oui_pid_pad));
|
||||||
memset(skb->data, 0, 2);
|
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);
|
skb_debug(skb);
|
||||||
|
|
||||||
ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
|
ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
|
||||||
|
@ -299,7 +341,6 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
|
||||||
struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);
|
struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);
|
||||||
struct net_device *net_dev = brvcc->device;
|
struct net_device *net_dev = brvcc->device;
|
||||||
struct br2684_dev *brdev = BRPRIV(net_dev);
|
struct br2684_dev *brdev = BRPRIV(net_dev);
|
||||||
int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN;
|
|
||||||
|
|
||||||
pr_debug("br2684_push\n");
|
pr_debug("br2684_push\n");
|
||||||
|
|
||||||
|
@ -320,35 +361,50 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
|
||||||
atm_return(atmvcc, skb->truesize);
|
atm_return(atmvcc, skb->truesize);
|
||||||
pr_debug("skb from brdev %p\n", brdev);
|
pr_debug("skb from brdev %p\n", brdev);
|
||||||
if (brvcc->encaps == e_llc) {
|
if (brvcc->encaps == e_llc) {
|
||||||
|
|
||||||
|
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.
|
/* let us waste some time for checking the encapsulation.
|
||||||
Note, that only 7 char is checked so frames with a valid FCS
|
Note, that only 7 char is checked so frames with a valid FCS
|
||||||
are also accepted (but FCS is not checked of course) */
|
are also accepted (but FCS is not checked of course) */
|
||||||
if (memcmp(skb->data, llc_oui_pid_pad, 7)) {
|
} 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++;
|
brdev->stats.rx_errors++;
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Strip FCS if present */
|
|
||||||
if (skb->len > 7 && skb->data[7] == 0x01)
|
|
||||||
__skb_trim(skb, skb->len - 4);
|
|
||||||
} else {
|
} else {
|
||||||
plen = PADLEN + ETH_HLEN; /* pad, dstmac,srcmac, ethtype */
|
|
||||||
/* first 2 chars should be 0 */
|
/* first 2 chars should be 0 */
|
||||||
if (*((u16 *) (skb->data)) != 0) {
|
if (*((u16 *) (skb->data)) != 0) {
|
||||||
brdev->stats.rx_errors++;
|
brdev->stats.rx_errors++;
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
skb_pull(skb, BR2684_PAD_LEN + ETH_HLEN); /* pad, dstmac, srcmac, ethtype */
|
||||||
if (skb->len < plen) {
|
skb->protocol = eth_type_trans(skb, net_dev);
|
||||||
brdev->stats.rx_errors++;
|
|
||||||
dev_kfree_skb(skb); /* dev_ not needed? */
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
skb_pull(skb, plen - ETH_HLEN);
|
|
||||||
skb->protocol = eth_type_trans(skb, net_dev);
|
|
||||||
#ifdef CONFIG_ATM_BR2684_IPFILTER
|
#ifdef CONFIG_ATM_BR2684_IPFILTER
|
||||||
if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb))) {
|
if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb))) {
|
||||||
brdev->stats.rx_dropped++;
|
brdev->stats.rx_dropped++;
|
||||||
|
@ -482,25 +538,52 @@ static void br2684_setup(struct net_device *netdev)
|
||||||
INIT_LIST_HEAD(&brdev->brvccs);
|
INIT_LIST_HEAD(&brdev->brvccs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
static int br2684_create(void __user *arg)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
struct br2684_dev *brdev;
|
struct br2684_dev *brdev;
|
||||||
struct atm_newif_br2684 ni;
|
struct atm_newif_br2684 ni;
|
||||||
|
enum br2684_payload payload;
|
||||||
|
|
||||||
pr_debug("br2684_create\n");
|
pr_debug("br2684_create\n");
|
||||||
|
|
||||||
if (copy_from_user(&ni, arg, sizeof ni)) {
|
if (copy_from_user(&ni, arg, sizeof ni)) {
|
||||||
return -EFAULT;
|
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) {
|
if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
netdev = alloc_netdev(sizeof(struct br2684_dev),
|
netdev = alloc_netdev(sizeof(struct br2684_dev),
|
||||||
ni.ifname[0] ? ni.ifname : "nas%d",
|
ni.ifname[0] ? ni.ifname : "nas%d",
|
||||||
br2684_setup);
|
(payload == p_routed) ?
|
||||||
|
br2684_setup_routed : br2684_setup);
|
||||||
if (!netdev)
|
if (!netdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -516,6 +599,7 @@ static int br2684_create(void __user *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
write_lock_irq(&devs_lock);
|
write_lock_irq(&devs_lock);
|
||||||
|
brdev->payload = payload;
|
||||||
brdev->number = list_empty(&br2684_devs) ? 1 :
|
brdev->number = list_empty(&br2684_devs) ? 1 :
|
||||||
BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
|
BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
|
||||||
list_add_tail(&brdev->br2684_devs, &br2684_devs);
|
list_add_tail(&brdev->br2684_devs, &br2684_devs);
|
||||||
|
@ -601,14 +685,14 @@ static int br2684_seq_show(struct seq_file *seq, void *v)
|
||||||
brdev->mac_was_set ? "set" : "auto");
|
brdev->mac_was_set ? "set" : "auto");
|
||||||
|
|
||||||
list_for_each_entry(brvcc, &brdev->brvccs, brvccs) {
|
list_for_each_entry(brvcc, &brdev->brvccs, brvccs) {
|
||||||
seq_printf(seq, " vcc %d.%d.%d: encaps=%s"
|
seq_printf(seq, " vcc %d.%d.%d: encaps=%s payload=%s"
|
||||||
", failed copies %u/%u"
|
", failed copies %u/%u"
|
||||||
"\n", brvcc->atmvcc->dev->number,
|
"\n", brvcc->atmvcc->dev->number,
|
||||||
brvcc->atmvcc->vpi, brvcc->atmvcc->vci,
|
brvcc->atmvcc->vpi, brvcc->atmvcc->vci,
|
||||||
(brvcc->encaps == e_llc) ? "LLC" : "VC"
|
(brvcc->encaps == e_llc) ? "LLC" : "VC",
|
||||||
, brvcc->copies_failed
|
(brdev->payload == p_bridged) ? "bridged" : "routed",
|
||||||
, brvcc->copies_needed
|
brvcc->copies_failed,
|
||||||
);
|
brvcc->copies_needed);
|
||||||
#ifdef CONFIG_ATM_BR2684_IPFILTER
|
#ifdef CONFIG_ATM_BR2684_IPFILTER
|
||||||
#define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte]
|
#define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte]
|
||||||
#define bs(var) b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3)
|
#define bs(var) b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3)
|
||||||
|
|
Loading…
Reference in a new issue