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