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