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