1 /*
2  * Generic HDLC support routines for Linux
3  *
4  * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of version 2 of the GNU General Public License
8  * as published by the Free Software Foundation.
9  *
10  * Currently supported:
11  *	* raw IP-in-HDLC
12  *	* Cisco HDLC
13  *	* Frame Relay with ANSI or CCITT LMI (both user and network side)
14  *	* PPP
15  *	* X.25
16  *
17  * Use sethdlc utility to set line parameters, protocol and PVCs
18  */
19 
20 #include <linux/config.h>
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/slab.h>
24 #include <linux/poll.h>
25 #include <linux/errno.h>
26 #include <linux/if_arp.h>
27 #include <linux/init.h>
28 #include <linux/skbuff.h>
29 #include <linux/pkt_sched.h>
30 #include <linux/inetdevice.h>
31 #include <linux/lapb.h>
32 #include <linux/rtnetlink.h>
33 #include <linux/hdlc.h>
34 
35 
36 static const char* version = "HDLC support module revision 1.14b";
37 
38 
hdlc_change_mtu(struct net_device * dev,int new_mtu)39 static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
40 {
41 	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
42 		return -EINVAL;
43 	dev->mtu = new_mtu;
44 	return 0;
45 }
46 
47 
48 
hdlc_get_stats(struct net_device * dev)49 static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
50 {
51 	return &dev_to_hdlc(dev)->stats;
52 }
53 
54 
55 
hdlc_rcv(struct sk_buff * skb,struct net_device * dev,struct packet_type * p)56 static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
57 		    struct packet_type *p)
58 {
59 	hdlc_device *hdlc = dev_to_hdlc(dev);
60 	if (hdlc->netif_rx)
61 		hdlc->netif_rx(skb);
62 	else {
63 		hdlc->stats.rx_dropped++; /* Shouldn't happen */
64 		dev_kfree_skb(skb);
65 	}
66 	return 0;
67 }
68 
69 
70 #ifndef CONFIG_HDLC_RAW
71 #define hdlc_raw_ioctl(hdlc, ifr)	-ENOSYS
72 #endif
73 
74 #ifndef CONFIG_HDLC_RAW_ETH
75 #define hdlc_raw_eth_ioctl(hdlc, ifr)	-ENOSYS
76 #endif
77 
78 #ifndef CONFIG_HDLC_PPP
79 #define hdlc_ppp_ioctl(hdlc, ifr)	-ENOSYS
80 #endif
81 
82 #ifndef CONFIG_HDLC_CISCO
83 #define hdlc_cisco_ioctl(hdlc, ifr)	-ENOSYS
84 #endif
85 
86 #ifndef CONFIG_HDLC_FR
87 #define hdlc_fr_ioctl(hdlc, ifr)	-ENOSYS
88 #endif
89 
90 #ifndef CONFIG_HDLC_X25
91 #define hdlc_x25_ioctl(hdlc, ifr)	-ENOSYS
92 #endif
93 
94 
hdlc_ioctl(struct net_device * dev,struct ifreq * ifr,int cmd)95 int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
96 {
97 	hdlc_device *hdlc = dev_to_hdlc(dev);
98 	unsigned int proto;
99 
100 	if (cmd != SIOCWANDEV)
101 		return -EINVAL;
102 
103 	switch(ifr->ifr_settings.type) {
104 	case IF_PROTO_HDLC:
105 	case IF_PROTO_HDLC_ETH:
106 	case IF_PROTO_PPP:
107 	case IF_PROTO_CISCO:
108 	case IF_PROTO_FR:
109 	case IF_PROTO_X25:
110 		proto = ifr->ifr_settings.type;
111 		break;
112 
113 	default:
114 		proto = hdlc->proto;
115 	}
116 
117 	switch(proto) {
118 	case IF_PROTO_HDLC:	return hdlc_raw_ioctl(hdlc, ifr);
119 	case IF_PROTO_HDLC_ETH:	return hdlc_raw_eth_ioctl(hdlc, ifr);
120 	case IF_PROTO_PPP:	return hdlc_ppp_ioctl(hdlc, ifr);
121 	case IF_PROTO_CISCO:	return hdlc_cisco_ioctl(hdlc, ifr);
122 	case IF_PROTO_FR:	return hdlc_fr_ioctl(hdlc, ifr);
123 	case IF_PROTO_X25:	return hdlc_x25_ioctl(hdlc, ifr);
124 	default:		return -EINVAL;
125 	}
126 }
127 
128 
129 
register_hdlc_device(hdlc_device * hdlc)130 int register_hdlc_device(hdlc_device *hdlc)
131 {
132 	int result;
133 	struct net_device *dev = hdlc_to_dev(hdlc);
134 
135 	dev->get_stats = hdlc_get_stats;
136 	dev->change_mtu = hdlc_change_mtu;
137 	dev->mtu = HDLC_MAX_MTU;
138 
139 	dev->type = ARPHRD_RAWHDLC;
140 	dev->hard_header_len = 16;
141 
142 	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
143 
144 	hdlc->proto = -1;
145 	hdlc->proto_detach = NULL;
146 
147 	result = dev_alloc_name(dev, "hdlc%d");
148 	if (result < 0)
149 		return result;
150 
151 	result = register_netdev(dev);
152 	if (result != 0)
153 		return -EIO;
154 
155 	MOD_INC_USE_COUNT;
156 	return 0;
157 }
158 
159 
160 
unregister_hdlc_device(hdlc_device * hdlc)161 void unregister_hdlc_device(hdlc_device *hdlc)
162 {
163 	rtnl_lock();
164 	hdlc_proto_detach(hdlc);
165 	unregister_netdevice(hdlc_to_dev(hdlc));
166 	rtnl_unlock();
167 	MOD_DEC_USE_COUNT;
168 }
169 
170 
171 
172 MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
173 MODULE_DESCRIPTION("HDLC support module");
174 MODULE_LICENSE("GPL v2");
175 
176 EXPORT_SYMBOL(hdlc_ioctl);
177 EXPORT_SYMBOL(register_hdlc_device);
178 EXPORT_SYMBOL(unregister_hdlc_device);
179 
180 static struct packet_type hdlc_packet_type = {
181         __constant_htons(ETH_P_HDLC),
182         NULL,
183         hdlc_rcv,
184         NULL,
185         NULL
186 };
187 
188 
hdlc_module_init(void)189 static int __init hdlc_module_init(void)
190 {
191 	printk(KERN_INFO "%s\n", version);
192         dev_add_pack(&hdlc_packet_type);
193 	return 0;
194 }
195 
196 
197 
hdlc_module_exit(void)198 static void __exit hdlc_module_exit(void)
199 {
200 	dev_remove_pack(&hdlc_packet_type);
201 }
202 
203 
204 module_init(hdlc_module_init);
205 module_exit(hdlc_module_exit);
206