Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb2a2fd9 authored by Krzysztof Halasa's avatar Krzysztof Halasa Committed by Jeff Garzik
Browse files

[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: default avatarKrzysztof Halasa <khc@pm.waw.pl>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent c226951b
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -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.
+7 −12
Original line number Diff line number Diff line
@@ -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
+99 −70
Original line number Diff line number Diff line
/*
 * 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),
+134 −64
Original line number Diff line number Diff line
@@ -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;

	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);
	state(hdlc)->up = 0;
	state(hdlc)->request_sent = 0;
	state(hdlc)->txseq = state(hdlc)->rxseq = 0;

	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");
+237 −152

File changed.

Preview size limit exceeded, changes collapsed.

Loading