Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Generic HDLC support routines for Linux
0004  * HDLC Ethernet emulation support
0005  *
0006  * Copyright (C) 2002-2006 Krzysztof Halasa <khc@pm.waw.pl>
0007  */
0008 
0009 #include <linux/errno.h>
0010 #include <linux/etherdevice.h>
0011 #include <linux/gfp.h>
0012 #include <linux/hdlc.h>
0013 #include <linux/if_arp.h>
0014 #include <linux/inetdevice.h>
0015 #include <linux/init.h>
0016 #include <linux/kernel.h>
0017 #include <linux/module.h>
0018 #include <linux/pkt_sched.h>
0019 #include <linux/poll.h>
0020 #include <linux/rtnetlink.h>
0021 #include <linux/skbuff.h>
0022 
0023 static int raw_eth_ioctl(struct net_device *dev, struct if_settings *ifs);
0024 
0025 static netdev_tx_t eth_tx(struct sk_buff *skb, struct net_device *dev)
0026 {
0027     int pad = ETH_ZLEN - skb->len;
0028     if (pad > 0) {      /* Pad the frame with zeros */
0029         int len = skb->len;
0030         if (skb_tailroom(skb) < pad)
0031             if (pskb_expand_head(skb, 0, pad, GFP_ATOMIC)) {
0032                 dev->stats.tx_dropped++;
0033                 dev_kfree_skb(skb);
0034                 return 0;
0035             }
0036         skb_put(skb, pad);
0037         memset(skb->data + len, 0, pad);
0038     }
0039     return dev_to_hdlc(dev)->xmit(skb, dev);
0040 }
0041 
0042 
0043 static struct hdlc_proto proto = {
0044     .type_trans = eth_type_trans,
0045     .xmit       = eth_tx,
0046     .ioctl      = raw_eth_ioctl,
0047     .module     = THIS_MODULE,
0048 };
0049 
0050 
0051 static int raw_eth_ioctl(struct net_device *dev, struct if_settings *ifs)
0052 {
0053     raw_hdlc_proto __user *raw_s = ifs->ifs_ifsu.raw_hdlc;
0054     const size_t size = sizeof(raw_hdlc_proto);
0055     raw_hdlc_proto new_settings;
0056     hdlc_device *hdlc = dev_to_hdlc(dev);
0057     unsigned int old_qlen;
0058     int result;
0059 
0060     switch (ifs->type) {
0061     case IF_GET_PROTO:
0062         if (dev_to_hdlc(dev)->proto != &proto)
0063             return -EINVAL;
0064         ifs->type = IF_PROTO_HDLC_ETH;
0065         if (ifs->size < size) {
0066             ifs->size = size; /* data size wanted */
0067             return -ENOBUFS;
0068         }
0069         if (copy_to_user(raw_s, hdlc->state, size))
0070             return -EFAULT;
0071         return 0;
0072 
0073     case IF_PROTO_HDLC_ETH:
0074         if (!capable(CAP_NET_ADMIN))
0075             return -EPERM;
0076 
0077         if (dev->flags & IFF_UP)
0078             return -EBUSY;
0079 
0080         if (copy_from_user(&new_settings, raw_s, size))
0081             return -EFAULT;
0082 
0083         if (new_settings.encoding == ENCODING_DEFAULT)
0084             new_settings.encoding = ENCODING_NRZ;
0085 
0086         if (new_settings.parity == PARITY_DEFAULT)
0087             new_settings.parity = PARITY_CRC16_PR1_CCITT;
0088 
0089         result = hdlc->attach(dev, new_settings.encoding,
0090                       new_settings.parity);
0091         if (result)
0092             return result;
0093 
0094         result = attach_hdlc_protocol(dev, &proto,
0095                           sizeof(raw_hdlc_proto));
0096         if (result)
0097             return result;
0098         memcpy(hdlc->state, &new_settings, size);
0099         old_qlen = dev->tx_queue_len;
0100         ether_setup(dev);
0101         dev->tx_queue_len = old_qlen;
0102         dev->priv_flags &= ~IFF_TX_SKB_SHARING;
0103         eth_hw_addr_random(dev);
0104         call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev);
0105         netif_dormant_off(dev);
0106         return 0;
0107     }
0108 
0109     return -EINVAL;
0110 }
0111 
0112 
0113 static int __init hdlc_eth_init(void)
0114 {
0115     register_hdlc_protocol(&proto);
0116     return 0;
0117 }
0118 
0119 
0120 
0121 static void __exit hdlc_eth_exit(void)
0122 {
0123     unregister_hdlc_protocol(&proto);
0124 }
0125 
0126 
0127 module_init(hdlc_eth_init);
0128 module_exit(hdlc_eth_exit);
0129 
0130 MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
0131 MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC");
0132 MODULE_LICENSE("GPL v2");