133 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Generic HDLC support routines for Linux4 * HDLC Ethernet emulation support5 *6 * Copyright (C) 2002-2006 Krzysztof Halasa <khc@pm.waw.pl>7 */8 9#include <linux/errno.h>10#include <linux/etherdevice.h>11#include <linux/gfp.h>12#include <linux/hdlc.h>13#include <linux/if_arp.h>14#include <linux/inetdevice.h>15#include <linux/init.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/pkt_sched.h>19#include <linux/poll.h>20#include <linux/rtnetlink.h>21#include <linux/skbuff.h>22 23static int raw_eth_ioctl(struct net_device *dev, struct if_settings *ifs);24 25static netdev_tx_t eth_tx(struct sk_buff *skb, struct net_device *dev)26{27 int pad = ETH_ZLEN - skb->len;28 if (pad > 0) { /* Pad the frame with zeros */29 int len = skb->len;30 if (skb_tailroom(skb) < pad)31 if (pskb_expand_head(skb, 0, pad, GFP_ATOMIC)) {32 dev->stats.tx_dropped++;33 dev_kfree_skb(skb);34 return 0;35 }36 skb_put(skb, pad);37 memset(skb->data + len, 0, pad);38 }39 return dev_to_hdlc(dev)->xmit(skb, dev);40}41 42 43static struct hdlc_proto proto = {44 .type_trans = eth_type_trans,45 .xmit = eth_tx,46 .ioctl = raw_eth_ioctl,47 .module = THIS_MODULE,48};49 50 51static int raw_eth_ioctl(struct net_device *dev, struct if_settings *ifs)52{53 raw_hdlc_proto __user *raw_s = ifs->ifs_ifsu.raw_hdlc;54 const size_t size = sizeof(raw_hdlc_proto);55 raw_hdlc_proto new_settings;56 hdlc_device *hdlc = dev_to_hdlc(dev);57 unsigned int old_qlen;58 int result;59 60 switch (ifs->type) {61 case IF_GET_PROTO:62 if (dev_to_hdlc(dev)->proto != &proto)63 return -EINVAL;64 ifs->type = IF_PROTO_HDLC_ETH;65 if (ifs->size < size) {66 ifs->size = size; /* data size wanted */67 return -ENOBUFS;68 }69 if (copy_to_user(raw_s, hdlc->state, size))70 return -EFAULT;71 return 0;72 73 case IF_PROTO_HDLC_ETH:74 if (!capable(CAP_NET_ADMIN))75 return -EPERM;76 77 if (dev->flags & IFF_UP)78 return -EBUSY;79 80 if (copy_from_user(&new_settings, raw_s, size))81 return -EFAULT;82 83 if (new_settings.encoding == ENCODING_DEFAULT)84 new_settings.encoding = ENCODING_NRZ;85 86 if (new_settings.parity == PARITY_DEFAULT)87 new_settings.parity = PARITY_CRC16_PR1_CCITT;88 89 result = hdlc->attach(dev, new_settings.encoding,90 new_settings.parity);91 if (result)92 return result;93 94 result = attach_hdlc_protocol(dev, &proto,95 sizeof(raw_hdlc_proto));96 if (result)97 return result;98 memcpy(hdlc->state, &new_settings, size);99 old_qlen = dev->tx_queue_len;100 ether_setup(dev);101 dev->tx_queue_len = old_qlen;102 dev->priv_flags &= ~IFF_TX_SKB_SHARING;103 eth_hw_addr_random(dev);104 call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, dev);105 netif_dormant_off(dev);106 return 0;107 }108 109 return -EINVAL;110}111 112 113static int __init hdlc_eth_init(void)114{115 register_hdlc_protocol(&proto);116 return 0;117}118 119 120 121static void __exit hdlc_eth_exit(void)122{123 unregister_hdlc_protocol(&proto);124}125 126 127module_init(hdlc_eth_init);128module_exit(hdlc_eth_exit);129 130MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");131MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC");132MODULE_LICENSE("GPL v2");133