提交 eb2a2fd9 编写于 作者: K Krzysztof Halasa 提交者: Jeff Garzik

[PATCH] Modularize generic HDLC

This patch enables building of individual WAN protocol support
routines (parts of generic HDLC) as separate modules.
All protocol-private definitions are moved from hdlc.h file
to protocol drivers. User-space interface and interface
between generic HDLC and underlying low-level HDLC drivers
are unchanged.
Signed-off-by: NKrzysztof Halasa <khc@pm.waw.pl>
Signed-off-by: NJeff Garzik <jeff@garzik.org>
上级 c226951b
...@@ -154,7 +154,7 @@ config HDLC ...@@ -154,7 +154,7 @@ config HDLC
If unsure, say N. If unsure, say N.
config HDLC_RAW config HDLC_RAW
bool "Raw HDLC support" tristate "Raw HDLC support"
depends on HDLC depends on HDLC
help help
Generic HDLC driver supporting raw HDLC over WAN connections. Generic HDLC driver supporting raw HDLC over WAN connections.
...@@ -162,7 +162,7 @@ config HDLC_RAW ...@@ -162,7 +162,7 @@ config HDLC_RAW
If unsure, say N. If unsure, say N.
config HDLC_RAW_ETH config HDLC_RAW_ETH
bool "Raw HDLC Ethernet device support" tristate "Raw HDLC Ethernet device support"
depends on HDLC depends on HDLC
help help
Generic HDLC driver supporting raw HDLC Ethernet device emulation Generic HDLC driver supporting raw HDLC Ethernet device emulation
...@@ -173,7 +173,7 @@ config HDLC_RAW_ETH ...@@ -173,7 +173,7 @@ config HDLC_RAW_ETH
If unsure, say N. If unsure, say N.
config HDLC_CISCO config HDLC_CISCO
bool "Cisco HDLC support" tristate "Cisco HDLC support"
depends on HDLC depends on HDLC
help help
Generic HDLC driver supporting Cisco HDLC over WAN connections. Generic HDLC driver supporting Cisco HDLC over WAN connections.
...@@ -181,7 +181,7 @@ config HDLC_CISCO ...@@ -181,7 +181,7 @@ config HDLC_CISCO
If unsure, say N. If unsure, say N.
config HDLC_FR config HDLC_FR
bool "Frame Relay support" tristate "Frame Relay support"
depends on HDLC depends on HDLC
help help
Generic HDLC driver supporting Frame Relay over WAN connections. Generic HDLC driver supporting Frame Relay over WAN connections.
...@@ -189,7 +189,7 @@ config HDLC_FR ...@@ -189,7 +189,7 @@ config HDLC_FR
If unsure, say N. If unsure, say N.
config HDLC_PPP config HDLC_PPP
bool "Synchronous Point-to-Point Protocol (PPP) support" tristate "Synchronous Point-to-Point Protocol (PPP) support"
depends on HDLC depends on HDLC
help help
Generic HDLC driver supporting PPP over WAN connections. Generic HDLC driver supporting PPP over WAN connections.
...@@ -197,7 +197,7 @@ config HDLC_PPP ...@@ -197,7 +197,7 @@ config HDLC_PPP
If unsure, say N. If unsure, say N.
config HDLC_X25 config HDLC_X25
bool "X.25 protocol support" tristate "X.25 protocol support"
depends on HDLC && (LAPB=m && HDLC=m || LAPB=y) depends on HDLC && (LAPB=m && HDLC=m || LAPB=y)
help help
Generic HDLC driver supporting X.25 over WAN connections. Generic HDLC driver supporting X.25 over WAN connections.
......
...@@ -9,14 +9,13 @@ cyclomx-y := cycx_main.o ...@@ -9,14 +9,13 @@ cyclomx-y := cycx_main.o
cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o
cyclomx-objs := $(cyclomx-y) cyclomx-objs := $(cyclomx-y)
hdlc-y := hdlc_generic.o obj-$(CONFIG_HDLC) += hdlc.o
hdlc-$(CONFIG_HDLC_RAW) += hdlc_raw.o obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o
hdlc-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
hdlc-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
hdlc-$(CONFIG_HDLC_FR) += hdlc_fr.o obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
hdlc-$(CONFIG_HDLC_PPP) += hdlc_ppp.o obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o
hdlc-$(CONFIG_HDLC_X25) += hdlc_x25.o obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
hdlc-objs := $(hdlc-y)
pc300-y := pc300_drv.o pc300-y := pc300_drv.o
pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
...@@ -38,10 +37,6 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o ...@@ -38,10 +37,6 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o
obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_LAPBETHER) += lapbether.o
obj-$(CONFIG_SBNI) += sbni.o obj-$(CONFIG_SBNI) += sbni.o
obj-$(CONFIG_PC300) += pc300.o obj-$(CONFIG_PC300) += pc300.o
obj-$(CONFIG_HDLC) += hdlc.o
ifeq ($(CONFIG_HDLC_PPP),y)
obj-$(CONFIG_HDLC) += syncppp.o
endif
obj-$(CONFIG_N2) += n2.o obj-$(CONFIG_N2) += n2.o
obj-$(CONFIG_C101) += c101.o obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o obj-$(CONFIG_WANXL) += wanxl.o
......
/* /*
* Generic HDLC support routines for Linux * Generic HDLC support routines for Linux
* *
* Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl> * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License * under the terms of version 2 of the GNU General Public License
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
* Use sethdlc utility to set line parameters, protocol and PVCs * Use sethdlc utility to set line parameters, protocol and PVCs
* *
* How does it work: * How does it work:
* - proto.open(), close(), start(), stop() calls are serialized. * - proto->open(), close(), start(), stop() calls are serialized.
* The order is: open, [ start, stop ... ] close ... * The order is: open, [ start, stop ... ] close ...
* - proto.start() and stop() are called with spin_lock_irq held. * - proto->start() and stop() are called with spin_lock_irq held.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -38,10 +38,12 @@ ...@@ -38,10 +38,12 @@
#include <linux/hdlc.h> #include <linux/hdlc.h>
static const char* version = "HDLC support module revision 1.19"; static const char* version = "HDLC support module revision 1.20";
#undef DEBUG_LINK #undef DEBUG_LINK
static struct hdlc_proto *first_proto = NULL;
static int hdlc_change_mtu(struct net_device *dev, int new_mtu) static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
{ {
...@@ -63,11 +65,11 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev) ...@@ -63,11 +65,11 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *p, struct net_device *orig_dev) struct packet_type *p, struct net_device *orig_dev)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); struct hdlc_device_desc *desc = dev_to_desc(dev);
if (hdlc->proto.netif_rx) if (desc->netif_rx)
return hdlc->proto.netif_rx(skb); return desc->netif_rx(skb);
hdlc->stats.rx_dropped++; /* Shouldn't happen */ desc->stats.rx_dropped++; /* Shouldn't happen */
dev_kfree_skb(skb); dev_kfree_skb(skb);
return NET_RX_DROP; return NET_RX_DROP;
} }
...@@ -77,8 +79,8 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -77,8 +79,8 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
static inline void hdlc_proto_start(struct net_device *dev) static inline void hdlc_proto_start(struct net_device *dev)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->proto.start) if (hdlc->proto->start)
return hdlc->proto.start(dev); return hdlc->proto->start(dev);
} }
...@@ -86,8 +88,8 @@ static inline void hdlc_proto_start(struct net_device *dev) ...@@ -86,8 +88,8 @@ static inline void hdlc_proto_start(struct net_device *dev)
static inline void hdlc_proto_stop(struct net_device *dev) static inline void hdlc_proto_stop(struct net_device *dev)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->proto.stop) if (hdlc->proto->stop)
return hdlc->proto.stop(dev); return hdlc->proto->stop(dev);
} }
...@@ -144,15 +146,15 @@ int hdlc_open(struct net_device *dev) ...@@ -144,15 +146,15 @@ int hdlc_open(struct net_device *dev)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
#ifdef DEBUG_LINK #ifdef DEBUG_LINK
printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n", printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name,
hdlc->carrier, hdlc->open); hdlc->carrier, hdlc->open);
#endif #endif
if (hdlc->proto.id == -1) if (hdlc->proto == NULL)
return -ENOSYS; /* no protocol attached */ return -ENOSYS; /* no protocol attached */
if (hdlc->proto.open) { if (hdlc->proto->open) {
int result = hdlc->proto.open(dev); int result = hdlc->proto->open(dev);
if (result) if (result)
return result; return result;
} }
...@@ -178,7 +180,7 @@ void hdlc_close(struct net_device *dev) ...@@ -178,7 +180,7 @@ void hdlc_close(struct net_device *dev)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
#ifdef DEBUG_LINK #ifdef DEBUG_LINK
printk(KERN_DEBUG "hdlc_close() carrier %i open %i\n", printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name,
hdlc->carrier, hdlc->open); hdlc->carrier, hdlc->open);
#endif #endif
...@@ -190,68 +192,34 @@ void hdlc_close(struct net_device *dev) ...@@ -190,68 +192,34 @@ void hdlc_close(struct net_device *dev)
spin_unlock_irq(&hdlc->state_lock); spin_unlock_irq(&hdlc->state_lock);
if (hdlc->proto.close) if (hdlc->proto->close)
hdlc->proto.close(dev); hdlc->proto->close(dev);
} }
#ifndef CONFIG_HDLC_RAW
#define hdlc_raw_ioctl(dev, ifr) -ENOSYS
#endif
#ifndef CONFIG_HDLC_RAW_ETH
#define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS
#endif
#ifndef CONFIG_HDLC_PPP
#define hdlc_ppp_ioctl(dev, ifr) -ENOSYS
#endif
#ifndef CONFIG_HDLC_CISCO
#define hdlc_cisco_ioctl(dev, ifr) -ENOSYS
#endif
#ifndef CONFIG_HDLC_FR
#define hdlc_fr_ioctl(dev, ifr) -ENOSYS
#endif
#ifndef CONFIG_HDLC_X25
#define hdlc_x25_ioctl(dev, ifr) -ENOSYS
#endif
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); struct hdlc_proto *proto = first_proto;
unsigned int proto; int result;
if (cmd != SIOCWANDEV) if (cmd != SIOCWANDEV)
return -EINVAL; return -EINVAL;
switch(ifr->ifr_settings.type) { if (dev_to_hdlc(dev)->proto) {
case IF_PROTO_HDLC: result = dev_to_hdlc(dev)->proto->ioctl(dev, ifr);
case IF_PROTO_HDLC_ETH: if (result != -EINVAL)
case IF_PROTO_PPP: return result;
case IF_PROTO_CISCO:
case IF_PROTO_FR:
case IF_PROTO_X25:
proto = ifr->ifr_settings.type;
break;
default:
proto = hdlc->proto.id;
} }
switch(proto) { /* Not handled by currently attached protocol (if any) */
case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr);
case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr); while (proto) {
case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr); if ((result = proto->ioctl(dev, ifr)) != -EINVAL)
case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr); return result;
case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr); proto = proto->next;
case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr);
default: return -EINVAL;
} }
return -EINVAL;
} }
void hdlc_setup(struct net_device *dev) void hdlc_setup(struct net_device *dev)
...@@ -267,8 +235,6 @@ void hdlc_setup(struct net_device *dev) ...@@ -267,8 +235,6 @@ void hdlc_setup(struct net_device *dev)
dev->flags = IFF_POINTOPOINT | IFF_NOARP; dev->flags = IFF_POINTOPOINT | IFF_NOARP;
hdlc->proto.id = -1;
hdlc->proto.detach = NULL;
hdlc->carrier = 1; hdlc->carrier = 1;
hdlc->open = 0; hdlc->open = 0;
spin_lock_init(&hdlc->state_lock); spin_lock_init(&hdlc->state_lock);
...@@ -277,7 +243,8 @@ void hdlc_setup(struct net_device *dev) ...@@ -277,7 +243,8 @@ void hdlc_setup(struct net_device *dev)
struct net_device *alloc_hdlcdev(void *priv) struct net_device *alloc_hdlcdev(void *priv)
{ {
struct net_device *dev; struct net_device *dev;
dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup); dev = alloc_netdev(sizeof(struct hdlc_device_desc) +
sizeof(hdlc_device), "hdlc%d", hdlc_setup);
if (dev) if (dev)
dev_to_hdlc(dev)->priv = priv; dev_to_hdlc(dev)->priv = priv;
return dev; return dev;
...@@ -286,13 +253,71 @@ struct net_device *alloc_hdlcdev(void *priv) ...@@ -286,13 +253,71 @@ struct net_device *alloc_hdlcdev(void *priv)
void unregister_hdlc_device(struct net_device *dev) void unregister_hdlc_device(struct net_device *dev)
{ {
rtnl_lock(); rtnl_lock();
hdlc_proto_detach(dev_to_hdlc(dev));
unregister_netdevice(dev); unregister_netdevice(dev);
detach_hdlc_protocol(dev);
rtnl_unlock(); rtnl_unlock();
} }
int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
int (*rx)(struct sk_buff *skb), size_t size)
{
detach_hdlc_protocol(dev);
if (!try_module_get(proto->module))
return -ENOSYS;
if (size)
if ((dev_to_hdlc(dev)->state = kmalloc(size,
GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "Memory squeeze on"
" hdlc_proto_attach()\n");
module_put(proto->module);
return -ENOBUFS;
}
dev_to_hdlc(dev)->proto = proto;
dev_to_desc(dev)->netif_rx = rx;
return 0;
}
void detach_hdlc_protocol(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->proto) {
if (hdlc->proto->detach)
hdlc->proto->detach(dev);
module_put(hdlc->proto->module);
hdlc->proto = NULL;
}
kfree(hdlc->state);
hdlc->state = NULL;
}
void register_hdlc_protocol(struct hdlc_proto *proto)
{
proto->next = first_proto;
first_proto = proto;
}
void unregister_hdlc_protocol(struct hdlc_proto *proto)
{
struct hdlc_proto **p = &first_proto;
while (*p) {
if (*p == proto) {
*p = proto->next;
return;
}
p = &((*p)->next);
}
}
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("HDLC support module"); MODULE_DESCRIPTION("HDLC support module");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -303,6 +328,10 @@ EXPORT_SYMBOL(hdlc_ioctl); ...@@ -303,6 +328,10 @@ EXPORT_SYMBOL(hdlc_ioctl);
EXPORT_SYMBOL(hdlc_setup); EXPORT_SYMBOL(hdlc_setup);
EXPORT_SYMBOL(alloc_hdlcdev); EXPORT_SYMBOL(alloc_hdlcdev);
EXPORT_SYMBOL(unregister_hdlc_device); EXPORT_SYMBOL(unregister_hdlc_device);
EXPORT_SYMBOL(register_hdlc_protocol);
EXPORT_SYMBOL(unregister_hdlc_protocol);
EXPORT_SYMBOL(attach_hdlc_protocol);
EXPORT_SYMBOL(detach_hdlc_protocol);
static struct packet_type hdlc_packet_type = { static struct packet_type hdlc_packet_type = {
.type = __constant_htons(ETH_P_HDLC), .type = __constant_htons(ETH_P_HDLC),
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux * Generic HDLC support routines for Linux
* Cisco HDLC support * Cisco HDLC support
* *
* Copyright (C) 2000 - 2003 Krzysztof Halasa <khc@pm.waw.pl> * Copyright (C) 2000 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License * under the terms of version 2 of the GNU General Public License
...@@ -34,17 +34,56 @@ ...@@ -34,17 +34,56 @@
#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ #define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
struct hdlc_header {
u8 address;
u8 control;
u16 protocol;
}__attribute__ ((packed));
struct cisco_packet {
u32 type; /* code */
u32 par1;
u32 par2;
u16 rel; /* reliability */
u32 time;
}__attribute__ ((packed));
#define CISCO_PACKET_LEN 18
#define CISCO_BIG_PACKET_LEN 20
struct cisco_state {
cisco_proto settings;
struct timer_list timer;
unsigned long last_poll;
int up;
int request_sent;
u32 txseq; /* TX sequence number */
u32 rxseq; /* RX sequence number */
};
static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
static inline struct cisco_state * state(hdlc_device *hdlc)
{
return(struct cisco_state *)(hdlc->state);
}
static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
u16 type, void *daddr, void *saddr, u16 type, void *daddr, void *saddr,
unsigned int len) unsigned int len)
{ {
hdlc_header *data; struct hdlc_header *data;
#ifdef DEBUG_HARD_HEADER #ifdef DEBUG_HARD_HEADER
printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
#endif #endif
skb_push(skb, sizeof(hdlc_header)); skb_push(skb, sizeof(struct hdlc_header));
data = (hdlc_header*)skb->data; data = (struct hdlc_header*)skb->data;
if (type == CISCO_KEEPALIVE) if (type == CISCO_KEEPALIVE)
data->address = CISCO_MULTICAST; data->address = CISCO_MULTICAST;
else else
...@@ -52,7 +91,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, ...@@ -52,7 +91,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
data->control = 0; data->control = 0;
data->protocol = htons(type); data->protocol = htons(type);
return sizeof(hdlc_header); return sizeof(struct hdlc_header);
} }
...@@ -61,9 +100,10 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, ...@@ -61,9 +100,10 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
u32 par1, u32 par2) u32 par1, u32 par2)
{ {
struct sk_buff *skb; struct sk_buff *skb;
cisco_packet *data; struct cisco_packet *data;
skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet)); skb = dev_alloc_skb(sizeof(struct hdlc_header) +
sizeof(struct cisco_packet));
if (!skb) { if (!skb) {
printk(KERN_WARNING printk(KERN_WARNING
"%s: Memory squeeze on cisco_keepalive_send()\n", "%s: Memory squeeze on cisco_keepalive_send()\n",
...@@ -72,7 +112,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, ...@@ -72,7 +112,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
} }
skb_reserve(skb, 4); skb_reserve(skb, 4);
cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0);
data = (cisco_packet*)(skb->data + 4); data = (struct cisco_packet*)(skb->data + 4);
data->type = htonl(type); data->type = htonl(type);
data->par1 = htonl(par1); data->par1 = htonl(par1);
...@@ -81,7 +121,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, ...@@ -81,7 +121,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
/* we will need do_div here if 1000 % HZ != 0 */ /* we will need do_div here if 1000 % HZ != 0 */
data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ)); data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
skb_put(skb, sizeof(cisco_packet)); skb_put(skb, sizeof(struct cisco_packet));
skb->priority = TC_PRIO_CONTROL; skb->priority = TC_PRIO_CONTROL;
skb->dev = dev; skb->dev = dev;
skb->nh.raw = skb->data; skb->nh.raw = skb->data;
...@@ -93,9 +133,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, ...@@ -93,9 +133,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev) static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
{ {
hdlc_header *data = (hdlc_header*)skb->data; struct hdlc_header *data = (struct hdlc_header*)skb->data;
if (skb->len < sizeof(hdlc_header)) if (skb->len < sizeof(struct hdlc_header))
return __constant_htons(ETH_P_HDLC); return __constant_htons(ETH_P_HDLC);
if (data->address != CISCO_MULTICAST && if (data->address != CISCO_MULTICAST &&
...@@ -106,7 +146,7 @@ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev) ...@@ -106,7 +146,7 @@ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
case __constant_htons(ETH_P_IP): case __constant_htons(ETH_P_IP):
case __constant_htons(ETH_P_IPX): case __constant_htons(ETH_P_IPX):
case __constant_htons(ETH_P_IPV6): case __constant_htons(ETH_P_IPV6):
skb_pull(skb, sizeof(hdlc_header)); skb_pull(skb, sizeof(struct hdlc_header));
return data->protocol; return data->protocol;
default: default:
return __constant_htons(ETH_P_HDLC); return __constant_htons(ETH_P_HDLC);
...@@ -118,12 +158,12 @@ static int cisco_rx(struct sk_buff *skb) ...@@ -118,12 +158,12 @@ static int cisco_rx(struct sk_buff *skb)
{ {
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
hdlc_header *data = (hdlc_header*)skb->data; struct hdlc_header *data = (struct hdlc_header*)skb->data;
cisco_packet *cisco_data; struct cisco_packet *cisco_data;
struct in_device *in_dev; struct in_device *in_dev;
u32 addr, mask; u32 addr, mask;
if (skb->len < sizeof(hdlc_header)) if (skb->len < sizeof(struct hdlc_header))
goto rx_error; goto rx_error;
if (data->address != CISCO_MULTICAST && if (data->address != CISCO_MULTICAST &&
...@@ -137,15 +177,17 @@ static int cisco_rx(struct sk_buff *skb) ...@@ -137,15 +177,17 @@ static int cisco_rx(struct sk_buff *skb)
return NET_RX_SUCCESS; return NET_RX_SUCCESS;
case CISCO_KEEPALIVE: case CISCO_KEEPALIVE:
if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN && if ((skb->len != sizeof(struct hdlc_header) +
skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) { CISCO_PACKET_LEN) &&
printk(KERN_INFO "%s: Invalid length of Cisco " (skb->len != sizeof(struct hdlc_header) +
"control packet (%d bytes)\n", CISCO_BIG_PACKET_LEN)) {
dev->name, skb->len); printk(KERN_INFO "%s: Invalid length of Cisco control"
" packet (%d bytes)\n", dev->name, skb->len);
goto rx_error; goto rx_error;
} }
cisco_data = (cisco_packet*)(skb->data + sizeof(hdlc_header)); cisco_data = (struct cisco_packet*)(skb->data + sizeof
(struct hdlc_header));
switch(ntohl (cisco_data->type)) { switch(ntohl (cisco_data->type)) {
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
...@@ -178,11 +220,11 @@ static int cisco_rx(struct sk_buff *skb) ...@@ -178,11 +220,11 @@ static int cisco_rx(struct sk_buff *skb)
goto rx_error; goto rx_error;
case CISCO_KEEPALIVE_REQ: case CISCO_KEEPALIVE_REQ:
hdlc->state.cisco.rxseq = ntohl(cisco_data->par1); state(hdlc)->rxseq = ntohl(cisco_data->par1);
if (hdlc->state.cisco.request_sent && if (state(hdlc)->request_sent &&
ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) { ntohl(cisco_data->par2) == state(hdlc)->txseq) {
hdlc->state.cisco.last_poll = jiffies; state(hdlc)->last_poll = jiffies;
if (!hdlc->state.cisco.up) { if (!state(hdlc)->up) {
u32 sec, min, hrs, days; u32 sec, min, hrs, days;
sec = ntohl(cisco_data->time) / 1000; sec = ntohl(cisco_data->time) / 1000;
min = sec / 60; sec -= min * 60; min = sec / 60; sec -= min * 60;
...@@ -193,7 +235,7 @@ static int cisco_rx(struct sk_buff *skb) ...@@ -193,7 +235,7 @@ static int cisco_rx(struct sk_buff *skb)
dev->name, days, hrs, dev->name, days, hrs,
min, sec); min, sec);
netif_dormant_off(dev); netif_dormant_off(dev);
hdlc->state.cisco.up = 1; state(hdlc)->up = 1;
} }
} }
...@@ -208,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb) ...@@ -208,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb)
return NET_RX_DROP; return NET_RX_DROP;
rx_error: rx_error:
hdlc->stats.rx_errors++; /* Mark error */ dev_to_desc(dev)->stats.rx_errors++; /* Mark error */
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return NET_RX_DROP; return NET_RX_DROP;
} }
...@@ -220,23 +262,22 @@ static void cisco_timer(unsigned long arg) ...@@ -220,23 +262,22 @@ static void cisco_timer(unsigned long arg)
struct net_device *dev = (struct net_device *)arg; struct net_device *dev = (struct net_device *)arg;
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
if (hdlc->state.cisco.up && if (state(hdlc)->up &&
time_after(jiffies, hdlc->state.cisco.last_poll + time_after(jiffies, state(hdlc)->last_poll +
hdlc->state.cisco.settings.timeout * HZ)) { state(hdlc)->settings.timeout * HZ)) {
hdlc->state.cisco.up = 0; state(hdlc)->up = 0;
printk(KERN_INFO "%s: Link down\n", dev->name); printk(KERN_INFO "%s: Link down\n", dev->name);
netif_dormant_on(dev); netif_dormant_on(dev);
} }
cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq,
++hdlc->state.cisco.txseq, state(hdlc)->rxseq);
hdlc->state.cisco.rxseq); state(hdlc)->request_sent = 1;
hdlc->state.cisco.request_sent = 1; state(hdlc)->timer.expires = jiffies +
hdlc->state.cisco.timer.expires = jiffies + state(hdlc)->settings.interval * HZ;
hdlc->state.cisco.settings.interval * HZ; state(hdlc)->timer.function = cisco_timer;
hdlc->state.cisco.timer.function = cisco_timer; state(hdlc)->timer.data = arg;
hdlc->state.cisco.timer.data = arg; add_timer(&state(hdlc)->timer);
add_timer(&hdlc->state.cisco.timer);
} }
...@@ -244,15 +285,15 @@ static void cisco_timer(unsigned long arg) ...@@ -244,15 +285,15 @@ static void cisco_timer(unsigned long arg)
static void cisco_start(struct net_device *dev) static void cisco_start(struct net_device *dev)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
hdlc->state.cisco.up = 0; state(hdlc)->up = 0;
hdlc->state.cisco.request_sent = 0; state(hdlc)->request_sent = 0;
hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0; state(hdlc)->txseq = state(hdlc)->rxseq = 0;
init_timer(&hdlc->state.cisco.timer); init_timer(&state(hdlc)->timer);
hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/ state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/
hdlc->state.cisco.timer.function = cisco_timer; state(hdlc)->timer.function = cisco_timer;
hdlc->state.cisco.timer.data = (unsigned long)dev; state(hdlc)->timer.data = (unsigned long)dev;
add_timer(&hdlc->state.cisco.timer); add_timer(&state(hdlc)->timer);
} }
...@@ -260,15 +301,24 @@ static void cisco_start(struct net_device *dev) ...@@ -260,15 +301,24 @@ static void cisco_start(struct net_device *dev)
static void cisco_stop(struct net_device *dev) static void cisco_stop(struct net_device *dev)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
del_timer_sync(&hdlc->state.cisco.timer); del_timer_sync(&state(hdlc)->timer);
netif_dormant_on(dev); netif_dormant_on(dev);
hdlc->state.cisco.up = 0; state(hdlc)->up = 0;
hdlc->state.cisco.request_sent = 0; state(hdlc)->request_sent = 0;
} }
int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) static struct hdlc_proto proto = {
.start = cisco_start,
.stop = cisco_stop,
.type_trans = cisco_type_trans,
.ioctl = cisco_ioctl,
.module = THIS_MODULE,
};
static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
{ {
cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco; cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco;
const size_t size = sizeof(cisco_proto); const size_t size = sizeof(cisco_proto);
...@@ -278,12 +328,14 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -278,12 +328,14 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) { switch (ifr->ifr_settings.type) {
case IF_GET_PROTO: case IF_GET_PROTO:
if (dev_to_hdlc(dev)->proto != &proto)
return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_CISCO; ifr->ifr_settings.type = IF_PROTO_CISCO;
if (ifr->ifr_settings.size < size) { if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */ ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS; return -ENOBUFS;
} }
if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size)) if (copy_to_user(cisco_s, &state(hdlc)->settings, size))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -302,19 +354,15 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -302,19 +354,15 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL; return -EINVAL;
result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
if (result) if (result)
return result; return result;
hdlc_proto_detach(hdlc); result = attach_hdlc_protocol(dev, &proto, cisco_rx,
memcpy(&hdlc->state.cisco.settings, &new_settings, size); sizeof(struct cisco_state));
memset(&hdlc->proto, 0, sizeof(hdlc->proto)); if (result)
return result;
hdlc->proto.start = cisco_start; memcpy(&state(hdlc)->settings, &new_settings, size);
hdlc->proto.stop = cisco_stop;
hdlc->proto.netif_rx = cisco_rx;
hdlc->proto.type_trans = cisco_type_trans;
hdlc->proto.id = IF_PROTO_CISCO;
dev->hard_start_xmit = hdlc->xmit; dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = cisco_hard_header; dev->hard_header = cisco_hard_header;
dev->hard_header_cache = NULL; dev->hard_header_cache = NULL;
...@@ -327,3 +375,25 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -327,3 +375,25 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL; return -EINVAL;
} }
static int __init mod_init(void)
{
register_hdlc_protocol(&proto);
return 0;
}
static void __exit mod_exit(void)
{
unregister_hdlc_protocol(&proto);
}
module_init(mod_init);
module_exit(mod_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("Cisco HDLC protocol support for generic HDLC");
MODULE_LICENSE("GPL v2");
此差异已折叠。
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux * Generic HDLC support routines for Linux
* Point-to-point protocol support * Point-to-point protocol support
* *
* Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl> * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License * under the terms of version 2 of the GNU General Public License
...@@ -22,6 +22,21 @@ ...@@ -22,6 +22,21 @@
#include <linux/lapb.h> #include <linux/lapb.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/hdlc.h> #include <linux/hdlc.h>
#include <net/syncppp.h>
struct ppp_state {
struct ppp_device pppdev;
struct ppp_device *syncppp_ptr;
int (*old_change_mtu)(struct net_device *dev, int new_mtu);
};
static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
static inline struct ppp_state* state(hdlc_device *hdlc)
{
return(struct ppp_state *)(hdlc->state);
}
static int ppp_open(struct net_device *dev) static int ppp_open(struct net_device *dev)
...@@ -30,16 +45,16 @@ static int ppp_open(struct net_device *dev) ...@@ -30,16 +45,16 @@ static int ppp_open(struct net_device *dev)
void *old_ioctl; void *old_ioctl;
int result; int result;
dev->priv = &hdlc->state.ppp.syncppp_ptr; dev->priv = &state(hdlc)->syncppp_ptr;
hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev; state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev;
hdlc->state.ppp.pppdev.dev = dev; state(hdlc)->pppdev.dev = dev;
old_ioctl = dev->do_ioctl; old_ioctl = dev->do_ioctl;
hdlc->state.ppp.old_change_mtu = dev->change_mtu; state(hdlc)->old_change_mtu = dev->change_mtu;
sppp_attach(&hdlc->state.ppp.pppdev); sppp_attach(&state(hdlc)->pppdev);
/* sppp_attach nukes them. We don't need syncppp's ioctl */ /* sppp_attach nukes them. We don't need syncppp's ioctl */
dev->do_ioctl = old_ioctl; dev->do_ioctl = old_ioctl;
hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO; state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO;
dev->type = ARPHRD_PPP; dev->type = ARPHRD_PPP;
result = sppp_open(dev); result = sppp_open(dev);
if (result) { if (result) {
...@@ -59,7 +74,7 @@ static void ppp_close(struct net_device *dev) ...@@ -59,7 +74,7 @@ static void ppp_close(struct net_device *dev)
sppp_close(dev); sppp_close(dev);
sppp_detach(dev); sppp_detach(dev);
dev->rebuild_header = NULL; dev->rebuild_header = NULL;
dev->change_mtu = hdlc->state.ppp.old_change_mtu; dev->change_mtu = state(hdlc)->old_change_mtu;
dev->mtu = HDLC_MAX_MTU; dev->mtu = HDLC_MAX_MTU;
dev->hard_header_len = 16; dev->hard_header_len = 16;
} }
...@@ -73,13 +88,24 @@ static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev) ...@@ -73,13 +88,24 @@ static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) static struct hdlc_proto proto = {
.open = ppp_open,
.close = ppp_close,
.type_trans = ppp_type_trans,
.ioctl = ppp_ioctl,
.module = THIS_MODULE,
};
static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
int result; int result;
switch (ifr->ifr_settings.type) { switch (ifr->ifr_settings.type) {
case IF_GET_PROTO: case IF_GET_PROTO:
if (dev_to_hdlc(dev)->proto != &proto)
return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_PPP; ifr->ifr_settings.type = IF_PROTO_PPP;
return 0; /* return protocol only, no settable parameters */ return 0; /* return protocol only, no settable parameters */
...@@ -96,13 +122,10 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -96,13 +122,10 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result) if (result)
return result; return result;
hdlc_proto_detach(hdlc); result = attach_hdlc_protocol(dev, &proto, NULL,
memset(&hdlc->proto, 0, sizeof(hdlc->proto)); sizeof(struct ppp_state));
if (result)
hdlc->proto.open = ppp_open; return result;
hdlc->proto.close = ppp_close;
hdlc->proto.type_trans = ppp_type_trans;
hdlc->proto.id = IF_PROTO_PPP;
dev->hard_start_xmit = hdlc->xmit; dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL; dev->hard_header = NULL;
dev->type = ARPHRD_PPP; dev->type = ARPHRD_PPP;
...@@ -113,3 +136,25 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -113,3 +136,25 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL; return -EINVAL;
} }
static int __init mod_init(void)
{
register_hdlc_protocol(&proto);
return 0;
}
static void __exit mod_exit(void)
{
unregister_hdlc_protocol(&proto);
}
module_init(mod_init);
module_exit(mod_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("PPP protocol support for generic HDLC");
MODULE_LICENSE("GPL v2");
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux * Generic HDLC support routines for Linux
* HDLC support * HDLC support
* *
* Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl> * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License * under the terms of version 2 of the GNU General Public License
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include <linux/hdlc.h> #include <linux/hdlc.h>
static int raw_ioctl(struct net_device *dev, struct ifreq *ifr);
static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev) static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
{ {
return __constant_htons(ETH_P_IP); return __constant_htons(ETH_P_IP);
...@@ -31,7 +33,14 @@ static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev) ...@@ -31,7 +33,14 @@ static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) static struct hdlc_proto proto = {
.type_trans = raw_type_trans,
.ioctl = raw_ioctl,
.module = THIS_MODULE,
};
static int raw_ioctl(struct net_device *dev, struct ifreq *ifr)
{ {
raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
const size_t size = sizeof(raw_hdlc_proto); const size_t size = sizeof(raw_hdlc_proto);
...@@ -41,12 +50,14 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -41,12 +50,14 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) { switch (ifr->ifr_settings.type) {
case IF_GET_PROTO: case IF_GET_PROTO:
if (dev_to_hdlc(dev)->proto != &proto)
return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_HDLC; ifr->ifr_settings.type = IF_PROTO_HDLC;
if (ifr->ifr_settings.size < size) { if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */ ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS; return -ENOBUFS;
} }
if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size)) if (copy_to_user(raw_s, hdlc->state, size))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -71,12 +82,11 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -71,12 +82,11 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result) if (result)
return result; return result;
hdlc_proto_detach(hdlc); result = attach_hdlc_protocol(dev, &proto, NULL,
memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); sizeof(raw_hdlc_proto));
memset(&hdlc->proto, 0, sizeof(hdlc->proto)); if (result)
return result;
hdlc->proto.type_trans = raw_type_trans; memcpy(hdlc->state, &new_settings, size);
hdlc->proto.id = IF_PROTO_HDLC;
dev->hard_start_xmit = hdlc->xmit; dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL; dev->hard_header = NULL;
dev->type = ARPHRD_RAWHDLC; dev->type = ARPHRD_RAWHDLC;
...@@ -88,3 +98,25 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -88,3 +98,25 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL; return -EINVAL;
} }
static int __init mod_init(void)
{
register_hdlc_protocol(&proto);
return 0;
}
static void __exit mod_exit(void)
{
unregister_hdlc_protocol(&proto);
}
module_init(mod_init);
module_exit(mod_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("Raw HDLC protocol support for generic HDLC");
MODULE_LICENSE("GPL v2");
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux * Generic HDLC support routines for Linux
* HDLC Ethernet emulation support * HDLC Ethernet emulation support
* *
* Copyright (C) 2002-2003 Krzysztof Halasa <khc@pm.waw.pl> * Copyright (C) 2002-2006 Krzysztof Halasa <khc@pm.waw.pl>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License * under the terms of version 2 of the GNU General Public License
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/hdlc.h> #include <linux/hdlc.h>
static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr);
static int eth_tx(struct sk_buff *skb, struct net_device *dev) static int eth_tx(struct sk_buff *skb, struct net_device *dev)
{ {
...@@ -44,7 +45,14 @@ static int eth_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -44,7 +45,14 @@ static int eth_tx(struct sk_buff *skb, struct net_device *dev)
} }
int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) static struct hdlc_proto proto = {
.type_trans = eth_type_trans,
.ioctl = raw_eth_ioctl,
.module = THIS_MODULE,
};
static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
{ {
raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc; raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
const size_t size = sizeof(raw_hdlc_proto); const size_t size = sizeof(raw_hdlc_proto);
...@@ -56,12 +64,14 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -56,12 +64,14 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) { switch (ifr->ifr_settings.type) {
case IF_GET_PROTO: case IF_GET_PROTO:
if (dev_to_hdlc(dev)->proto != &proto)
return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_HDLC_ETH; ifr->ifr_settings.type = IF_PROTO_HDLC_ETH;
if (ifr->ifr_settings.size < size) { if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */ ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS; return -ENOBUFS;
} }
if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size)) if (copy_to_user(raw_s, hdlc->state, size))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -86,12 +96,11 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -86,12 +96,11 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result) if (result)
return result; return result;
hdlc_proto_detach(hdlc); result = attach_hdlc_protocol(dev, &proto, NULL,
memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); sizeof(raw_hdlc_proto));
memset(&hdlc->proto, 0, sizeof(hdlc->proto)); if (result)
return result;
hdlc->proto.type_trans = eth_type_trans; memcpy(hdlc->state, &new_settings, size);
hdlc->proto.id = IF_PROTO_HDLC_ETH;
dev->hard_start_xmit = eth_tx; dev->hard_start_xmit = eth_tx;
old_ch_mtu = dev->change_mtu; old_ch_mtu = dev->change_mtu;
old_qlen = dev->tx_queue_len; old_qlen = dev->tx_queue_len;
...@@ -106,3 +115,25 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -106,3 +115,25 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL; return -EINVAL;
} }
static int __init mod_init(void)
{
register_hdlc_protocol(&proto);
return 0;
}
static void __exit mod_exit(void)
{
unregister_hdlc_protocol(&proto);
}
module_init(mod_init);
module_exit(mod_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC");
MODULE_LICENSE("GPL v2");
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux * Generic HDLC support routines for Linux
* X.25 support * X.25 support
* *
* Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl> * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License * under the terms of version 2 of the GNU General Public License
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <net/x25device.h> #include <net/x25device.h>
static int x25_ioctl(struct net_device *dev, struct ifreq *ifr);
/* These functions are callbacks called by LAPB layer */ /* These functions are callbacks called by LAPB layer */
static void x25_connect_disconnect(struct net_device *dev, int reason, int code) static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
...@@ -162,30 +164,39 @@ static void x25_close(struct net_device *dev) ...@@ -162,30 +164,39 @@ static void x25_close(struct net_device *dev)
static int x25_rx(struct sk_buff *skb) static int x25_rx(struct sk_buff *skb)
{ {
hdlc_device *hdlc = dev_to_hdlc(skb->dev); struct hdlc_device_desc *desc = dev_to_desc(skb->dev);
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
hdlc->stats.rx_dropped++; desc->stats.rx_dropped++;
return NET_RX_DROP; return NET_RX_DROP;
} }
if (lapb_data_received(skb->dev, skb) == LAPB_OK) if (lapb_data_received(skb->dev, skb) == LAPB_OK)
return NET_RX_SUCCESS; return NET_RX_SUCCESS;
hdlc->stats.rx_errors++; desc->stats.rx_errors++;
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return NET_RX_DROP; return NET_RX_DROP;
} }
static struct hdlc_proto proto = {
.open = x25_open,
.close = x25_close,
.ioctl = x25_ioctl,
.module = THIS_MODULE,
};
int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
{ {
hdlc_device *hdlc = dev_to_hdlc(dev); hdlc_device *hdlc = dev_to_hdlc(dev);
int result; int result;
switch (ifr->ifr_settings.type) { switch (ifr->ifr_settings.type) {
case IF_GET_PROTO: case IF_GET_PROTO:
if (dev_to_hdlc(dev)->proto != &proto)
return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_X25; ifr->ifr_settings.type = IF_PROTO_X25;
return 0; /* return protocol only, no settable parameters */ return 0; /* return protocol only, no settable parameters */
...@@ -200,14 +211,9 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -200,14 +211,9 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result) if (result)
return result; return result;
hdlc_proto_detach(hdlc); if ((result = attach_hdlc_protocol(dev, &proto,
memset(&hdlc->proto, 0, sizeof(hdlc->proto)); x25_rx, 0)) != 0)
return result;
hdlc->proto.open = x25_open;
hdlc->proto.close = x25_close;
hdlc->proto.netif_rx = x25_rx;
hdlc->proto.type_trans = NULL;
hdlc->proto.id = IF_PROTO_X25;
dev->hard_start_xmit = x25_xmit; dev->hard_start_xmit = x25_xmit;
dev->hard_header = NULL; dev->hard_header = NULL;
dev->type = ARPHRD_X25; dev->type = ARPHRD_X25;
...@@ -218,3 +224,25 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -218,3 +224,25 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL; return -EINVAL;
} }
static int __init mod_init(void)
{
register_hdlc_protocol(&proto);
return 0;
}
static void __exit mod_exit(void)
{
unregister_hdlc_protocol(&proto);
}
module_init(mod_init);
module_exit(mod_exit);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("X.25 protocol support for generic HDLC");
MODULE_LICENSE("GPL v2");
...@@ -11,95 +11,46 @@ ...@@ -11,95 +11,46 @@
#ifndef __HDLC_H #ifndef __HDLC_H
#define __HDLC_H #define __HDLC_H
#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */
#define CLOCK_DEFAULT 0 /* Default setting */
#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
#define ENCODING_DEFAULT 0 /* Default setting */
#define ENCODING_NRZ 1
#define ENCODING_NRZI 2
#define ENCODING_FM_MARK 3
#define ENCODING_FM_SPACE 4
#define ENCODING_MANCHESTER 5
#define PARITY_DEFAULT 0 /* Default setting */
#define PARITY_NONE 1 /* No parity */
#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
#define LMI_DEFAULT 0 /* Default setting */
#define LMI_NONE 1 /* No LMI, all PVCs are static */
#define LMI_ANSI 2 /* ANSI Annex D */
#define LMI_CCITT 3 /* ITU-T Annex A */
#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */
#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ #define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */
#if 0
#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */ #define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */
#else
#define HDLC_MAX_MRU 1600 /* as required for FR network */
#endif
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <net/syncppp.h>
#include <linux/hdlc/ioctl.h> #include <linux/hdlc/ioctl.h>
typedef struct { /* Used in Cisco and PPP mode */ /* Used by all network devices here, pointed to by netdev_priv(dev) */
u8 address; struct hdlc_device_desc {
u8 control; int (*netif_rx)(struct sk_buff *skb);
u16 protocol;
}__attribute__ ((packed)) hdlc_header;
typedef struct {
u32 type; /* code */
u32 par1;
u32 par2;
u16 rel; /* reliability */
u32 time;
}__attribute__ ((packed)) cisco_packet;
#define CISCO_PACKET_LEN 18
#define CISCO_BIG_PACKET_LEN 20
typedef struct pvc_device_struct {
struct net_device *master;
struct net_device *main;
struct net_device *ether; /* bridged Ethernet interface */
struct pvc_device_struct *next; /* Sorted in ascending DLCI order */
int dlci;
int open_count;
struct {
unsigned int new: 1;
unsigned int active: 1;
unsigned int exist: 1;
unsigned int deleted: 1;
unsigned int fecn: 1;
unsigned int becn: 1;
unsigned int bandwidth; /* Cisco LMI reporting only */
}state;
}pvc_device;
typedef struct hdlc_device_struct {
/* To be initialized by hardware driver */
struct net_device_stats stats; struct net_device_stats stats;
};
/* This structure is a private property of HDLC protocols.
Hardware drivers have no interest here */
struct hdlc_proto {
int (*open)(struct net_device *dev);
void (*close)(struct net_device *dev);
void (*start)(struct net_device *dev); /* if open & DCD */
void (*stop)(struct net_device *dev); /* if open & !DCD */
void (*detach)(struct net_device *dev);
int (*ioctl)(struct net_device *dev, struct ifreq *ifr);
unsigned short (*type_trans)(struct sk_buff *skb,
struct net_device *dev);
struct module *module;
struct hdlc_proto *next; /* next protocol in the list */
};
typedef struct hdlc_device {
/* used by HDLC layer to take control over HDLC device from hw driver*/ /* used by HDLC layer to take control over HDLC device from hw driver*/
int (*attach)(struct net_device *dev, int (*attach)(struct net_device *dev,
unsigned short encoding, unsigned short parity); unsigned short encoding, unsigned short parity);
...@@ -107,82 +58,18 @@ typedef struct hdlc_device_struct { ...@@ -107,82 +58,18 @@ typedef struct hdlc_device_struct {
/* hardware driver must handle this instead of dev->hard_start_xmit */ /* hardware driver must handle this instead of dev->hard_start_xmit */
int (*xmit)(struct sk_buff *skb, struct net_device *dev); int (*xmit)(struct sk_buff *skb, struct net_device *dev);
/* Things below are for HDLC layer internal use only */ /* Things below are for HDLC layer internal use only */
struct { const struct hdlc_proto *proto;
int (*open)(struct net_device *dev);
void (*close)(struct net_device *dev);
/* if open & DCD */
void (*start)(struct net_device *dev);
/* if open & !DCD */
void (*stop)(struct net_device *dev);
void (*detach)(struct hdlc_device_struct *hdlc);
int (*netif_rx)(struct sk_buff *skb);
unsigned short (*type_trans)(struct sk_buff *skb,
struct net_device *dev);
int id; /* IF_PROTO_HDLC/CISCO/FR/etc. */
}proto;
int carrier; int carrier;
int open; int open;
spinlock_t state_lock; spinlock_t state_lock;
void *state;
union {
struct {
fr_proto settings;
pvc_device *first_pvc;
int dce_pvc_count;
struct timer_list timer;
unsigned long last_poll;
int reliable;
int dce_changed;
int request;
int fullrep_sent;
u32 last_errors; /* last errors bit list */
u8 n391cnt;
u8 txseq; /* TX sequence number */
u8 rxseq; /* RX sequence number */
}fr;
struct {
cisco_proto settings;
struct timer_list timer;
unsigned long last_poll;
int up;
int request_sent;
u32 txseq; /* TX sequence number */
u32 rxseq; /* RX sequence number */
}cisco;
struct {
raw_hdlc_proto settings;
}raw_hdlc;
struct {
struct ppp_device pppdev;
struct ppp_device *syncppp_ptr;
int (*old_change_mtu)(struct net_device *dev,
int new_mtu);
}ppp;
}state;
void *priv; void *priv;
}hdlc_device; }hdlc_device;
int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr); /* Exported from hdlc module */
int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr);
int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr);
int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr);
/* Exported from hdlc.o */
/* Called by hardware driver when a user requests HDLC service */ /* Called by hardware driver when a user requests HDLC service */
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
...@@ -191,17 +78,21 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); ...@@ -191,17 +78,21 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
#define register_hdlc_device(dev) register_netdev(dev) #define register_hdlc_device(dev) register_netdev(dev)
void unregister_hdlc_device(struct net_device *dev); void unregister_hdlc_device(struct net_device *dev);
void register_hdlc_protocol(struct hdlc_proto *proto);
void unregister_hdlc_protocol(struct hdlc_proto *proto);
struct net_device *alloc_hdlcdev(void *priv); struct net_device *alloc_hdlcdev(void *priv);
static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
static __inline__ struct hdlc_device_desc* dev_to_desc(struct net_device *dev)
{ {
return netdev_priv(dev); return netdev_priv(dev);
} }
static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
{ {
return (pvc_device*)dev->priv; return netdev_priv(dev) + sizeof(struct hdlc_device_desc);
} }
...@@ -225,18 +116,14 @@ int hdlc_open(struct net_device *dev); ...@@ -225,18 +116,14 @@ int hdlc_open(struct net_device *dev);
/* Must be called by hardware driver when HDLC device is being closed */ /* Must be called by hardware driver when HDLC device is being closed */
void hdlc_close(struct net_device *dev); void hdlc_close(struct net_device *dev);
int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
int (*rx)(struct sk_buff *skb), size_t size);
/* May be used by hardware driver to gain control over HDLC device */ /* May be used by hardware driver to gain control over HDLC device */
static __inline__ void hdlc_proto_detach(hdlc_device *hdlc) void detach_hdlc_protocol(struct net_device *dev);
{
if (hdlc->proto.detach)
hdlc->proto.detach(hdlc);
hdlc->proto.detach = NULL;
}
static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev) static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev)
{ {
return &dev_to_hdlc(dev)->stats; return &dev_to_desc(dev)->stats;
} }
...@@ -248,8 +135,8 @@ static __inline__ __be16 hdlc_type_trans(struct sk_buff *skb, ...@@ -248,8 +135,8 @@ static __inline__ __be16 hdlc_type_trans(struct sk_buff *skb,
skb->mac.raw = skb->data; skb->mac.raw = skb->data;
skb->dev = dev; skb->dev = dev;
if (hdlc->proto.type_trans) if (hdlc->proto->type_trans)
return hdlc->proto.type_trans(skb, dev); return hdlc->proto->type_trans(skb, dev);
else else
return htons(ETH_P_HDLC); return htons(ETH_P_HDLC);
} }
......
#ifndef __HDLC_IOCTL_H__ #ifndef __HDLC_IOCTL_H__
#define __HDLC_IOCTL_H__ #define __HDLC_IOCTL_H__
#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */
#define CLOCK_DEFAULT 0 /* Default setting */
#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
#define ENCODING_DEFAULT 0 /* Default setting */
#define ENCODING_NRZ 1
#define ENCODING_NRZI 2
#define ENCODING_FM_MARK 3
#define ENCODING_FM_SPACE 4
#define ENCODING_MANCHESTER 5
#define PARITY_DEFAULT 0 /* Default setting */
#define PARITY_NONE 1 /* No parity */
#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
#define LMI_DEFAULT 0 /* Default setting */
#define LMI_NONE 1 /* No LMI, all PVCs are static */
#define LMI_ANSI 2 /* ANSI Annex D */
#define LMI_CCITT 3 /* ITU-T Annex A */
#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */
typedef struct { typedef struct {
unsigned int clock_rate; /* bits per second */ unsigned int clock_rate; /* bits per second */
unsigned int clock_type; /* internal, external, TX-internal etc. */ unsigned int clock_type; /* internal, external, TX-internal etc. */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册