380 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Generic HDLC support routines for Linux4 *5 * Copyright (C) 1999 - 2008 Krzysztof Halasa <khc@pm.waw.pl>6 *7 * Currently supported:8 * * raw IP-in-HDLC9 * * Cisco HDLC10 * * Frame Relay with ANSI or CCITT LMI (both user and network side)11 * * PPP12 * * X.2513 *14 * Use sethdlc utility to set line parameters, protocol and PVCs15 *16 * How does it work:17 * - proto->open(), close(), start(), stop() calls are serialized.18 * The order is: open, [ start, stop ... ] close ...19 * - proto->start() and stop() are called with spin_lock_irq held.20 */21 22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt23 24#include <linux/errno.h>25#include <linux/hdlc.h>26#include <linux/if_arp.h>27#include <linux/inetdevice.h>28#include <linux/init.h>29#include <linux/kernel.h>30#include <linux/module.h>31#include <linux/notifier.h>32#include <linux/pkt_sched.h>33#include <linux/poll.h>34#include <linux/rtnetlink.h>35#include <linux/skbuff.h>36#include <linux/slab.h>37#include <net/net_namespace.h>38 39static const char *version = "HDLC support module revision 1.22";40 41#undef DEBUG_LINK42 43static struct hdlc_proto *first_proto;44 45static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,46 struct packet_type *p, struct net_device *orig_dev)47{48 struct hdlc_device *hdlc;49 50 /* First make sure "dev" is an HDLC device */51 if (!(dev->priv_flags & IFF_WAN_HDLC)) {52 kfree_skb(skb);53 return NET_RX_SUCCESS;54 }55 56 hdlc = dev_to_hdlc(dev);57 58 if (!net_eq(dev_net(dev), &init_net)) {59 kfree_skb(skb);60 return 0;61 }62 63 BUG_ON(!hdlc->proto->netif_rx);64 return hdlc->proto->netif_rx(skb);65}66 67netdev_tx_t hdlc_start_xmit(struct sk_buff *skb, struct net_device *dev)68{69 hdlc_device *hdlc = dev_to_hdlc(dev);70 71 if (hdlc->proto->xmit)72 return hdlc->proto->xmit(skb, dev);73 74 return hdlc->xmit(skb, dev); /* call hardware driver directly */75}76EXPORT_SYMBOL(hdlc_start_xmit);77 78static inline void hdlc_proto_start(struct net_device *dev)79{80 hdlc_device *hdlc = dev_to_hdlc(dev);81 82 if (hdlc->proto->start)83 hdlc->proto->start(dev);84}85 86static inline void hdlc_proto_stop(struct net_device *dev)87{88 hdlc_device *hdlc = dev_to_hdlc(dev);89 90 if (hdlc->proto->stop)91 hdlc->proto->stop(dev);92}93 94static int hdlc_device_event(struct notifier_block *this, unsigned long event,95 void *ptr)96{97 struct net_device *dev = netdev_notifier_info_to_dev(ptr);98 hdlc_device *hdlc;99 unsigned long flags;100 int on;101 102 if (!net_eq(dev_net(dev), &init_net))103 return NOTIFY_DONE;104 105 if (!(dev->priv_flags & IFF_WAN_HDLC))106 return NOTIFY_DONE; /* not an HDLC device */107 108 if (event != NETDEV_CHANGE)109 return NOTIFY_DONE; /* Only interested in carrier changes */110 111 on = netif_carrier_ok(dev);112 113#ifdef DEBUG_LINK114 printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n",115 dev->name, on);116#endif117 118 hdlc = dev_to_hdlc(dev);119 spin_lock_irqsave(&hdlc->state_lock, flags);120 121 if (hdlc->carrier == on)122 goto carrier_exit; /* no change in DCD line level */123 124 hdlc->carrier = on;125 126 if (!hdlc->open)127 goto carrier_exit;128 129 if (hdlc->carrier) {130 netdev_info(dev, "Carrier detected\n");131 hdlc_proto_start(dev);132 } else {133 netdev_info(dev, "Carrier lost\n");134 hdlc_proto_stop(dev);135 }136 137carrier_exit:138 spin_unlock_irqrestore(&hdlc->state_lock, flags);139 return NOTIFY_DONE;140}141 142/* Must be called by hardware driver when HDLC device is being opened */143int hdlc_open(struct net_device *dev)144{145 hdlc_device *hdlc = dev_to_hdlc(dev);146#ifdef DEBUG_LINK147 printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name,148 hdlc->carrier, hdlc->open);149#endif150 151 if (!hdlc->proto)152 return -ENOSYS; /* no protocol attached */153 154 if (hdlc->proto->open) {155 int result = hdlc->proto->open(dev);156 157 if (result)158 return result;159 }160 161 spin_lock_irq(&hdlc->state_lock);162 163 if (hdlc->carrier) {164 netdev_info(dev, "Carrier detected\n");165 hdlc_proto_start(dev);166 } else {167 netdev_info(dev, "No carrier\n");168 }169 170 hdlc->open = 1;171 172 spin_unlock_irq(&hdlc->state_lock);173 return 0;174}175EXPORT_SYMBOL(hdlc_open);176 177/* Must be called by hardware driver when HDLC device is being closed */178void hdlc_close(struct net_device *dev)179{180 hdlc_device *hdlc = dev_to_hdlc(dev);181#ifdef DEBUG_LINK182 printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name,183 hdlc->carrier, hdlc->open);184#endif185 186 spin_lock_irq(&hdlc->state_lock);187 188 hdlc->open = 0;189 if (hdlc->carrier)190 hdlc_proto_stop(dev);191 192 spin_unlock_irq(&hdlc->state_lock);193 194 if (hdlc->proto->close)195 hdlc->proto->close(dev);196}197EXPORT_SYMBOL(hdlc_close);198 199int hdlc_ioctl(struct net_device *dev, struct if_settings *ifs)200{201 struct hdlc_proto *proto = first_proto;202 int result;203 204 if (dev_to_hdlc(dev)->proto) {205 result = dev_to_hdlc(dev)->proto->ioctl(dev, ifs);206 if (result != -EINVAL)207 return result;208 }209 210 /* Not handled by currently attached protocol (if any) */211 212 while (proto) {213 result = proto->ioctl(dev, ifs);214 if (result != -EINVAL)215 return result;216 proto = proto->next;217 }218 return -EINVAL;219}220EXPORT_SYMBOL(hdlc_ioctl);221 222static const struct header_ops hdlc_null_ops;223 224static void hdlc_setup_dev(struct net_device *dev)225{226 /* Re-init all variables changed by HDLC protocol drivers,227 * including ether_setup() called from hdlc_raw_eth.c.228 */229 dev->flags = IFF_POINTOPOINT | IFF_NOARP;230 dev->priv_flags = IFF_WAN_HDLC;231 dev->mtu = HDLC_MAX_MTU;232 dev->min_mtu = 68;233 dev->max_mtu = HDLC_MAX_MTU;234 dev->type = ARPHRD_RAWHDLC;235 dev->hard_header_len = 0;236 dev->needed_headroom = 0;237 dev->addr_len = 0;238 dev->header_ops = &hdlc_null_ops;239}240 241static void hdlc_setup(struct net_device *dev)242{243 hdlc_device *hdlc = dev_to_hdlc(dev);244 245 hdlc_setup_dev(dev);246 hdlc->carrier = 1;247 hdlc->open = 0;248 spin_lock_init(&hdlc->state_lock);249}250 251struct net_device *alloc_hdlcdev(void *priv)252{253 struct net_device *dev;254 255 dev = alloc_netdev(sizeof(struct hdlc_device), "hdlc%d",256 NET_NAME_UNKNOWN, hdlc_setup);257 if (dev)258 dev_to_hdlc(dev)->priv = priv;259 return dev;260}261EXPORT_SYMBOL(alloc_hdlcdev);262 263void unregister_hdlc_device(struct net_device *dev)264{265 rtnl_lock();266 detach_hdlc_protocol(dev);267 unregister_netdevice(dev);268 rtnl_unlock();269}270EXPORT_SYMBOL(unregister_hdlc_device);271 272int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,273 size_t size)274{275 int err;276 277 err = detach_hdlc_protocol(dev);278 if (err)279 return err;280 281 if (!try_module_get(proto->module))282 return -ENOSYS;283 284 if (size) {285 dev_to_hdlc(dev)->state = kmalloc(size, GFP_KERNEL);286 if (!dev_to_hdlc(dev)->state) {287 module_put(proto->module);288 return -ENOBUFS;289 }290 }291 dev_to_hdlc(dev)->proto = proto;292 293 return 0;294}295EXPORT_SYMBOL(attach_hdlc_protocol);296 297int detach_hdlc_protocol(struct net_device *dev)298{299 hdlc_device *hdlc = dev_to_hdlc(dev);300 int err;301 302 if (hdlc->proto) {303 err = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, dev);304 err = notifier_to_errno(err);305 if (err) {306 netdev_err(dev, "Refused to change device type\n");307 return err;308 }309 310 if (hdlc->proto->detach)311 hdlc->proto->detach(dev);312 module_put(hdlc->proto->module);313 hdlc->proto = NULL;314 }315 kfree(hdlc->state);316 hdlc->state = NULL;317 hdlc_setup_dev(dev);318 319 return 0;320}321EXPORT_SYMBOL(detach_hdlc_protocol);322 323void register_hdlc_protocol(struct hdlc_proto *proto)324{325 rtnl_lock();326 proto->next = first_proto;327 first_proto = proto;328 rtnl_unlock();329}330EXPORT_SYMBOL(register_hdlc_protocol);331 332void unregister_hdlc_protocol(struct hdlc_proto *proto)333{334 struct hdlc_proto **p;335 336 rtnl_lock();337 p = &first_proto;338 while (*p != proto) {339 BUG_ON(!*p);340 p = &((*p)->next);341 }342 *p = proto->next;343 rtnl_unlock();344}345EXPORT_SYMBOL(unregister_hdlc_protocol);346 347MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");348MODULE_DESCRIPTION("HDLC support module");349MODULE_LICENSE("GPL v2");350 351static struct packet_type hdlc_packet_type __read_mostly = {352 .type = cpu_to_be16(ETH_P_HDLC),353 .func = hdlc_rcv,354};355 356static struct notifier_block hdlc_notifier = {357 .notifier_call = hdlc_device_event,358};359 360static int __init hdlc_module_init(void)361{362 int result;363 364 pr_info("%s\n", version);365 result = register_netdevice_notifier(&hdlc_notifier);366 if (result)367 return result;368 dev_add_pack(&hdlc_packet_type);369 return 0;370}371 372static void __exit hdlc_module_exit(void)373{374 dev_remove_pack(&hdlc_packet_type);375 unregister_netdevice_notifier(&hdlc_notifier);376}377 378module_init(hdlc_module_init);379module_exit(hdlc_module_exit);380