mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
[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: Krzysztof Halasa <khc@pm.waw.pl> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
1 parent
c226951b93
commit
eb2a2fd91f
11 files changed
+739
-504
No files matched your search
@@ -154,7 +154,7 @@ config HDLC
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_RAW
|
||||
bool "Raw HDLC support"
|
||||
tristate "Raw HDLC support"
|
||||
depends on HDLC
|
||||
help
|
||||
Generic HDLC driver supporting raw HDLC over WAN connections.
|
||||
@@ -162,7 +162,7 @@ config HDLC_RAW
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_RAW_ETH
|
||||
bool "Raw HDLC Ethernet device support"
|
||||
tristate "Raw HDLC Ethernet device support"
|
||||
depends on HDLC
|
||||
help
|
||||
Generic HDLC driver supporting raw HDLC Ethernet device emulation
|
||||
@@ -173,7 +173,7 @@ config HDLC_RAW_ETH
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_CISCO
|
||||
bool "Cisco HDLC support"
|
||||
tristate "Cisco HDLC support"
|
||||
depends on HDLC
|
||||
help
|
||||
Generic HDLC driver supporting Cisco HDLC over WAN connections.
|
||||
@@ -181,7 +181,7 @@ config HDLC_CISCO
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_FR
|
||||
bool "Frame Relay support"
|
||||
tristate "Frame Relay support"
|
||||
depends on HDLC
|
||||
help
|
||||
Generic HDLC driver supporting Frame Relay over WAN connections.
|
||||
@@ -189,7 +189,7 @@ config HDLC_FR
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_PPP
|
||||
bool "Synchronous Point-to-Point Protocol (PPP) support"
|
||||
tristate "Synchronous Point-to-Point Protocol (PPP) support"
|
||||
depends on HDLC
|
||||
help
|
||||
Generic HDLC driver supporting PPP over WAN connections.
|
||||
@@ -197,7 +197,7 @@ config HDLC_PPP
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_X25
|
||||
bool "X.25 protocol support"
|
||||
tristate "X.25 protocol support"
|
||||
depends on HDLC && (LAPB=m && HDLC=m || LAPB=y)
|
||||
help
|
||||
Generic HDLC driver supporting X.25 over WAN connections.
|
||||
|
||||
@@ -9,14 +9,13 @@ cyclomx-y := cycx_main.o
|
||||
cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o
|
||||
cyclomx-objs := $(cyclomx-y)
|
||||
|
||||
hdlc-y := hdlc_generic.o
|
||||
hdlc-$(CONFIG_HDLC_RAW) += hdlc_raw.o
|
||||
hdlc-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
|
||||
hdlc-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
|
||||
hdlc-$(CONFIG_HDLC_FR) += hdlc_fr.o
|
||||
hdlc-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
|
||||
hdlc-$(CONFIG_HDLC_X25) += hdlc_x25.o
|
||||
hdlc-objs := $(hdlc-y)
|
||||
obj-$(CONFIG_HDLC) += hdlc.o
|
||||
obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o
|
||||
obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
|
||||
obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
|
||||
obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
|
||||
obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o
|
||||
obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
|
||||
|
||||
pc300-y := pc300_drv.o
|
||||
pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
|
||||
@@ -38,10 +37,6 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o
|
||||
obj-$(CONFIG_LAPBETHER) += lapbether.o
|
||||
obj-$(CONFIG_SBNI) += sbni.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_C101) += c101.o
|
||||
obj-$(CONFIG_WANXL) += wanxl.o
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@@ -17,9 +17,9 @@
|
||||
* Use sethdlc utility to set line parameters, protocol and PVCs
|
||||
*
|
||||
* 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 ...
|
||||
* - 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>
|
||||
@@ -38,10 +38,12 @@
|
||||
#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
|
||||
|
||||
static struct hdlc_proto *first_proto = NULL;
|
||||
|
||||
|
||||
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)
|
||||
static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *p, struct net_device *orig_dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
if (hdlc->proto.netif_rx)
|
||||
return hdlc->proto.netif_rx(skb);
|
||||
struct hdlc_device_desc *desc = dev_to_desc(dev);
|
||||
if (desc->netif_rx)
|
||||
return desc->netif_rx(skb);
|
||||
|
||||
hdlc->stats.rx_dropped++; /* Shouldn't happen */
|
||||
desc->stats.rx_dropped++; /* Shouldn't happen */
|
||||
dev_kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
if (hdlc->proto.start)
|
||||
return hdlc->proto.start(dev);
|
||||
if (hdlc->proto->start)
|
||||
return hdlc->proto->start(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)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
if (hdlc->proto.stop)
|
||||
return hdlc->proto.stop(dev);
|
||||
if (hdlc->proto->stop)
|
||||
return hdlc->proto->stop(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -144,15 +146,15 @@ int hdlc_open(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
#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);
|
||||
#endif
|
||||
|
||||
if (hdlc->proto.id == -1)
|
||||
if (hdlc->proto == NULL)
|
||||
return -ENOSYS; /* no protocol attached */
|
||||
|
||||
if (hdlc->proto.open) {
|
||||
int result = hdlc->proto.open(dev);
|
||||
if (hdlc->proto->open) {
|
||||
int result = hdlc->proto->open(dev);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
@@ -178,7 +180,7 @@ void hdlc_close(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
#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);
|
||||
#endif
|
||||
|
||||
@@ -190,68 +192,34 @@ void hdlc_close(struct net_device *dev)
|
||||
|
||||
spin_unlock_irq(&hdlc->state_lock);
|
||||
|
||||
if (hdlc->proto.close)
|
||||
hdlc->proto.close(dev);
|
||||
if (hdlc->proto->close)
|
||||
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)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
unsigned int proto;
|
||||
struct hdlc_proto *proto = first_proto;
|
||||
int result;
|
||||
|
||||
if (cmd != SIOCWANDEV)
|
||||
return -EINVAL;
|
||||
|
||||
switch(ifr->ifr_settings.type) {
|
||||
case IF_PROTO_HDLC:
|
||||
case IF_PROTO_HDLC_ETH:
|
||||
case IF_PROTO_PPP:
|
||||
case IF_PROTO_CISCO:
|
||||
case IF_PROTO_FR:
|
||||
case IF_PROTO_X25:
|
||||
proto = ifr->ifr_settings.type;
|
||||
break;
|
||||
|
||||
default:
|
||||
proto = hdlc->proto.id;
|
||||
if (dev_to_hdlc(dev)->proto) {
|
||||
result = dev_to_hdlc(dev)->proto->ioctl(dev, ifr);
|
||||
if (result != -EINVAL)
|
||||
return result;
|
||||
}
|
||||
|
||||
switch(proto) {
|
||||
case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr);
|
||||
case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr);
|
||||
case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr);
|
||||
case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr);
|
||||
case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr);
|
||||
case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr);
|
||||
default: return -EINVAL;
|
||||
/* Not handled by currently attached protocol (if any) */
|
||||
|
||||
while (proto) {
|
||||
if ((result = proto->ioctl(dev, ifr)) != -EINVAL)
|
||||
return result;
|
||||
proto = proto->next;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void hdlc_setup(struct net_device *dev)
|
||||
@@ -267,8 +235,6 @@ void hdlc_setup(struct net_device *dev)
|
||||
|
||||
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
|
||||
|
||||
hdlc->proto.id = -1;
|
||||
hdlc->proto.detach = NULL;
|
||||
hdlc->carrier = 1;
|
||||
hdlc->open = 0;
|
||||
spin_lock_init(&hdlc->state_lock);
|
||||
@@ -277,7 +243,8 @@ void hdlc_setup(struct net_device *dev)
|
||||
struct net_device *alloc_hdlcdev(void *priv)
|
||||
{
|
||||
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)
|
||||
dev_to_hdlc(dev)->priv = priv;
|
||||
return dev;
|
||||
@@ -286,13 +253,71 @@ struct net_device *alloc_hdlcdev(void *priv)
|
||||
void unregister_hdlc_device(struct net_device *dev)
|
||||
{
|
||||
rtnl_lock();
|
||||
hdlc_proto_detach(dev_to_hdlc(dev));
|
||||
unregister_netdevice(dev);
|
||||
detach_hdlc_protocol(dev);
|
||||
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_DESCRIPTION("HDLC support module");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -303,6 +328,10 @@ EXPORT_SYMBOL(hdlc_ioctl);
|
||||
EXPORT_SYMBOL(hdlc_setup);
|
||||
EXPORT_SYMBOL(alloc_hdlcdev);
|
||||
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 = {
|
||||
.type = __constant_htons(ETH_P_HDLC),
|
||||
+133
-63
@@ -2,7 +2,7 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* 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
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@@ -34,17 +34,56 @@
|
||||
#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,
|
||||
u16 type, void *daddr, void *saddr,
|
||||
unsigned int len)
|
||||
{
|
||||
hdlc_header *data;
|
||||
struct hdlc_header *data;
|
||||
#ifdef DEBUG_HARD_HEADER
|
||||
printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
|
||||
#endif
|
||||
|
||||
skb_push(skb, sizeof(hdlc_header));
|
||||
data = (hdlc_header*)skb->data;
|
||||
skb_push(skb, sizeof(struct hdlc_header));
|
||||
data = (struct hdlc_header*)skb->data;
|
||||
if (type == CISCO_KEEPALIVE)
|
||||
data->address = CISCO_MULTICAST;
|
||||
else
|
||||
@@ -52,7 +91,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
|
||||
data->control = 0;
|
||||
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,
|
||||
u32 par1, u32 par2)
|
||||
{
|
||||
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) {
|
||||
printk(KERN_WARNING
|
||||
"%s: Memory squeeze on cisco_keepalive_send()\n",
|
||||
@@ -72,7 +112,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
|
||||
}
|
||||
skb_reserve(skb, 4);
|
||||
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->par1 = htonl(par1);
|
||||
@@ -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 */
|
||||
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->dev = dev;
|
||||
skb->nh.raw = skb->data;
|
||||
@@ -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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (data->address != CISCO_MULTICAST &&
|
||||
@@ -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_IPX):
|
||||
case __constant_htons(ETH_P_IPV6):
|
||||
skb_pull(skb, sizeof(hdlc_header));
|
||||
skb_pull(skb, sizeof(struct hdlc_header));
|
||||
return data->protocol;
|
||||
default:
|
||||
return __constant_htons(ETH_P_HDLC);
|
||||
@@ -118,12 +158,12 @@ static int cisco_rx(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = skb->dev;
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
hdlc_header *data = (hdlc_header*)skb->data;
|
||||
cisco_packet *cisco_data;
|
||||
struct hdlc_header *data = (struct hdlc_header*)skb->data;
|
||||
struct cisco_packet *cisco_data;
|
||||
struct in_device *in_dev;
|
||||
u32 addr, mask;
|
||||
|
||||
if (skb->len < sizeof(hdlc_header))
|
||||
if (skb->len < sizeof(struct hdlc_header))
|
||||
goto rx_error;
|
||||
|
||||
if (data->address != CISCO_MULTICAST &&
|
||||
@@ -137,15 +177,17 @@ static int cisco_rx(struct sk_buff *skb)
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
case CISCO_KEEPALIVE:
|
||||
if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN &&
|
||||
skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) {
|
||||
printk(KERN_INFO "%s: Invalid length of Cisco "
|
||||
"control packet (%d bytes)\n",
|
||||
dev->name, skb->len);
|
||||
if ((skb->len != sizeof(struct hdlc_header) +
|
||||
CISCO_PACKET_LEN) &&
|
||||
(skb->len != sizeof(struct hdlc_header) +
|
||||
CISCO_BIG_PACKET_LEN)) {
|
||||
printk(KERN_INFO "%s: Invalid length of Cisco control"
|
||||
" packet (%d bytes)\n", dev->name, skb->len);
|
||||
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)) {
|
||||
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
|
||||
@@ -178,11 +220,11 @@ static int cisco_rx(struct sk_buff *skb)
|
||||
goto rx_error;
|
||||
|
||||
case CISCO_KEEPALIVE_REQ:
|
||||
hdlc->state.cisco.rxseq = ntohl(cisco_data->par1);
|
||||
if (hdlc->state.cisco.request_sent &&
|
||||
ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) {
|
||||
hdlc->state.cisco.last_poll = jiffies;
|
||||
if (!hdlc->state.cisco.up) {
|
||||
state(hdlc)->rxseq = ntohl(cisco_data->par1);
|
||||
if (state(hdlc)->request_sent &&
|
||||
ntohl(cisco_data->par2) == state(hdlc)->txseq) {
|
||||
state(hdlc)->last_poll = jiffies;
|
||||
if (!state(hdlc)->up) {
|
||||
u32 sec, min, hrs, days;
|
||||
sec = ntohl(cisco_data->time) / 1000;
|
||||
min = sec / 60; sec -= min * 60;
|
||||
@@ -193,7 +235,7 @@ static int cisco_rx(struct sk_buff *skb)
|
||||
dev->name, days, hrs,
|
||||
min, sec);
|
||||
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)
|
||||
return NET_RX_DROP;
|
||||
|
||||
rx_error:
|
||||
hdlc->stats.rx_errors++; /* Mark error */
|
||||
dev_to_desc(dev)->stats.rx_errors++; /* Mark error */
|
||||
dev_kfree_skb_any(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
@@ -220,23 +262,22 @@ static void cisco_timer(unsigned long arg)
|
||||
struct net_device *dev = (struct net_device *)arg;
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
|
||||
if (hdlc->state.cisco.up &&
|
||||
time_after(jiffies, hdlc->state.cisco.last_poll +
|
||||
hdlc->state.cisco.settings.timeout * HZ)) {
|
||||
hdlc->state.cisco.up = 0;
|
||||
if (state(hdlc)->up &&
|
||||
time_after(jiffies, state(hdlc)->last_poll +
|
||||
state(hdlc)->settings.timeout * HZ)) {
|
||||
state(hdlc)->up = 0;
|
||||
printk(KERN_INFO "%s: Link down\n", dev->name);
|
||||
netif_dormant_on(dev);
|
||||
}
|
||||
|
||||
cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
|
||||
++hdlc->state.cisco.txseq,
|
||||
hdlc->state.cisco.rxseq);
|
||||
hdlc->state.cisco.request_sent = 1;
|
||||
hdlc->state.cisco.timer.expires = jiffies +
|
||||
hdlc->state.cisco.settings.interval * HZ;
|
||||
hdlc->state.cisco.timer.function = cisco_timer;
|
||||
hdlc->state.cisco.timer.data = arg;
|
||||
add_timer(&hdlc->state.cisco.timer);
|
||||
cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq,
|
||||
state(hdlc)->rxseq);
|
||||
state(hdlc)->request_sent = 1;
|
||||
state(hdlc)->timer.expires = jiffies +
|
||||
state(hdlc)->settings.interval * HZ;
|
||||
state(hdlc)->timer.function = cisco_timer;
|
||||
state(hdlc)->timer.data = arg;
|
||||
add_timer(&state(hdlc)->timer);
|
||||
}
|
||||
|
||||
|
||||
@@ -244,15 +285,15 @@ static void cisco_timer(unsigned long arg)
|
||||
static void cisco_start(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
hdlc->state.cisco.up = 0;
|
||||
hdlc->state.cisco.request_sent = 0;
|
||||
hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
|
||||
state(hdlc)->up = 0;
|
||||
state(hdlc)->request_sent = 0;
|
||||
state(hdlc)->txseq = state(hdlc)->rxseq = 0;
|
||||
|
||||
init_timer(&hdlc->state.cisco.timer);
|
||||
hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/
|
||||
hdlc->state.cisco.timer.function = cisco_timer;
|
||||
hdlc->state.cisco.timer.data = (unsigned long)dev;
|
||||
add_timer(&hdlc->state.cisco.timer);
|
||||
init_timer(&state(hdlc)->timer);
|
||||
state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/
|
||||
state(hdlc)->timer.function = cisco_timer;
|
||||
state(hdlc)->timer.data = (unsigned long)dev;
|
||||
add_timer(&state(hdlc)->timer);
|
||||
}
|
||||
|
||||
|
||||
@@ -260,15 +301,24 @@ static void cisco_start(struct net_device *dev)
|
||||
static void cisco_stop(struct net_device *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);
|
||||
hdlc->state.cisco.up = 0;
|
||||
hdlc->state.cisco.request_sent = 0;
|
||||
state(hdlc)->up = 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;
|
||||
const size_t size = sizeof(cisco_proto);
|
||||
@@ -278,12 +328,14 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto)
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_CISCO;
|
||||
if (ifr->ifr_settings.size < size) {
|
||||
ifr->ifr_settings.size = size; /* data size wanted */
|
||||
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 0;
|
||||
|
||||
@@ -302,19 +354,15 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
return -EINVAL;
|
||||
|
||||
result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc_proto_detach(hdlc);
|
||||
memcpy(&hdlc->state.cisco.settings, &new_settings, size);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
result = attach_hdlc_protocol(dev, &proto, cisco_rx,
|
||||
sizeof(struct cisco_state));
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc->proto.start = cisco_start;
|
||||
hdlc->proto.stop = cisco_stop;
|
||||
hdlc->proto.netif_rx = cisco_rx;
|
||||
hdlc->proto.type_trans = cisco_type_trans;
|
||||
hdlc->proto.id = IF_PROTO_CISCO;
|
||||
memcpy(&state(hdlc)->settings, &new_settings, size);
|
||||
dev->hard_start_xmit = hdlc->xmit;
|
||||
dev->hard_header = cisco_hard_header;
|
||||
dev->hard_header_cache = NULL;
|
||||
@@ -327,3 +375,25 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
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");
|
||||
+235
-150
File diff suppressed because it is too large.
Load diff
+61
-16
@@ -2,7 +2,7 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* 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
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@@ -22,6 +22,21 @@
|
||||
#include <linux/lapb.h>
|
||||
#include <linux/rtnetlink.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)
|
||||
@@ -30,16 +45,16 @@ static int ppp_open(struct net_device *dev)
|
||||
void *old_ioctl;
|
||||
int result;
|
||||
|
||||
dev->priv = &hdlc->state.ppp.syncppp_ptr;
|
||||
hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;
|
||||
hdlc->state.ppp.pppdev.dev = dev;
|
||||
dev->priv = &state(hdlc)->syncppp_ptr;
|
||||
state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev;
|
||||
state(hdlc)->pppdev.dev = dev;
|
||||
|
||||
old_ioctl = dev->do_ioctl;
|
||||
hdlc->state.ppp.old_change_mtu = dev->change_mtu;
|
||||
sppp_attach(&hdlc->state.ppp.pppdev);
|
||||
state(hdlc)->old_change_mtu = dev->change_mtu;
|
||||
sppp_attach(&state(hdlc)->pppdev);
|
||||
/* sppp_attach nukes them. We don't need syncppp's 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;
|
||||
result = sppp_open(dev);
|
||||
if (result) {
|
||||
@@ -59,7 +74,7 @@ static void ppp_close(struct net_device *dev)
|
||||
sppp_close(dev);
|
||||
sppp_detach(dev);
|
||||
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->hard_header_len = 16;
|
||||
}
|
||||
@@ -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);
|
||||
int result;
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto)
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_PPP;
|
||||
return 0; /* return protocol only, no settable parameters */
|
||||
|
||||
@@ -96,13 +122,10 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc_proto_detach(hdlc);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
|
||||
hdlc->proto.open = ppp_open;
|
||||
hdlc->proto.close = ppp_close;
|
||||
hdlc->proto.type_trans = ppp_type_trans;
|
||||
hdlc->proto.id = IF_PROTO_PPP;
|
||||
result = attach_hdlc_protocol(dev, &proto, NULL,
|
||||
sizeof(struct ppp_state));
|
||||
if (result)
|
||||
return result;
|
||||
dev->hard_start_xmit = hdlc->xmit;
|
||||
dev->hard_header = NULL;
|
||||
dev->type = ARPHRD_PPP;
|
||||
@@ -113,3 +136,25 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
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 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* 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
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@@ -24,6 +24,8 @@
|
||||
#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)
|
||||
{
|
||||
return __constant_htons(ETH_P_IP);
|
||||
@@ -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;
|
||||
const size_t size = sizeof(raw_hdlc_proto);
|
||||
@@ -41,12 +50,14 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto)
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_HDLC;
|
||||
if (ifr->ifr_settings.size < size) {
|
||||
ifr->ifr_settings.size = size; /* data size wanted */
|
||||
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 0;
|
||||
|
||||
@@ -71,12 +82,11 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc_proto_detach(hdlc);
|
||||
memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
|
||||
hdlc->proto.type_trans = raw_type_trans;
|
||||
hdlc->proto.id = IF_PROTO_HDLC;
|
||||
result = attach_hdlc_protocol(dev, &proto, NULL,
|
||||
sizeof(raw_hdlc_proto));
|
||||
if (result)
|
||||
return result;
|
||||
memcpy(hdlc->state, &new_settings, size);
|
||||
dev->hard_start_xmit = hdlc->xmit;
|
||||
dev->hard_header = NULL;
|
||||
dev->type = ARPHRD_RAWHDLC;
|
||||
@@ -88,3 +98,25 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
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 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* 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
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <linux/etherdevice.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)
|
||||
{
|
||||
@@ -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;
|
||||
const size_t size = sizeof(raw_hdlc_proto);
|
||||
@@ -56,12 +64,14 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto)
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_HDLC_ETH;
|
||||
if (ifr->ifr_settings.size < size) {
|
||||
ifr->ifr_settings.size = size; /* data size wanted */
|
||||
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 0;
|
||||
|
||||
@@ -86,12 +96,11 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc_proto_detach(hdlc);
|
||||
memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
|
||||
hdlc->proto.type_trans = eth_type_trans;
|
||||
hdlc->proto.id = IF_PROTO_HDLC_ETH;
|
||||
result = attach_hdlc_protocol(dev, &proto, NULL,
|
||||
sizeof(raw_hdlc_proto));
|
||||
if (result)
|
||||
return result;
|
||||
memcpy(hdlc->state, &new_settings, size);
|
||||
dev->hard_start_xmit = eth_tx;
|
||||
old_ch_mtu = dev->change_mtu;
|
||||
old_qlen = dev->tx_queue_len;
|
||||
@@ -106,3 +115,25 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
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");
|
||||
+41
-13
@@ -2,7 +2,7 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* 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
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#include <net/x25device.h>
|
||||
|
||||
static int x25_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
|
||||
/* These functions are callbacks called by LAPB layer */
|
||||
|
||||
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)
|
||||
|
||||
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) {
|
||||
hdlc->stats.rx_dropped++;
|
||||
desc->stats.rx_dropped++;
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
if (lapb_data_received(skb->dev, skb) == LAPB_OK)
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
hdlc->stats.rx_errors++;
|
||||
desc->stats.rx_errors++;
|
||||
dev_kfree_skb_any(skb);
|
||||
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);
|
||||
int result;
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto)
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_X25;
|
||||
return 0; /* return protocol only, no settable parameters */
|
||||
|
||||
@@ -200,14 +211,9 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc_proto_detach(hdlc);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
|
||||
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;
|
||||
if ((result = attach_hdlc_protocol(dev, &proto,
|
||||
x25_rx, 0)) != 0)
|
||||
return result;
|
||||
dev->hard_start_xmit = x25_xmit;
|
||||
dev->hard_header = NULL;
|
||||
dev->type = ARPHRD_X25;
|
||||
@@ -218,3 +224,25 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
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");
|
||||
+43
-156
@@ -11,95 +11,46 @@
|
||||
#ifndef __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 */
|
||||
#if 0
|
||||
#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__
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/syncppp.h>
|
||||
#include <linux/hdlc/ioctl.h>
|
||||
|
||||
|
||||
typedef struct { /* Used in Cisco and PPP mode */
|
||||
u8 address;
|
||||
u8 control;
|
||||
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 */
|
||||
/* Used by all network devices here, pointed to by netdev_priv(dev) */
|
||||
struct hdlc_device_desc {
|
||||
int (*netif_rx)(struct sk_buff *skb);
|
||||
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*/
|
||||
int (*attach)(struct net_device *dev,
|
||||
unsigned short encoding, unsigned short parity);
|
||||
@@ -107,82 +58,18 @@ typedef struct hdlc_device_struct {
|
||||
/* hardware driver must handle this instead of dev->hard_start_xmit */
|
||||
int (*xmit)(struct sk_buff *skb, struct net_device *dev);
|
||||
|
||||
|
||||
/* Things below are for HDLC layer internal use only */
|
||||
struct {
|
||||
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;
|
||||
|
||||
const struct hdlc_proto *proto;
|
||||
int carrier;
|
||||
int open;
|
||||
spinlock_t state_lock;
|
||||
|
||||
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 *state;
|
||||
void *priv;
|
||||
}hdlc_device;
|
||||
|
||||
|
||||
|
||||
int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
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 */
|
||||
/* Exported from hdlc module */
|
||||
|
||||
/* Called by hardware driver when a user requests HDLC service */
|
||||
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)
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
|
||||
static __inline__ hdlc_device* dev_to_hdlc(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);
|
||||
/* Must be called by hardware driver when HDLC device is being closed */
|
||||
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 */
|
||||
static __inline__ void hdlc_proto_detach(hdlc_device *hdlc)
|
||||
{
|
||||
if (hdlc->proto.detach)
|
||||
hdlc->proto.detach(hdlc);
|
||||
hdlc->proto.detach = NULL;
|
||||
}
|
||||
|
||||
void detach_hdlc_protocol(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,
|
||||
skb->mac.raw = skb->data;
|
||||
skb->dev = dev;
|
||||
|
||||
if (hdlc->proto.type_trans)
|
||||
return hdlc->proto.type_trans(skb, dev);
|
||||
if (hdlc->proto->type_trans)
|
||||
return hdlc->proto->type_trans(skb, dev);
|
||||
else
|
||||
return htons(ETH_P_HDLC);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,39 @@
|
||||
#ifndef __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 {
|
||||
unsigned int clock_rate; /* bits per second */
|
||||
unsigned int clock_type; /* internal, external, TX-internal etc. */
|
||||
|
||||
Reference in new issue
Block a user