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