root/drivers/net/wan/lapbether.c

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

DEFINITIONS

This source file includes following definitions.
  1. lapbeth_get_x25_dev
  2. dev_is_ethdev
  3. lapbeth_rcv
  4. lapbeth_data_indication
  5. lapbeth_xmit
  6. lapbeth_data_transmit
  7. lapbeth_connected
  8. lapbeth_disconnected
  9. lapbeth_set_mac_address
  10. lapbeth_open
  11. lapbeth_close
  12. lapbeth_setup
  13. lapbeth_new_device
  14. lapbeth_free_device
  15. lapbeth_device_event
  16. lapbeth_init_driver
  17. lapbeth_cleanup_driver

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *      "LAPB via ethernet" driver release 001
   4  *
   5  *      This code REQUIRES 2.1.15 or higher/ NET3.038
   6  *
   7  *      This is a "pseudo" network driver to allow LAPB over Ethernet.
   8  *
   9  *      This driver can use any ethernet destination address, and can be 
  10  *      limited to accept frames from one dedicated ethernet card only.
  11  *
  12  *      History
  13  *      LAPBETH 001     Jonathan Naylor         Cloned from bpqether.c
  14  *      2000-10-29      Henner Eisen    lapb_data_indication() return status.
  15  *      2000-11-14      Henner Eisen    dev_hold/put, NETDEV_GOING_DOWN support
  16  */
  17 
  18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  19 
  20 #include <linux/errno.h>
  21 #include <linux/types.h>
  22 #include <linux/socket.h>
  23 #include <linux/in.h>
  24 #include <linux/slab.h>
  25 #include <linux/kernel.h>
  26 #include <linux/string.h>
  27 #include <linux/net.h>
  28 #include <linux/inet.h>
  29 #include <linux/netdevice.h>
  30 #include <linux/if_arp.h>
  31 #include <linux/skbuff.h>
  32 #include <net/sock.h>
  33 #include <linux/uaccess.h>
  34 #include <linux/mm.h>
  35 #include <linux/interrupt.h>
  36 #include <linux/notifier.h>
  37 #include <linux/stat.h>
  38 #include <linux/module.h>
  39 #include <linux/lapb.h>
  40 #include <linux/init.h>
  41 
  42 #include <net/x25device.h>
  43 
  44 static const u8 bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
  45 
  46 /* If this number is made larger, check that the temporary string buffer
  47  * in lapbeth_new_device is large enough to store the probe device name.*/
  48 #define MAXLAPBDEV 100
  49 
  50 struct lapbethdev {
  51         struct list_head        node;
  52         struct net_device       *ethdev;        /* link to ethernet device */
  53         struct net_device       *axdev;         /* lapbeth device (lapb#) */
  54 };
  55 
  56 static LIST_HEAD(lapbeth_devices);
  57 
  58 /* ------------------------------------------------------------------------ */
  59 
  60 /*
  61  *      Get the LAPB device for the ethernet device
  62  */
  63 static struct lapbethdev *lapbeth_get_x25_dev(struct net_device *dev)
  64 {
  65         struct lapbethdev *lapbeth;
  66 
  67         list_for_each_entry_rcu(lapbeth, &lapbeth_devices, node) {
  68                 if (lapbeth->ethdev == dev) 
  69                         return lapbeth;
  70         }
  71         return NULL;
  72 }
  73 
  74 static __inline__ int dev_is_ethdev(struct net_device *dev)
  75 {
  76         return dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5);
  77 }
  78 
  79 /* ------------------------------------------------------------------------ */
  80 
  81 /*
  82  *      Receive a LAPB frame via an ethernet interface.
  83  */
  84 static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
  85 {
  86         int len, err;
  87         struct lapbethdev *lapbeth;
  88 
  89         if (dev_net(dev) != &init_net)
  90                 goto drop;
  91 
  92         if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
  93                 return NET_RX_DROP;
  94 
  95         if (!pskb_may_pull(skb, 2))
  96                 goto drop;
  97 
  98         rcu_read_lock();
  99         lapbeth = lapbeth_get_x25_dev(dev);
 100         if (!lapbeth)
 101                 goto drop_unlock;
 102         if (!netif_running(lapbeth->axdev))
 103                 goto drop_unlock;
 104 
 105         len = skb->data[0] + skb->data[1] * 256;
 106         dev->stats.rx_packets++;
 107         dev->stats.rx_bytes += len;
 108 
 109         skb_pull(skb, 2);       /* Remove the length bytes */
 110         skb_trim(skb, len);     /* Set the length of the data */
 111 
 112         if ((err = lapb_data_received(lapbeth->axdev, skb)) != LAPB_OK) {
 113                 printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
 114                 goto drop_unlock;
 115         }
 116 out:
 117         rcu_read_unlock();
 118         return 0;
 119 drop_unlock:
 120         kfree_skb(skb);
 121         goto out;
 122 drop:
 123         kfree_skb(skb);
 124         return 0;
 125 }
 126 
 127 static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb)
 128 {
 129         unsigned char *ptr;
 130 
 131         skb_push(skb, 1);
 132 
 133         if (skb_cow(skb, 1))
 134                 return NET_RX_DROP;
 135 
 136         ptr  = skb->data;
 137         *ptr = X25_IFACE_DATA;
 138 
 139         skb->protocol = x25_type_trans(skb, dev);
 140         return netif_rx(skb);
 141 }
 142 
 143 /*
 144  *      Send a LAPB frame via an ethernet interface
 145  */
 146 static netdev_tx_t lapbeth_xmit(struct sk_buff *skb,
 147                                       struct net_device *dev)
 148 {
 149         int err;
 150 
 151         /*
 152          * Just to be *really* sure not to send anything if the interface
 153          * is down, the ethernet device may have gone.
 154          */
 155         if (!netif_running(dev))
 156                 goto drop;
 157 
 158         switch (skb->data[0]) {
 159         case X25_IFACE_DATA:
 160                 break;
 161         case X25_IFACE_CONNECT:
 162                 if ((err = lapb_connect_request(dev)) != LAPB_OK)
 163                         pr_err("lapb_connect_request error: %d\n", err);
 164                 goto drop;
 165         case X25_IFACE_DISCONNECT:
 166                 if ((err = lapb_disconnect_request(dev)) != LAPB_OK)
 167                         pr_err("lapb_disconnect_request err: %d\n", err);
 168                 /* Fall thru */
 169         default:
 170                 goto drop;
 171         }
 172 
 173         skb_pull(skb, 1);
 174 
 175         if ((err = lapb_data_request(dev, skb)) != LAPB_OK) {
 176                 pr_err("lapb_data_request error - %d\n", err);
 177                 goto drop;
 178         }
 179 out:
 180         return NETDEV_TX_OK;
 181 drop:
 182         kfree_skb(skb);
 183         goto out;
 184 }
 185 
 186 static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
 187 {
 188         struct lapbethdev *lapbeth = netdev_priv(ndev);
 189         unsigned char *ptr;
 190         struct net_device *dev;
 191         int size = skb->len;
 192 
 193         skb->protocol = htons(ETH_P_X25);
 194 
 195         ptr = skb_push(skb, 2);
 196 
 197         *ptr++ = size % 256;
 198         *ptr++ = size / 256;
 199 
 200         ndev->stats.tx_packets++;
 201         ndev->stats.tx_bytes += size;
 202 
 203         skb->dev = dev = lapbeth->ethdev;
 204 
 205         dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
 206 
 207         dev_queue_xmit(skb);
 208 }
 209 
 210 static void lapbeth_connected(struct net_device *dev, int reason)
 211 {
 212         unsigned char *ptr;
 213         struct sk_buff *skb = dev_alloc_skb(1);
 214 
 215         if (!skb) {
 216                 pr_err("out of memory\n");
 217                 return;
 218         }
 219 
 220         ptr  = skb_put(skb, 1);
 221         *ptr = X25_IFACE_CONNECT;
 222 
 223         skb->protocol = x25_type_trans(skb, dev);
 224         netif_rx(skb);
 225 }
 226 
 227 static void lapbeth_disconnected(struct net_device *dev, int reason)
 228 {
 229         unsigned char *ptr;
 230         struct sk_buff *skb = dev_alloc_skb(1);
 231 
 232         if (!skb) {
 233                 pr_err("out of memory\n");
 234                 return;
 235         }
 236 
 237         ptr  = skb_put(skb, 1);
 238         *ptr = X25_IFACE_DISCONNECT;
 239 
 240         skb->protocol = x25_type_trans(skb, dev);
 241         netif_rx(skb);
 242 }
 243 
 244 /*
 245  *      Set AX.25 callsign
 246  */
 247 static int lapbeth_set_mac_address(struct net_device *dev, void *addr)
 248 {
 249         struct sockaddr *sa = addr;
 250         memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
 251         return 0;
 252 }
 253 
 254 
 255 static const struct lapb_register_struct lapbeth_callbacks = {
 256         .connect_confirmation    = lapbeth_connected,
 257         .connect_indication      = lapbeth_connected,
 258         .disconnect_confirmation = lapbeth_disconnected,
 259         .disconnect_indication   = lapbeth_disconnected,
 260         .data_indication         = lapbeth_data_indication,
 261         .data_transmit           = lapbeth_data_transmit,
 262 };
 263 
 264 /*
 265  * open/close a device
 266  */
 267 static int lapbeth_open(struct net_device *dev)
 268 {
 269         int err;
 270 
 271         if ((err = lapb_register(dev, &lapbeth_callbacks)) != LAPB_OK) {
 272                 pr_err("lapb_register error: %d\n", err);
 273                 return -ENODEV;
 274         }
 275 
 276         netif_start_queue(dev);
 277         return 0;
 278 }
 279 
 280 static int lapbeth_close(struct net_device *dev)
 281 {
 282         int err;
 283 
 284         netif_stop_queue(dev);
 285 
 286         if ((err = lapb_unregister(dev)) != LAPB_OK)
 287                 pr_err("lapb_unregister error: %d\n", err);
 288 
 289         return 0;
 290 }
 291 
 292 /* ------------------------------------------------------------------------ */
 293 
 294 static const struct net_device_ops lapbeth_netdev_ops = {
 295         .ndo_open            = lapbeth_open,
 296         .ndo_stop            = lapbeth_close,
 297         .ndo_start_xmit      = lapbeth_xmit,
 298         .ndo_set_mac_address = lapbeth_set_mac_address,
 299 };
 300 
 301 static void lapbeth_setup(struct net_device *dev)
 302 {
 303         dev->netdev_ops      = &lapbeth_netdev_ops;
 304         dev->needs_free_netdev = true;
 305         dev->type            = ARPHRD_X25;
 306         dev->hard_header_len = 3;
 307         dev->mtu             = 1000;
 308         dev->addr_len        = 0;
 309 }
 310 
 311 /*
 312  *      Setup a new device.
 313  */
 314 static int lapbeth_new_device(struct net_device *dev)
 315 {
 316         struct net_device *ndev;
 317         struct lapbethdev *lapbeth;
 318         int rc = -ENOMEM;
 319 
 320         ASSERT_RTNL();
 321 
 322         ndev = alloc_netdev(sizeof(*lapbeth), "lapb%d", NET_NAME_UNKNOWN,
 323                             lapbeth_setup);
 324         if (!ndev)
 325                 goto out;
 326 
 327         lapbeth = netdev_priv(ndev);
 328         lapbeth->axdev = ndev;
 329 
 330         dev_hold(dev);
 331         lapbeth->ethdev = dev;
 332 
 333         rc = -EIO;
 334         if (register_netdevice(ndev))
 335                 goto fail;
 336 
 337         list_add_rcu(&lapbeth->node, &lapbeth_devices);
 338         rc = 0;
 339 out:
 340         return rc;
 341 fail:
 342         dev_put(dev);
 343         free_netdev(ndev);
 344         goto out;
 345 }
 346 
 347 /*
 348  *      Free a lapb network device.
 349  */
 350 static void lapbeth_free_device(struct lapbethdev *lapbeth)
 351 {
 352         dev_put(lapbeth->ethdev);
 353         list_del_rcu(&lapbeth->node);
 354         unregister_netdevice(lapbeth->axdev);
 355 }
 356 
 357 /*
 358  *      Handle device status changes.
 359  *
 360  * Called from notifier with RTNL held.
 361  */
 362 static int lapbeth_device_event(struct notifier_block *this,
 363                                 unsigned long event, void *ptr)
 364 {
 365         struct lapbethdev *lapbeth;
 366         struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 367 
 368         if (dev_net(dev) != &init_net)
 369                 return NOTIFY_DONE;
 370 
 371         if (!dev_is_ethdev(dev))
 372                 return NOTIFY_DONE;
 373 
 374         switch (event) {
 375         case NETDEV_UP:
 376                 /* New ethernet device -> new LAPB interface     */
 377                 if (lapbeth_get_x25_dev(dev) == NULL)
 378                         lapbeth_new_device(dev);
 379                 break;
 380         case NETDEV_DOWN:       
 381                 /* ethernet device closed -> close LAPB interface */
 382                 lapbeth = lapbeth_get_x25_dev(dev);
 383                 if (lapbeth) 
 384                         dev_close(lapbeth->axdev);
 385                 break;
 386         case NETDEV_UNREGISTER:
 387                 /* ethernet device disappears -> remove LAPB interface */
 388                 lapbeth = lapbeth_get_x25_dev(dev);
 389                 if (lapbeth)
 390                         lapbeth_free_device(lapbeth);
 391                 break;
 392         }
 393 
 394         return NOTIFY_DONE;
 395 }
 396 
 397 /* ------------------------------------------------------------------------ */
 398 
 399 static struct packet_type lapbeth_packet_type __read_mostly = {
 400         .type = cpu_to_be16(ETH_P_DEC),
 401         .func = lapbeth_rcv,
 402 };
 403 
 404 static struct notifier_block lapbeth_dev_notifier = {
 405         .notifier_call = lapbeth_device_event,
 406 };
 407 
 408 static const char banner[] __initconst =
 409         KERN_INFO "LAPB Ethernet driver version 0.02\n";
 410 
 411 static int __init lapbeth_init_driver(void)
 412 {
 413         dev_add_pack(&lapbeth_packet_type);
 414 
 415         register_netdevice_notifier(&lapbeth_dev_notifier);
 416 
 417         printk(banner);
 418 
 419         return 0;
 420 }
 421 module_init(lapbeth_init_driver);
 422 
 423 static void __exit lapbeth_cleanup_driver(void)
 424 {
 425         struct lapbethdev *lapbeth;
 426         struct list_head *entry, *tmp;
 427 
 428         dev_remove_pack(&lapbeth_packet_type);
 429         unregister_netdevice_notifier(&lapbeth_dev_notifier);
 430 
 431         rtnl_lock();
 432         list_for_each_safe(entry, tmp, &lapbeth_devices) {
 433                 lapbeth = list_entry(entry, struct lapbethdev, node);
 434 
 435                 dev_put(lapbeth->ethdev);
 436                 unregister_netdevice(lapbeth->axdev);
 437         }
 438         rtnl_unlock();
 439 }
 440 module_exit(lapbeth_cleanup_driver);
 441 
 442 MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
 443 MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver");
 444 MODULE_LICENSE("GPL");

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