Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.26-rc6 385 lines 8.2 kB view raw
1/* 2 * Generic HDLC support routines for Linux 3 * 4 * Copyright (C) 1999 - 2008 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#include <net/net_namespace.h> 40 41 42static const char* version = "HDLC support module revision 1.22"; 43 44#undef DEBUG_LINK 45 46static struct hdlc_proto *first_proto; 47 48static int hdlc_change_mtu(struct net_device *dev, int new_mtu) 49{ 50 if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU)) 51 return -EINVAL; 52 dev->mtu = new_mtu; 53 return 0; 54} 55 56 57 58static struct net_device_stats *hdlc_get_stats(struct net_device *dev) 59{ 60 return hdlc_stats(dev); 61} 62 63 64 65static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, 66 struct packet_type *p, struct net_device *orig_dev) 67{ 68 struct hdlc_device *hdlc = dev_to_hdlc(dev); 69 70 if (dev_net(dev) != &init_net) { 71 kfree_skb(skb); 72 return 0; 73 } 74 75 BUG_ON(!hdlc->proto->netif_rx); 76 return hdlc->proto->netif_rx(skb); 77} 78 79 80 81static inline void hdlc_proto_start(struct net_device *dev) 82{ 83 hdlc_device *hdlc = dev_to_hdlc(dev); 84 if (hdlc->proto->start) 85 hdlc->proto->start(dev); 86} 87 88 89 90static inline void hdlc_proto_stop(struct net_device *dev) 91{ 92 hdlc_device *hdlc = dev_to_hdlc(dev); 93 if (hdlc->proto->stop) 94 hdlc->proto->stop(dev); 95} 96 97 98 99static int hdlc_device_event(struct notifier_block *this, unsigned long event, 100 void *ptr) 101{ 102 struct net_device *dev = ptr; 103 hdlc_device *hdlc; 104 unsigned long flags; 105 int on; 106 107 if (dev_net(dev) != &init_net) 108 return NOTIFY_DONE; 109 110 if (dev->get_stats != hdlc_get_stats) 111 return NOTIFY_DONE; /* not an HDLC device */ 112 113 if (event != NETDEV_CHANGE) 114 return NOTIFY_DONE; /* Only interrested in carrier changes */ 115 116 on = netif_carrier_ok(dev); 117 118#ifdef DEBUG_LINK 119 printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n", 120 dev->name, on); 121#endif 122 123 hdlc = dev_to_hdlc(dev); 124 spin_lock_irqsave(&hdlc->state_lock, flags); 125 126 if (hdlc->carrier == on) 127 goto carrier_exit; /* no change in DCD line level */ 128 129 hdlc->carrier = on; 130 131 if (!hdlc->open) 132 goto carrier_exit; 133 134 if (hdlc->carrier) { 135 printk(KERN_INFO "%s: Carrier detected\n", dev->name); 136 hdlc_proto_start(dev); 137 } else { 138 printk(KERN_INFO "%s: Carrier lost\n", dev->name); 139 hdlc_proto_stop(dev); 140 } 141 142carrier_exit: 143 spin_unlock_irqrestore(&hdlc->state_lock, flags); 144 return NOTIFY_DONE; 145} 146 147 148 149/* Must be called by hardware driver when HDLC device is being opened */ 150int hdlc_open(struct net_device *dev) 151{ 152 hdlc_device *hdlc = dev_to_hdlc(dev); 153#ifdef DEBUG_LINK 154 printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name, 155 hdlc->carrier, hdlc->open); 156#endif 157 158 if (hdlc->proto == NULL) 159 return -ENOSYS; /* no protocol attached */ 160 161 if (hdlc->proto->open) { 162 int result = hdlc->proto->open(dev); 163 if (result) 164 return result; 165 } 166 167 spin_lock_irq(&hdlc->state_lock); 168 169 if (hdlc->carrier) { 170 printk(KERN_INFO "%s: Carrier detected\n", dev->name); 171 hdlc_proto_start(dev); 172 } else 173 printk(KERN_INFO "%s: No carrier\n", dev->name); 174 175 hdlc->open = 1; 176 177 spin_unlock_irq(&hdlc->state_lock); 178 return 0; 179} 180 181 182 183/* Must be called by hardware driver when HDLC device is being closed */ 184void hdlc_close(struct net_device *dev) 185{ 186 hdlc_device *hdlc = dev_to_hdlc(dev); 187#ifdef DEBUG_LINK 188 printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name, 189 hdlc->carrier, hdlc->open); 190#endif 191 192 spin_lock_irq(&hdlc->state_lock); 193 194 hdlc->open = 0; 195 if (hdlc->carrier) 196 hdlc_proto_stop(dev); 197 198 spin_unlock_irq(&hdlc->state_lock); 199 200 if (hdlc->proto->close) 201 hdlc->proto->close(dev); 202} 203 204 205 206int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 207{ 208 struct hdlc_proto *proto = first_proto; 209 int result; 210 211 if (cmd != SIOCWANDEV) 212 return -EINVAL; 213 214 if (dev_to_hdlc(dev)->proto) { 215 result = dev_to_hdlc(dev)->proto->ioctl(dev, ifr); 216 if (result != -EINVAL) 217 return result; 218 } 219 220 /* Not handled by currently attached protocol (if any) */ 221 222 while (proto) { 223 if ((result = proto->ioctl(dev, ifr)) != -EINVAL) 224 return result; 225 proto = proto->next; 226 } 227 return -EINVAL; 228} 229 230static const struct header_ops hdlc_null_ops; 231 232static void hdlc_setup_dev(struct net_device *dev) 233{ 234 /* Re-init all variables changed by HDLC protocol drivers, 235 * including ether_setup() called from hdlc_raw_eth.c. 236 */ 237 dev->get_stats = hdlc_get_stats; 238 dev->flags = IFF_POINTOPOINT | IFF_NOARP; 239 dev->mtu = HDLC_MAX_MTU; 240 dev->type = ARPHRD_RAWHDLC; 241 dev->hard_header_len = 16; 242 dev->addr_len = 0; 243 dev->header_ops = &hdlc_null_ops; 244 245 dev->change_mtu = hdlc_change_mtu; 246} 247 248static void hdlc_setup(struct net_device *dev) 249{ 250 hdlc_device *hdlc = dev_to_hdlc(dev); 251 252 hdlc_setup_dev(dev); 253 hdlc->carrier = 1; 254 hdlc->open = 0; 255 spin_lock_init(&hdlc->state_lock); 256} 257 258struct net_device *alloc_hdlcdev(void *priv) 259{ 260 struct net_device *dev; 261 dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d", hdlc_setup); 262 if (dev) 263 dev_to_hdlc(dev)->priv = priv; 264 return dev; 265} 266 267void unregister_hdlc_device(struct net_device *dev) 268{ 269 rtnl_lock(); 270 unregister_netdevice(dev); 271 detach_hdlc_protocol(dev); 272 rtnl_unlock(); 273} 274 275 276 277int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto, 278 size_t size) 279{ 280 detach_hdlc_protocol(dev); 281 282 if (!try_module_get(proto->module)) 283 return -ENOSYS; 284 285 if (size) 286 if ((dev_to_hdlc(dev)->state = kmalloc(size, 287 GFP_KERNEL)) == NULL) { 288 printk(KERN_WARNING "Memory squeeze on" 289 " hdlc_proto_attach()\n"); 290 module_put(proto->module); 291 return -ENOBUFS; 292 } 293 dev_to_hdlc(dev)->proto = proto; 294 return 0; 295} 296 297 298void detach_hdlc_protocol(struct net_device *dev) 299{ 300 hdlc_device *hdlc = dev_to_hdlc(dev); 301 302 if (hdlc->proto) { 303 if (hdlc->proto->detach) 304 hdlc->proto->detach(dev); 305 module_put(hdlc->proto->module); 306 hdlc->proto = NULL; 307 } 308 kfree(hdlc->state); 309 hdlc->state = NULL; 310 hdlc_setup_dev(dev); 311} 312 313 314void register_hdlc_protocol(struct hdlc_proto *proto) 315{ 316 rtnl_lock(); 317 proto->next = first_proto; 318 first_proto = proto; 319 rtnl_unlock(); 320} 321 322 323void unregister_hdlc_protocol(struct hdlc_proto *proto) 324{ 325 struct hdlc_proto **p; 326 327 rtnl_lock(); 328 p = &first_proto; 329 while (*p != proto) { 330 BUG_ON(!*p); 331 p = &((*p)->next); 332 } 333 *p = proto->next; 334 rtnl_unlock(); 335} 336 337 338 339MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); 340MODULE_DESCRIPTION("HDLC support module"); 341MODULE_LICENSE("GPL v2"); 342 343EXPORT_SYMBOL(hdlc_open); 344EXPORT_SYMBOL(hdlc_close); 345EXPORT_SYMBOL(hdlc_ioctl); 346EXPORT_SYMBOL(alloc_hdlcdev); 347EXPORT_SYMBOL(unregister_hdlc_device); 348EXPORT_SYMBOL(register_hdlc_protocol); 349EXPORT_SYMBOL(unregister_hdlc_protocol); 350EXPORT_SYMBOL(attach_hdlc_protocol); 351EXPORT_SYMBOL(detach_hdlc_protocol); 352 353static struct packet_type hdlc_packet_type = { 354 .type = __constant_htons(ETH_P_HDLC), 355 .func = hdlc_rcv, 356}; 357 358 359static struct notifier_block hdlc_notifier = { 360 .notifier_call = hdlc_device_event, 361}; 362 363 364static int __init hdlc_module_init(void) 365{ 366 int result; 367 368 printk(KERN_INFO "%s\n", version); 369 if ((result = register_netdevice_notifier(&hdlc_notifier)) != 0) 370 return result; 371 dev_add_pack(&hdlc_packet_type); 372 return 0; 373} 374 375 376 377static void __exit hdlc_module_exit(void) 378{ 379 dev_remove_pack(&hdlc_packet_type); 380 unregister_netdevice_notifier(&hdlc_notifier); 381} 382 383 384module_init(hdlc_module_init); 385module_exit(hdlc_module_exit);