diff options
author | Krzysztof Halasa <khc@pm.waw.pl> | 2006-09-26 17:23:45 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-09-26 17:40:24 -0400 |
commit | eb2a2fd91f7c8a53b15063d6f08cf22b9a56cbfb (patch) | |
tree | 1d910a9460b76fd85ed02e8b9131270e4977f6f7 /drivers/net/wan/hdlc_generic.c | |
parent | c226951b93f7cd7c3a10b17384535b617bd43fd0 (diff) |
[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>
Diffstat (limited to 'drivers/net/wan/hdlc_generic.c')
-rw-r--r-- | drivers/net/wan/hdlc_generic.c | 339 |
1 files changed, 0 insertions, 339 deletions
diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c deleted file mode 100644 index 04ca1f7b6424..000000000000 --- a/drivers/net/wan/hdlc_generic.c +++ /dev/null | |||
@@ -1,339 +0,0 @@ | |||
1 | /* | ||
2 | * Generic HDLC support routines for Linux | ||
3 | * | ||
4 | * Copyright (C) 1999 - 2005 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 | * How does it work: | ||
20 | * - proto.open(), close(), start(), stop() calls are serialized. | ||
21 | * The order is: open, [ start, stop ... ] close ... | ||
22 | * - proto.start() and stop() are called with spin_lock_irq held. | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/poll.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/if_arp.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/skbuff.h> | ||
33 | #include <linux/pkt_sched.h> | ||
34 | #include <linux/inetdevice.h> | ||
35 | #include <linux/lapb.h> | ||
36 | #include <linux/rtnetlink.h> | ||
37 | #include <linux/notifier.h> | ||
38 | #include <linux/hdlc.h> | ||
39 | |||
40 | |||
41 | static const char* version = "HDLC support module revision 1.19"; | ||
42 | |||
43 | #undef DEBUG_LINK | ||
44 | |||
45 | |||
46 | static int hdlc_change_mtu(struct net_device *dev, int new_mtu) | ||
47 | { | ||
48 | if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) | ||
49 | return -EINVAL; | ||
50 | dev->mtu = new_mtu; | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | |||
55 | |||
56 | static struct net_device_stats *hdlc_get_stats(struct net_device *dev) | ||
57 | { | ||
58 | return hdlc_stats(dev); | ||
59 | } | ||
60 | |||
61 | |||
62 | |||
63 | static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, | ||
64 | struct packet_type *p, struct net_device *orig_dev) | ||
65 | { | ||
66 | hdlc_device *hdlc = dev_to_hdlc(dev); | ||
67 | if (hdlc->proto.netif_rx) | ||
68 | return hdlc->proto.netif_rx(skb); | ||
69 | |||
70 | hdlc->stats.rx_dropped++; /* Shouldn't happen */ | ||
71 | dev_kfree_skb(skb); | ||
72 | return NET_RX_DROP; | ||
73 | } | ||
74 | |||
75 | |||
76 | |||
77 | static inline void hdlc_proto_start(struct net_device *dev) | ||
78 | { | ||
79 | hdlc_device *hdlc = dev_to_hdlc(dev); | ||
80 | if (hdlc->proto.start) | ||
81 | return hdlc->proto.start(dev); | ||
82 | } | ||
83 | |||
84 | |||
85 | |||
86 | static inline void hdlc_proto_stop(struct net_device *dev) | ||
87 | { | ||
88 | hdlc_device *hdlc = dev_to_hdlc(dev); | ||
89 | if (hdlc->proto.stop) | ||
90 | return hdlc->proto.stop(dev); | ||
91 | } | ||
92 | |||
93 | |||
94 | |||
95 | static int hdlc_device_event(struct notifier_block *this, unsigned long event, | ||
96 | void *ptr) | ||
97 | { | ||
98 | struct net_device *dev = ptr; | ||
99 | hdlc_device *hdlc; | ||
100 | unsigned long flags; | ||
101 | int on; | ||
102 | |||
103 | if (dev->get_stats != hdlc_get_stats) | ||
104 | return NOTIFY_DONE; /* not an HDLC device */ | ||
105 | |||
106 | if (event != NETDEV_CHANGE) | ||
107 | return NOTIFY_DONE; /* Only interrested in carrier changes */ | ||
108 | |||
109 | on = netif_carrier_ok(dev); | ||
110 | |||
111 | #ifdef DEBUG_LINK | ||
112 | printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n", | ||
113 | dev->name, on); | ||
114 | #endif | ||
115 | |||
116 | hdlc = dev_to_hdlc(dev); | ||
117 | spin_lock_irqsave(&hdlc->state_lock, flags); | ||
118 | |||
119 | if (hdlc->carrier == on) | ||
120 | goto carrier_exit; /* no change in DCD line level */ | ||
121 | |||
122 | hdlc->carrier = on; | ||
123 | |||
124 | if (!hdlc->open) | ||
125 | goto carrier_exit; | ||
126 | |||
127 | if (hdlc->carrier) { | ||
128 | printk(KERN_INFO "%s: Carrier detected\n", dev->name); | ||
129 | hdlc_proto_start(dev); | ||
130 | } else { | ||
131 | printk(KERN_INFO "%s: Carrier lost\n", dev->name); | ||
132 | hdlc_proto_stop(dev); | ||
133 | } | ||
134 | |||
135 | carrier_exit: | ||
136 | spin_unlock_irqrestore(&hdlc->state_lock, flags); | ||
137 | return NOTIFY_DONE; | ||
138 | } | ||
139 | |||
140 | |||
141 | |||
142 | /* Must be called by hardware driver when HDLC device is being opened */ | ||
143 | int hdlc_open(struct net_device *dev) | ||
144 | { | ||
145 | hdlc_device *hdlc = dev_to_hdlc(dev); | ||
146 | #ifdef DEBUG_LINK | ||
147 | printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n", | ||
148 | hdlc->carrier, hdlc->open); | ||
149 | #endif | ||
150 | |||
151 | if (hdlc->proto.id == -1) | ||
152 | return -ENOSYS; /* no protocol attached */ | ||
153 | |||
154 | if (hdlc->proto.open) { | ||
155 | int result = hdlc->proto.open(dev); | ||
156 | if (result) | ||
157 | return result; | ||
158 | } | ||
159 | |||
160 | spin_lock_irq(&hdlc->state_lock); | ||
161 | |||
162 | if (hdlc->carrier) { | ||
163 | printk(KERN_INFO "%s: Carrier detected\n", dev->name); | ||
164 | hdlc_proto_start(dev); | ||
165 | } else | ||
166 | printk(KERN_INFO "%s: No carrier\n", dev->name); | ||
167 | |||
168 | hdlc->open = 1; | ||
169 | |||
170 | spin_unlock_irq(&hdlc->state_lock); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | |||
175 | |||
176 | /* Must be called by hardware driver when HDLC device is being closed */ | ||
177 | void hdlc_close(struct net_device *dev) | ||
178 | { | ||
179 | hdlc_device *hdlc = dev_to_hdlc(dev); | ||
180 | #ifdef DEBUG_LINK | ||
181 | printk(KERN_DEBUG "hdlc_close() carrier %i open %i\n", | ||
182 | hdlc->carrier, hdlc->open); | ||
183 | #endif | ||
184 | |||
185 | spin_lock_irq(&hdlc->state_lock); | ||
186 | |||
187 | hdlc->open = 0; | ||
188 | if (hdlc->carrier) | ||
189 | hdlc_proto_stop(dev); | ||
190 | |||
191 | spin_unlock_irq(&hdlc->state_lock); | ||
192 | |||
193 | if (hdlc->proto.close) | ||
194 | hdlc->proto.close(dev); | ||
195 | } | ||
196 | |||
197 | |||
198 | |||
199 | #ifndef CONFIG_HDLC_RAW | ||
200 | #define hdlc_raw_ioctl(dev, ifr) -ENOSYS | ||
201 | #endif | ||
202 | |||
203 | #ifndef CONFIG_HDLC_RAW_ETH | ||
204 | #define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS | ||
205 | #endif | ||
206 | |||
207 | #ifndef CONFIG_HDLC_PPP | ||
208 | #define hdlc_ppp_ioctl(dev, ifr) -ENOSYS | ||
209 | #endif | ||
210 | |||
211 | #ifndef CONFIG_HDLC_CISCO | ||
212 | #define hdlc_cisco_ioctl(dev, ifr) -ENOSYS | ||
213 | #endif | ||
214 | |||
215 | #ifndef CONFIG_HDLC_FR | ||
216 | #define hdlc_fr_ioctl(dev, ifr) -ENOSYS | ||
217 | #endif | ||
218 | |||
219 | #ifndef CONFIG_HDLC_X25 | ||
220 | #define hdlc_x25_ioctl(dev, ifr) -ENOSYS | ||
221 | #endif | ||
222 | |||
223 | |||
224 | int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
225 | { | ||
226 | hdlc_device *hdlc = dev_to_hdlc(dev); | ||
227 | unsigned int proto; | ||
228 | |||
229 | if (cmd != SIOCWANDEV) | ||
230 | return -EINVAL; | ||
231 | |||
232 | switch(ifr->ifr_settings.type) { | ||
233 | case IF_PROTO_HDLC: | ||
234 | case IF_PROTO_HDLC_ETH: | ||
235 | case IF_PROTO_PPP: | ||
236 | case IF_PROTO_CISCO: | ||
237 | case IF_PROTO_FR: | ||
238 | case IF_PROTO_X25: | ||
239 | proto = ifr->ifr_settings.type; | ||
240 | break; | ||
241 | |||
242 | default: | ||
243 | proto = hdlc->proto.id; | ||
244 | } | ||
245 | |||
246 | switch(proto) { | ||
247 | case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr); | ||
248 | case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr); | ||
249 | case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr); | ||
250 | case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr); | ||
251 | case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr); | ||
252 | case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr); | ||
253 | default: return -EINVAL; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | void hdlc_setup(struct net_device *dev) | ||
258 | { | ||
259 | hdlc_device *hdlc = dev_to_hdlc(dev); | ||
260 | |||
261 | dev->get_stats = hdlc_get_stats; | ||
262 | dev->change_mtu = hdlc_change_mtu; | ||
263 | dev->mtu = HDLC_MAX_MTU; | ||
264 | |||
265 | dev->type = ARPHRD_RAWHDLC; | ||
266 | dev->hard_header_len = 16; | ||
267 | |||
268 | dev->flags = IFF_POINTOPOINT | IFF_NOARP; | ||
269 | |||
270 | hdlc->proto.id = -1; | ||
271 | hdlc->proto.detach = NULL; | ||
272 | hdlc->carrier = 1; | ||
273 | hdlc->open = 0; | ||
274 | spin_lock_init(&hdlc->state_lock); | ||
275 | } | ||
276 | |||
277 | struct net_device *alloc_hdlcdev(void *priv) | ||
278 | { | ||
279 | struct net_device *dev; | ||
280 | dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup); | ||
281 | if (dev) | ||
282 | dev_to_hdlc(dev)->priv = priv; | ||
283 | return dev; | ||
284 | } | ||
285 | |||
286 | void unregister_hdlc_device(struct net_device *dev) | ||
287 | { | ||
288 | rtnl_lock(); | ||
289 | hdlc_proto_detach(dev_to_hdlc(dev)); | ||
290 | unregister_netdevice(dev); | ||
291 | rtnl_unlock(); | ||
292 | } | ||
293 | |||
294 | |||
295 | |||
296 | MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); | ||
297 | MODULE_DESCRIPTION("HDLC support module"); | ||
298 | MODULE_LICENSE("GPL v2"); | ||
299 | |||
300 | EXPORT_SYMBOL(hdlc_open); | ||
301 | EXPORT_SYMBOL(hdlc_close); | ||
302 | EXPORT_SYMBOL(hdlc_ioctl); | ||
303 | EXPORT_SYMBOL(hdlc_setup); | ||
304 | EXPORT_SYMBOL(alloc_hdlcdev); | ||
305 | EXPORT_SYMBOL(unregister_hdlc_device); | ||
306 | |||
307 | static struct packet_type hdlc_packet_type = { | ||
308 | .type = __constant_htons(ETH_P_HDLC), | ||
309 | .func = hdlc_rcv, | ||
310 | }; | ||
311 | |||
312 | |||
313 | static struct notifier_block hdlc_notifier = { | ||
314 | .notifier_call = hdlc_device_event, | ||
315 | }; | ||
316 | |||
317 | |||
318 | static int __init hdlc_module_init(void) | ||
319 | { | ||
320 | int result; | ||
321 | |||
322 | printk(KERN_INFO "%s\n", version); | ||
323 | if ((result = register_netdevice_notifier(&hdlc_notifier)) != 0) | ||
324 | return result; | ||
325 | dev_add_pack(&hdlc_packet_type); | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | |||
330 | |||
331 | static void __exit hdlc_module_exit(void) | ||
332 | { | ||
333 | dev_remove_pack(&hdlc_packet_type); | ||
334 | unregister_netdevice_notifier(&hdlc_notifier); | ||
335 | } | ||
336 | |||
337 | |||
338 | module_init(hdlc_module_init); | ||
339 | module_exit(hdlc_module_exit); | ||