^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * DLCI Implementation of Frame Relay protocol for Linux, according to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * RFC 1490. This generic device provides en/decapsulation for an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * underlying hardware driver. Routes & IPs are assigned to these
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * interfaces. Requires 'dlcicfg' program to create usable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * interfaces, the initial one, 'dlci' is for IOCTL use only.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Version: @(#)dlci.c 0.35 4 Jan 1997
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Author: Mike McLagan <mike.mclagan@linux.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Changes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * 0.15 Mike Mclagan Packet freeing, bug in kmalloc call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * DLCI_RET handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * 0.20 Mike McLagan More conservative on which packets
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * are returned for retry and which are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * are dropped. If DLCI_RET_DROP is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * returned from the FRAD, the packet is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * sent back to Linux for re-transmission
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * 0.25 Mike McLagan Converted to use SIOC IOCTL calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * 0.30 Jim Freeman Fixed to allow IPX traffic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * 0.35 Michael Elizabeth Fixed incorrect memcpy_fromfs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/in.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <linux/skbuff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <linux/if_arp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <linux/if_frad.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #include <net/sock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #include <asm/dma.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static LIST_HEAD(dlci_devs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static void dlci_setup(struct net_device *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * these encapsulate the RFC 1490 requirements as well as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * deal with packet transmission and reception, working with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * the upper network layers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static int dlci_header(struct sk_buff *skb, struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) unsigned short type, const void *daddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) const void *saddr, unsigned len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct frhdr hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) unsigned int hlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) char *dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) hdr.control = FRAD_I_UI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) switch (type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) case ETH_P_IP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) hdr.IP_NLPID = FRAD_P_IP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) hlen = sizeof(hdr.control) + sizeof(hdr.IP_NLPID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* feel free to add other types, if necessary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) hdr.pad = FRAD_P_PADDING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) hdr.NLPID = FRAD_P_SNAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) memset(hdr.OUI, 0, sizeof(hdr.OUI));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) hdr.PID = htons(type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) hlen = sizeof(hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) dest = skb_push(skb, hlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (!dest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) memcpy(dest, &hdr, hlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return hlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct frhdr *hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) int process, header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (!pskb_may_pull(skb, sizeof(*hdr))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) netdev_notice(dev, "invalid data no header\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) dev->stats.rx_errors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) hdr = (struct frhdr *) skb->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) process = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) header = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) skb->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (hdr->control != FRAD_I_UI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) netdev_notice(dev, "Invalid header flag 0x%02X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) hdr->control);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) dev->stats.rx_errors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) switch (hdr->IP_NLPID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) case FRAD_P_PADDING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (hdr->NLPID != FRAD_P_SNAP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) netdev_notice(dev, "Unsupported NLPID 0x%02X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) hdr->NLPID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) dev->stats.rx_errors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) netdev_notice(dev, "Unsupported organizationally unique identifier 0x%02X-%02X-%02X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) hdr->OUI[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) hdr->OUI[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) hdr->OUI[2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) dev->stats.rx_errors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* at this point, it's an EtherType frame */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) header = sizeof(struct frhdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /* Already in network order ! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) skb->protocol = hdr->PID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) process = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) case FRAD_P_IP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) header = sizeof(hdr->control) + sizeof(hdr->IP_NLPID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) skb->protocol = htons(ETH_P_IP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) process = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case FRAD_P_SNAP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) case FRAD_P_Q933:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) case FRAD_P_CLNP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) netdev_notice(dev, "Unsupported NLPID 0x%02X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) hdr->pad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) dev->stats.rx_errors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) netdev_notice(dev, "Invalid pad byte 0x%02X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) hdr->pad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) dev->stats.rx_errors++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (process)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /* we've set up the protocol, so discard the header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) skb_reset_mac_header(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) skb_pull(skb, header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) dev->stats.rx_bytes += skb->len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) netif_rx(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) dev->stats.rx_packets++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) dev_kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static netdev_tx_t dlci_transmit(struct sk_buff *skb, struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct dlci_local *dlp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (skb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct netdev_queue *txq = skb_get_tx_queue(dev, skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) netdev_start_xmit(skb, dlp->slave, txq, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return NETDEV_TX_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, int get)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) struct dlci_conf config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct dlci_local *dlp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct frad_local *flp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) dlp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) flp = netdev_priv(dlp->slave);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (!get)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (copy_from_user(&config, conf, sizeof(struct dlci_conf)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (config.flags & ~DLCI_VALID_FLAGS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) memcpy(&dlp->config, &config, sizeof(struct dlci_conf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) dlp->configured = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) err = (*flp->dlci_conf)(dlp->slave, dev, get);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (get)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) struct dlci_local *dlp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) if (!capable(CAP_NET_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) dlp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) switch (cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) case DLCI_GET_SLAVE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (!*(short *)(dev->dev_addr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) strncpy(ifr->ifr_slave, dlp->slave->name, sizeof(ifr->ifr_slave));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) case DLCI_GET_CONF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) case DLCI_SET_CONF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (!*(short *)(dev->dev_addr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return dlci_config(dev, ifr->ifr_data, cmd == DLCI_GET_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static int dlci_change_mtu(struct net_device *dev, int new_mtu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct dlci_local *dlp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return dev_set_mtu(dlp->slave, new_mtu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int dlci_open(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct dlci_local *dlp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) struct frad_local *flp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) dlp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (!*(short *)(dev->dev_addr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (!netif_running(dlp->slave))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return -ENOTCONN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) flp = netdev_priv(dlp->slave);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) err = (*flp->activate)(dlp->slave, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) netif_start_queue(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static int dlci_close(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct dlci_local *dlp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) struct frad_local *flp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) netif_stop_queue(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) dlp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) flp = netdev_priv(dlp->slave);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) (*flp->deactivate)(dlp->slave, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) static int dlci_add(struct dlci_add *dlci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct net_device *master, *slave;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) struct dlci_local *dlp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) struct frad_local *flp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) int err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) /* validate slave device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) slave = dev_get_by_name(&init_net, dlci->devname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (!slave)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (slave->type != ARPHRD_FRAD || netdev_priv(slave) == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) goto err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) /* create device name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) master = alloc_netdev(sizeof(struct dlci_local), "dlci%d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) NET_NAME_UNKNOWN, dlci_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (!master) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) goto err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) /* make sure same slave not already registered */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) list_for_each_entry(dlp, &dlci_devs, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (dlp->slave == slave) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) goto err2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) *(short *)(master->dev_addr) = dlci->dlci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) dlp = netdev_priv(master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) dlp->slave = slave;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) dlp->master = master;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) flp = netdev_priv(slave);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) err = (*flp->assoc)(slave, master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) goto err2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) err = register_netdevice(master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) goto err2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) strcpy(dlci->devname, master->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) list_add(&dlp->list, &dlci_devs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) err2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) free_netdev(master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) err1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) dev_put(slave);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) static int dlci_del(struct dlci_add *dlci)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) struct dlci_local *dlp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) struct frad_local *flp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) struct net_device *master, *slave;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /* validate slave device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) master = __dev_get_by_name(&init_net, dlci->devname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (!master) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) list_for_each_entry(dlp, &dlci_devs, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (dlp->master == master) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (!found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (netif_running(master)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) dlp = netdev_priv(master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) slave = dlp->slave;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) flp = netdev_priv(slave);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) err = (*flp->deassoc)(slave, master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (!err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) list_del(&dlp->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) unregister_netdevice(master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) dev_put(slave);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) static int dlci_ioctl(unsigned int cmd, void __user *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) struct dlci_add add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (!capable(CAP_NET_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) if (copy_from_user(&add, arg, sizeof(struct dlci_add)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) switch (cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) case SIOCADDDLCI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) err = dlci_add(&add);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) if (copy_to_user(arg, &add, sizeof(struct dlci_add)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) case SIOCDELDLCI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) err = dlci_del(&add);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static const struct header_ops dlci_header_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) .create = dlci_header,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) static const struct net_device_ops dlci_netdev_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) .ndo_open = dlci_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) .ndo_stop = dlci_close,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) .ndo_do_ioctl = dlci_dev_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) .ndo_start_xmit = dlci_transmit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) .ndo_change_mtu = dlci_change_mtu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) static void dlci_setup(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) struct dlci_local *dlp = netdev_priv(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) dev->flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) dev->header_ops = &dlci_header_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) dev->netdev_ops = &dlci_netdev_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) dev->needs_free_netdev = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) dlp->receive = dlci_receive;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) dev->type = ARPHRD_DLCI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) dev->hard_header_len = sizeof(struct frhdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) dev->addr_len = sizeof(short);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) /* if slave is unregistering, then cleanup master */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) static int dlci_dev_event(struct notifier_block *unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) unsigned long event, void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) struct net_device *dev = netdev_notifier_info_to_dev(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (dev_net(dev) != &init_net)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (event == NETDEV_UNREGISTER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) struct dlci_local *dlp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) list_for_each_entry(dlp, &dlci_devs, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (dlp->slave == dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) list_del(&dlp->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) unregister_netdevice(dlp->master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) dev_put(dlp->slave);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static struct notifier_block dlci_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) .notifier_call = dlci_dev_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static int __init init_dlci(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) dlci_ioctl_set(dlci_ioctl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) register_netdevice_notifier(&dlci_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) printk("%s.\n", version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) static void __exit dlci_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) struct dlci_local *dlp, *nxt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) dlci_ioctl_set(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) unregister_netdevice_notifier(&dlci_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) list_for_each_entry_safe(dlp, nxt, &dlci_devs, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) unregister_netdevice(dlp->master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) dev_put(dlp->slave);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) module_init(init_dlci);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) module_exit(dlci_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) MODULE_AUTHOR("Mike McLagan");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) MODULE_DESCRIPTION("Frame Relay DLCI layer");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) MODULE_LICENSE("GPL");