Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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