root/drivers/net/wan/dlci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dlci_header
  2. dlci_receive
  3. dlci_transmit
  4. dlci_config
  5. dlci_dev_ioctl
  6. dlci_change_mtu
  7. dlci_open
  8. dlci_close
  9. dlci_add
  10. dlci_del
  11. dlci_ioctl
  12. dlci_setup
  13. dlci_dev_event
  14. init_dlci
  15. dlci_exit

   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 
  53 static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
  54 
  55 static LIST_HEAD(dlci_devs);
  56 
  57 static 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 
  65 static 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 
 101 static 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 
 187 static 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 
 198 static 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 
 232 static 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 
 263 static 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 
 270 static 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 
 294 static 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 
 310 static 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 
 373 static 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         }
 418 out:
 419         rtnl_unlock();
 420         return err;
 421 }
 422 
 423 static 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 
 455 static const struct header_ops dlci_header_ops = {
 456         .create = dlci_header,
 457 };
 458 
 459 static 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 
 467 static 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 */
 485 static 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 
 508 static struct notifier_block dlci_notifier = {
 509         .notifier_call = dlci_dev_event,
 510 };
 511 
 512 static 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 
 522 static 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 
 537 module_init(init_dlci);
 538 module_exit(dlci_exit);
 539 
 540 MODULE_AUTHOR("Mike McLagan");
 541 MODULE_DESCRIPTION("Frame Relay DLCI layer");
 542 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */