summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/atm/Kconfig37
-rw-r--r--net/atm/Makefile4
-rw-r--r--net/atm/clip.c960
-rw-r--r--net/atm/ioctl.c14
-rw-r--r--net/atm/lec.c2274
-rw-r--r--net/atm/lec.h155
-rw-r--r--net/atm/lec_arpc.h97
-rw-r--r--net/atm/mpc.c1538
-rw-r--r--net/atm/mpc.h65
-rw-r--r--net/atm/mpoa_caches.c565
-rw-r--r--net/atm/mpoa_caches.h99
-rw-r--r--net/atm/mpoa_proc.c307
-rw-r--r--net/atm/proc.c11
-rw-r--r--net/bridge/br.c7
-rw-r--r--net/bridge/br_fdb.c29
-rw-r--r--net/bridge/br_private.h4
-rw-r--r--net/core/dev.c7
17 files changed, 0 insertions, 6173 deletions
diff --git a/net/atm/Kconfig b/net/atm/Kconfig
index 77343d57ff2a..dfdc3a8553ba 100644
--- a/net/atm/Kconfig
+++ b/net/atm/Kconfig
@@ -19,43 +19,6 @@ config ATM
of ATM. See the file <file:Documentation/networking/atm.rst> for
further details.
-config ATM_CLIP
- tristate "Classical IP over ATM"
- depends on ATM && INET
- help
- Classical IP over ATM for PVCs and SVCs, supporting InARP and
- ATMARP. If you want to communication with other IP hosts on your ATM
- network, you will typically either say Y here or to "LAN Emulation
- (LANE)" below.
-
-config ATM_CLIP_NO_ICMP
- bool "Do NOT send ICMP if no neighbour"
- depends on ATM_CLIP
- help
- Normally, an "ICMP host unreachable" message is sent if a neighbour
- cannot be reached because there is no VC to it in the kernel's
- ATMARP table. This may cause problems when ATMARP table entries are
- briefly removed during revalidation. If you say Y here, packets to
- such neighbours are silently discarded instead.
-
-config ATM_LANE
- tristate "LAN Emulation (LANE) support"
- depends on ATM
- help
- LAN Emulation emulates services of existing LANs across an ATM
- network. Besides operating as a normal ATM end station client, Linux
- LANE client can also act as an proxy client bridging packets between
- ELAN and Ethernet segments. You need LANE if you want to try MPOA.
-
-config ATM_MPOA
- tristate "Multi-Protocol Over ATM (MPOA) support"
- depends on ATM && INET && ATM_LANE!=n
- help
- Multi-Protocol Over ATM allows ATM edge devices such as routers,
- bridges and ATM attached hosts establish direct ATM VCs across
- subnetwork boundaries. These shortcut connections bypass routers
- enhancing overall network performance.
-
config ATM_BR2684
tristate "RFC1483/2684 Bridged protocols"
depends on ATM && INET
diff --git a/net/atm/Makefile b/net/atm/Makefile
index bfec0f2d83b5..484a1b1552cc 100644
--- a/net/atm/Makefile
+++ b/net/atm/Makefile
@@ -4,13 +4,9 @@
#
atm-y := addr.o pvc.o signaling.o svc.o ioctl.o common.o atm_misc.o raw.o resources.o atm_sysfs.o
-mpoa-objs := mpc.o mpoa_caches.o mpoa_proc.o
obj-$(CONFIG_ATM) += atm.o
-obj-$(CONFIG_ATM_CLIP) += clip.o
obj-$(CONFIG_ATM_BR2684) += br2684.o
atm-$(CONFIG_PROC_FS) += proc.o
-obj-$(CONFIG_ATM_LANE) += lec.o
-obj-$(CONFIG_ATM_MPOA) += mpoa.o
obj-$(CONFIG_PPPOATM) += pppoatm.o
diff --git a/net/atm/clip.c b/net/atm/clip.c
deleted file mode 100644
index 516b2214680b..000000000000
--- a/net/atm/clip.c
+++ /dev/null
@@ -1,960 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/* net/atm/clip.c - RFC1577 Classical IP over ATM */
-
-/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
-
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kernel.h> /* for UINT_MAX */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-#include <linux/timer.h>
-#include <linux/if_arp.h> /* for some manifest constants */
-#include <linux/notifier.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/atmclip.h>
-#include <linux/atmarp.h>
-#include <linux/capability.h>
-#include <linux/ip.h> /* for net/route.h */
-#include <linux/in.h> /* for struct sockaddr_in */
-#include <linux/if.h> /* for IFF_UP */
-#include <linux/inetdevice.h>
-#include <linux/bitops.h>
-#include <linux/poison.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/rcupdate.h>
-#include <linux/jhash.h>
-#include <linux/slab.h>
-#include <net/route.h> /* for struct rtable and routing */
-#include <net/icmp.h> /* icmp_send */
-#include <net/arp.h>
-#include <linux/param.h> /* for HZ */
-#include <linux/uaccess.h>
-#include <asm/byteorder.h> /* for htons etc. */
-#include <linux/atomic.h>
-
-#include "common.h"
-#include "resources.h"
-#include <net/atmclip.h>
-
-static struct net_device *clip_devs;
-static struct atm_vcc __rcu *atmarpd;
-static DEFINE_MUTEX(atmarpd_lock);
-static struct timer_list idle_timer;
-static const struct neigh_ops clip_neigh_ops;
-
-static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip)
-{
- struct sock *sk;
- struct atmarp_ctrl *ctrl;
- struct atm_vcc *vcc;
- struct sk_buff *skb;
- int err = 0;
-
- pr_debug("(%d)\n", type);
-
- rcu_read_lock();
- vcc = rcu_dereference(atmarpd);
- if (!vcc) {
- err = -EUNATCH;
- goto unlock;
- }
- skb = alloc_skb(sizeof(struct atmarp_ctrl), GFP_ATOMIC);
- if (!skb) {
- err = -ENOMEM;
- goto unlock;
- }
- ctrl = skb_put(skb, sizeof(struct atmarp_ctrl));
- ctrl->type = type;
- ctrl->itf_num = itf;
- ctrl->ip = ip;
- atm_force_charge(vcc, skb->truesize);
-
- sk = sk_atm(vcc);
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk);
-unlock:
- rcu_read_unlock();
- return err;
-}
-
-static void link_vcc(struct clip_vcc *clip_vcc, struct atmarp_entry *entry)
-{
- pr_debug("%p to entry %p (neigh %p)\n", clip_vcc, entry, entry->neigh);
- clip_vcc->entry = entry;
- clip_vcc->xoff = 0; /* @@@ may overrun buffer by one packet */
- clip_vcc->next = entry->vccs;
- entry->vccs = clip_vcc;
- entry->neigh->used = jiffies;
-}
-
-static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
-{
- struct atmarp_entry *entry = clip_vcc->entry;
- struct clip_vcc **walk;
-
- if (!entry) {
- pr_err("!clip_vcc->entry (clip_vcc %p)\n", clip_vcc);
- return;
- }
- netif_tx_lock_bh(entry->neigh->dev); /* block clip_start_xmit() */
- entry->neigh->used = jiffies;
- for (walk = &entry->vccs; *walk; walk = &(*walk)->next)
- if (*walk == clip_vcc) {
- int error;
-
- *walk = clip_vcc->next; /* atomic */
- clip_vcc->entry = NULL;
- if (clip_vcc->xoff)
- netif_wake_queue(entry->neigh->dev);
- if (entry->vccs)
- goto out;
- entry->expires = jiffies - 1;
- /* force resolution or expiration */
- error = neigh_update(entry->neigh, NULL, NUD_NONE,
- NEIGH_UPDATE_F_ADMIN, 0);
- if (error)
- pr_err("neigh_update failed with %d\n", error);
- goto out;
- }
- pr_err("ATMARP: failed (entry %p, vcc 0x%p)\n", entry, clip_vcc);
-out:
- netif_tx_unlock_bh(entry->neigh->dev);
-}
-
-/* The neighbour entry n->lock is held. */
-static int neigh_check_cb(struct neighbour *n)
-{
- struct atmarp_entry *entry = neighbour_priv(n);
- struct clip_vcc *cv;
-
- if (n->ops != &clip_neigh_ops)
- return 0;
- for (cv = entry->vccs; cv; cv = cv->next) {
- unsigned long exp = cv->last_use + cv->idle_timeout;
-
- if (cv->idle_timeout && time_after(jiffies, exp)) {
- pr_debug("releasing vcc %p->%p of entry %p\n",
- cv, cv->vcc, entry);
- vcc_release_async(cv->vcc, -ETIMEDOUT);
- }
- }
-
- if (entry->vccs || time_before(jiffies, entry->expires))
- return 0;
-
- if (refcount_read(&n->refcnt) > 1) {
- struct sk_buff *skb;
-
- pr_debug("destruction postponed with ref %d\n",
- refcount_read(&n->refcnt));
-
- while ((skb = skb_dequeue(&n->arp_queue)) != NULL)
- dev_kfree_skb(skb);
-
- return 0;
- }
-
- pr_debug("expired neigh %p\n", n);
- return 1;
-}
-
-static void idle_timer_check(struct timer_list *unused)
-{
- spin_lock(&arp_tbl.lock);
- __neigh_for_each_release(&arp_tbl, neigh_check_cb);
- mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ);
- spin_unlock(&arp_tbl.lock);
-}
-
-static int clip_arp_rcv(struct sk_buff *skb)
-{
- struct atm_vcc *vcc;
-
- pr_debug("\n");
- vcc = ATM_SKB(skb)->vcc;
- if (!vcc || !atm_charge(vcc, skb->truesize)) {
- dev_kfree_skb_any(skb);
- return 0;
- }
- pr_debug("pushing to %p\n", vcc);
- pr_debug("using %p\n", CLIP_VCC(vcc)->old_push);
- CLIP_VCC(vcc)->old_push(vcc, skb);
- return 0;
-}
-
-static const unsigned char llc_oui[] = {
- 0xaa, /* DSAP: non-ISO */
- 0xaa, /* SSAP: non-ISO */
- 0x03, /* Ctrl: Unnumbered Information Command PDU */
- 0x00, /* OUI: EtherType */
- 0x00,
- 0x00
-};
-
-static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
-
- pr_debug("\n");
-
- if (!skb) {
- pr_debug("removing VCC %p\n", clip_vcc);
- if (clip_vcc->entry)
- unlink_clip_vcc(clip_vcc);
- clip_vcc->old_push(vcc, NULL); /* pass on the bad news */
- kfree(clip_vcc);
- return;
- }
- atm_return(vcc, skb->truesize);
- if (!clip_devs) {
- kfree_skb(skb);
- return;
- }
-
- skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs;
- /* clip_vcc->entry == NULL if we don't have an IP address yet */
- if (!skb->dev) {
- dev_kfree_skb_any(skb);
- return;
- }
- ATM_SKB(skb)->vcc = vcc;
- skb_reset_mac_header(skb);
- if (!clip_vcc->encap ||
- skb->len < RFC1483LLC_LEN ||
- memcmp(skb->data, llc_oui, sizeof(llc_oui)))
- skb->protocol = htons(ETH_P_IP);
- else {
- skb->protocol = ((__be16 *)skb->data)[3];
- skb_pull(skb, RFC1483LLC_LEN);
- if (skb->protocol == htons(ETH_P_ARP)) {
- skb->dev->stats.rx_packets++;
- skb->dev->stats.rx_bytes += skb->len;
- clip_arp_rcv(skb);
- return;
- }
- }
- clip_vcc->last_use = jiffies;
- skb->dev->stats.rx_packets++;
- skb->dev->stats.rx_bytes += skb->len;
- memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
- netif_rx(skb);
-}
-
-/*
- * Note: these spinlocks _must_not_ block on non-SMP. The only goal is that
- * clip_pop is atomic with respect to the critical section in clip_start_xmit.
- */
-
-static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
- struct net_device *dev = skb->dev;
- int old;
- unsigned long flags;
-
- pr_debug("(vcc %p)\n", vcc);
- clip_vcc->old_pop(vcc, skb);
- /* skb->dev == NULL in outbound ARP packets */
- if (!dev)
- return;
- spin_lock_irqsave(&PRIV(dev)->xoff_lock, flags);
- if (atm_may_send(vcc, 0)) {
- old = xchg(&clip_vcc->xoff, 0);
- if (old)
- netif_wake_queue(dev);
- }
- spin_unlock_irqrestore(&PRIV(dev)->xoff_lock, flags);
-}
-
-static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb)
-{
- __be32 *ip = (__be32 *) neigh->primary_key;
-
- pr_debug("(neigh %p, skb %p)\n", neigh, skb);
- to_atmarpd(act_need, PRIV(neigh->dev)->number, *ip);
-}
-
-static void clip_neigh_error(struct neighbour *neigh, struct sk_buff *skb)
-{
-#ifndef CONFIG_ATM_CLIP_NO_ICMP
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
-#endif
- kfree_skb(skb);
-}
-
-static const struct neigh_ops clip_neigh_ops = {
- .family = AF_INET,
- .solicit = clip_neigh_solicit,
- .error_report = clip_neigh_error,
- .output = neigh_direct_output,
- .connected_output = neigh_direct_output,
-};
-
-static int clip_constructor(struct net_device *dev, struct neighbour *neigh)
-{
- struct atmarp_entry *entry = neighbour_priv(neigh);
-
- if (neigh->tbl->family != AF_INET)
- return -EINVAL;
-
- if (neigh->type != RTN_UNICAST)
- return -EINVAL;
-
- neigh->nud_state = NUD_NONE;
- neigh->ops = &clip_neigh_ops;
- neigh->output = neigh->ops->output;
- entry->neigh = neigh;
- entry->vccs = NULL;
- entry->expires = jiffies - 1;
-
- return 0;
-}
-
-/* @@@ copy bh locking from arp.c -- need to bh-enable atm code before */
-
-/*
- * We play with the resolve flag: 0 and 1 have the usual meaning, but -1 means
- * to allocate the neighbour entry but not to ask atmarpd for resolution. Also,
- * don't increment the usage count. This is used to create entries in
- * clip_setentry.
- */
-
-static int clip_encap(struct atm_vcc *vcc, int mode)
-{
- if (!CLIP_VCC(vcc))
- return -EBADFD;
-
- CLIP_VCC(vcc)->encap = mode;
- return 0;
-}
-
-static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct clip_priv *clip_priv = PRIV(dev);
- struct dst_entry *dst = skb_dst(skb);
- struct atmarp_entry *entry;
- struct neighbour *n;
- struct atm_vcc *vcc;
- struct rtable *rt;
- __be32 *daddr;
- int old;
- unsigned long flags;
-
- pr_debug("(skb %p)\n", skb);
- if (!dst) {
- pr_err("skb_dst(skb) == NULL\n");
- dev_kfree_skb(skb);
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- rt = dst_rtable(dst);
- if (rt->rt_gw_family == AF_INET)
- daddr = &rt->rt_gw4;
- else
- daddr = &ip_hdr(skb)->daddr;
- n = dst_neigh_lookup(dst, daddr);
- if (!n) {
- pr_err("NO NEIGHBOUR !\n");
- dev_kfree_skb(skb);
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- entry = neighbour_priv(n);
- if (!entry->vccs) {
- if (time_after(jiffies, entry->expires)) {
- /* should be resolved */
- entry->expires = jiffies + ATMARP_RETRY_DELAY * HZ;
- to_atmarpd(act_need, PRIV(dev)->number, *((__be32 *)n->primary_key));
- }
- if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS)
- skb_queue_tail(&entry->neigh->arp_queue, skb);
- else {
- dev_kfree_skb(skb);
- dev->stats.tx_dropped++;
- }
- goto out_release_neigh;
- }
- pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);
- ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
- pr_debug("using neighbour %p, vcc %p\n", n, vcc);
- if (entry->vccs->encap) {
- void *here;
-
- here = skb_push(skb, RFC1483LLC_LEN);
- memcpy(here, llc_oui, sizeof(llc_oui));
- ((__be16 *) here)[3] = skb->protocol;
- }
- atm_account_tx(vcc, skb);
- entry->vccs->last_use = jiffies;
- pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
- old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */
- if (old) {
- pr_warn("XOFF->XOFF transition\n");
- goto out_release_neigh;
- }
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
- vcc->send(vcc, skb);
- if (atm_may_send(vcc, 0)) {
- entry->vccs->xoff = 0;
- goto out_release_neigh;
- }
- spin_lock_irqsave(&clip_priv->xoff_lock, flags);
- netif_stop_queue(dev); /* XOFF -> throttle immediately */
- barrier();
- if (!entry->vccs->xoff)
- netif_start_queue(dev);
- /* Oh, we just raced with clip_pop. netif_start_queue should be
- good enough, because nothing should really be asleep because
- of the brief netif_stop_queue. If this isn't true or if it
- changes, use netif_wake_queue instead. */
- spin_unlock_irqrestore(&clip_priv->xoff_lock, flags);
-out_release_neigh:
- neigh_release(n);
- return NETDEV_TX_OK;
-}
-
-static int clip_mkip(struct atm_vcc *vcc, int timeout)
-{
- struct clip_vcc *clip_vcc;
-
- if (!vcc->push)
- return -EBADFD;
- if (vcc->user_back)
- return -EINVAL;
- clip_vcc = kmalloc_obj(struct clip_vcc);
- if (!clip_vcc)
- return -ENOMEM;
- pr_debug("%p vcc %p\n", clip_vcc, vcc);
- clip_vcc->vcc = vcc;
- vcc->user_back = clip_vcc;
- set_bit(ATM_VF_IS_CLIP, &vcc->flags);
- clip_vcc->entry = NULL;
- clip_vcc->xoff = 0;
- clip_vcc->encap = 1;
- clip_vcc->last_use = jiffies;
- clip_vcc->idle_timeout = timeout * HZ;
- clip_vcc->old_push = vcc->push;
- clip_vcc->old_pop = vcc->pop;
- vcc->push = clip_push;
- vcc->pop = clip_pop;
-
- /* re-process everything received between connection setup and MKIP */
- vcc_process_recv_queue(vcc);
-
- return 0;
-}
-
-static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
-{
- struct neighbour *neigh;
- struct atmarp_entry *entry;
- int error;
- struct clip_vcc *clip_vcc;
- struct rtable *rt;
-
- if (vcc->push != clip_push) {
- pr_warn("non-CLIP VCC\n");
- return -EBADF;
- }
- clip_vcc = CLIP_VCC(vcc);
- if (!ip) {
- if (!clip_vcc->entry) {
- pr_err("hiding hidden ATMARP entry\n");
- return 0;
- }
- pr_debug("remove\n");
- unlink_clip_vcc(clip_vcc);
- return 0;
- }
- rt = ip_route_output(&init_net, ip, 0, 0, 0, RT_SCOPE_LINK);
- if (IS_ERR(rt))
- return PTR_ERR(rt);
- neigh = __neigh_lookup(&arp_tbl, &ip, rt->dst.dev, 1);
- ip_rt_put(rt);
- if (!neigh)
- return -ENOMEM;
- entry = neighbour_priv(neigh);
- if (entry != clip_vcc->entry) {
- if (!clip_vcc->entry)
- pr_debug("add\n");
- else {
- pr_debug("update\n");
- unlink_clip_vcc(clip_vcc);
- }
- link_vcc(clip_vcc, entry);
- }
- error = neigh_update(neigh, llc_oui, NUD_PERMANENT,
- NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN, 0);
- neigh_release(neigh);
- return error;
-}
-
-static const struct net_device_ops clip_netdev_ops = {
- .ndo_start_xmit = clip_start_xmit,
- .ndo_neigh_construct = clip_constructor,
-};
-
-static void clip_setup(struct net_device *dev)
-{
- dev->netdev_ops = &clip_netdev_ops;
- dev->type = ARPHRD_ATM;
- dev->neigh_priv_len = sizeof(struct atmarp_entry);
- dev->hard_header_len = RFC1483LLC_LEN;
- dev->mtu = RFC1626_MTU;
- dev->tx_queue_len = 100; /* "normal" queue (packets) */
- /* When using a "real" qdisc, the qdisc determines the queue */
- /* length. tx_queue_len is only used for the default case, */
- /* without any more elaborate queuing. 100 is a reasonable */
- /* compromise between decent burst-tolerance and protection */
- /* against memory hogs. */
- netif_keep_dst(dev);
-}
-
-static int clip_create(int number)
-{
- struct net_device *dev;
- struct clip_priv *clip_priv;
- int error;
-
- if (number != -1) {
- for (dev = clip_devs; dev; dev = PRIV(dev)->next)
- if (PRIV(dev)->number == number)
- return -EEXIST;
- } else {
- number = 0;
- for (dev = clip_devs; dev; dev = PRIV(dev)->next)
- if (PRIV(dev)->number >= number)
- number = PRIV(dev)->number + 1;
- }
- dev = alloc_netdev(sizeof(struct clip_priv), "", NET_NAME_UNKNOWN,
- clip_setup);
- if (!dev)
- return -ENOMEM;
- clip_priv = PRIV(dev);
- sprintf(dev->name, "atm%d", number);
- spin_lock_init(&clip_priv->xoff_lock);
- clip_priv->number = number;
- error = register_netdev(dev);
- if (error) {
- free_netdev(dev);
- return error;
- }
- clip_priv->next = clip_devs;
- clip_devs = dev;
- pr_debug("registered (net:%s)\n", dev->name);
- return number;
-}
-
-static int clip_device_event(struct notifier_block *this, unsigned long event,
- void *ptr)
-{
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
- if (event == NETDEV_UNREGISTER)
- return NOTIFY_DONE;
-
- /* ignore non-CLIP devices */
- if (dev->type != ARPHRD_ATM || dev->netdev_ops != &clip_netdev_ops)
- return NOTIFY_DONE;
-
- switch (event) {
- case NETDEV_UP:
- pr_debug("NETDEV_UP\n");
- to_atmarpd(act_up, PRIV(dev)->number, 0);
- break;
- case NETDEV_GOING_DOWN:
- pr_debug("NETDEV_DOWN\n");
- to_atmarpd(act_down, PRIV(dev)->number, 0);
- break;
- case NETDEV_CHANGE:
- case NETDEV_CHANGEMTU:
- pr_debug("NETDEV_CHANGE*\n");
- to_atmarpd(act_change, PRIV(dev)->number, 0);
- break;
- }
- return NOTIFY_DONE;
-}
-
-static int clip_inet_event(struct notifier_block *this, unsigned long event,
- void *ifa)
-{
- struct in_device *in_dev;
- struct netdev_notifier_info info;
-
- in_dev = ((struct in_ifaddr *)ifa)->ifa_dev;
- /*
- * Transitions are of the down-change-up type, so it's sufficient to
- * handle the change on up.
- */
- if (event != NETDEV_UP)
- return NOTIFY_DONE;
- netdev_notifier_info_init(&info, in_dev->dev);
- return clip_device_event(this, NETDEV_CHANGE, &info);
-}
-
-static struct notifier_block clip_dev_notifier = {
- .notifier_call = clip_device_event,
-};
-
-
-
-static struct notifier_block clip_inet_notifier = {
- .notifier_call = clip_inet_event,
-};
-
-
-
-static void atmarpd_close(struct atm_vcc *vcc)
-{
- pr_debug("\n");
-
- mutex_lock(&atmarpd_lock);
- RCU_INIT_POINTER(atmarpd, NULL);
- mutex_unlock(&atmarpd_lock);
-
- synchronize_rcu();
- skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
-
- pr_debug("(done)\n");
- module_put(THIS_MODULE);
-}
-
-static int atmarpd_send(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- atm_return_tx(vcc, skb);
- dev_kfree_skb_any(skb);
- return 0;
-}
-
-static const struct atmdev_ops atmarpd_dev_ops = {
- .close = atmarpd_close,
- .send = atmarpd_send
-};
-
-
-static struct atm_dev atmarpd_dev = {
- .ops = &atmarpd_dev_ops,
- .type = "arpd",
- .number = 999,
- .lock = __SPIN_LOCK_UNLOCKED(atmarpd_dev.lock)
-};
-
-
-static int atm_init_atmarp(struct atm_vcc *vcc)
-{
- if (vcc->push == clip_push)
- return -EINVAL;
-
- mutex_lock(&atmarpd_lock);
- if (atmarpd) {
- mutex_unlock(&atmarpd_lock);
- return -EADDRINUSE;
- }
-
- mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ);
-
- rcu_assign_pointer(atmarpd, vcc);
- set_bit(ATM_VF_META, &vcc->flags);
- set_bit(ATM_VF_READY, &vcc->flags);
- /* allow replies and avoid getting closed if signaling dies */
- vcc->dev = &atmarpd_dev;
- vcc_insert_socket(sk_atm(vcc));
- vcc->push = NULL;
- vcc->pop = NULL; /* crash */
- vcc->push_oam = NULL; /* crash */
- mutex_unlock(&atmarpd_lock);
- return 0;
-}
-
-static int clip_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct atm_vcc *vcc = ATM_SD(sock);
- struct sock *sk = sock->sk;
- int err = 0;
-
- switch (cmd) {
- case SIOCMKCLIP:
- case ATMARPD_CTRL:
- case ATMARP_MKIP:
- case ATMARP_SETENTRY:
- case ATMARP_ENCAP:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- break;
- default:
- return -ENOIOCTLCMD;
- }
-
- switch (cmd) {
- case SIOCMKCLIP:
- err = clip_create(arg);
- break;
- case ATMARPD_CTRL:
- lock_sock(sk);
- err = atm_init_atmarp(vcc);
- if (!err) {
- sock->state = SS_CONNECTED;
- __module_get(THIS_MODULE);
- }
- release_sock(sk);
- break;
- case ATMARP_MKIP:
- lock_sock(sk);
- err = clip_mkip(vcc, arg);
- release_sock(sk);
- break;
- case ATMARP_SETENTRY:
- err = clip_setentry(vcc, (__force __be32)arg);
- break;
- case ATMARP_ENCAP:
- err = clip_encap(vcc, arg);
- break;
- }
- return err;
-}
-
-static struct atm_ioctl clip_ioctl_ops = {
- .owner = THIS_MODULE,
- .ioctl = clip_ioctl,
-};
-
-#ifdef CONFIG_PROC_FS
-
-static void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr)
-{
- static int code[] = { 1, 2, 10, 6, 1, 0 };
- static int e164[] = { 1, 8, 4, 6, 1, 0 };
-
- if (*addr->sas_addr.pub) {
- seq_printf(seq, "%s", addr->sas_addr.pub);
- if (*addr->sas_addr.prv)
- seq_putc(seq, '+');
- } else if (!*addr->sas_addr.prv) {
- seq_printf(seq, "%s", "(none)");
- return;
- }
- if (*addr->sas_addr.prv) {
- unsigned char *prv = addr->sas_addr.prv;
- int *fields;
- int i, j;
-
- fields = *prv == ATM_AFI_E164 ? e164 : code;
- for (i = 0; fields[i]; i++) {
- for (j = fields[i]; j; j--)
- seq_printf(seq, "%02X", *prv++);
- if (fields[i + 1])
- seq_putc(seq, '.');
- }
- }
-}
-
-/* This means the neighbour entry has no attached VCC objects. */
-#define SEQ_NO_VCC_TOKEN ((void *) 2)
-
-static void atmarp_info(struct seq_file *seq, struct neighbour *n,
- struct atmarp_entry *entry, struct clip_vcc *clip_vcc)
-{
- struct net_device *dev = n->dev;
- unsigned long exp;
- char buf[17];
- int svc, llc, off;
-
- svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) ||
- (sk_atm(clip_vcc->vcc)->sk_family == AF_ATMSVC));
-
- llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) || clip_vcc->encap);
-
- if (clip_vcc == SEQ_NO_VCC_TOKEN)
- exp = entry->neigh->used;
- else
- exp = clip_vcc->last_use;
-
- exp = (jiffies - exp) / HZ;
-
- seq_printf(seq, "%-6s%-4s%-4s%5ld ",
- dev->name, svc ? "SVC" : "PVC", llc ? "LLC" : "NULL", exp);
-
- off = scnprintf(buf, sizeof(buf) - 1, "%pI4", n->primary_key);
- while (off < 16)
- buf[off++] = ' ';
- buf[off] = '\0';
- seq_printf(seq, "%s", buf);
-
- if (clip_vcc == SEQ_NO_VCC_TOKEN) {
- if (time_before(jiffies, entry->expires))
- seq_printf(seq, "(resolving)\n");
- else
- seq_printf(seq, "(expired, ref %d)\n",
- refcount_read(&entry->neigh->refcnt));
- } else if (!svc) {
- seq_printf(seq, "%d.%d.%d\n",
- clip_vcc->vcc->dev->number,
- clip_vcc->vcc->vpi, clip_vcc->vcc->vci);
- } else {
- svc_addr(seq, &clip_vcc->vcc->remote);
- seq_putc(seq, '\n');
- }
-}
-
-struct clip_seq_state {
- /* This member must be first. */
- struct neigh_seq_state ns;
-
- /* Local to clip specific iteration. */
- struct clip_vcc *vcc;
-};
-
-static struct clip_vcc *clip_seq_next_vcc(struct atmarp_entry *e,
- struct clip_vcc *curr)
-{
- if (!curr) {
- curr = e->vccs;
- if (!curr)
- return SEQ_NO_VCC_TOKEN;
- return curr;
- }
- if (curr == SEQ_NO_VCC_TOKEN)
- return NULL;
-
- curr = curr->next;
-
- return curr;
-}
-
-static void *clip_seq_vcc_walk(struct clip_seq_state *state,
- struct atmarp_entry *e, loff_t * pos)
-{
- struct clip_vcc *vcc = state->vcc;
-
- vcc = clip_seq_next_vcc(e, vcc);
- if (vcc && pos != NULL) {
- while (*pos) {
- vcc = clip_seq_next_vcc(e, vcc);
- if (!vcc)
- break;
- --(*pos);
- }
- }
- state->vcc = vcc;
-
- return vcc;
-}
-
-static void *clip_seq_sub_iter(struct neigh_seq_state *_state,
- struct neighbour *n, loff_t * pos)
-{
- struct clip_seq_state *state = (struct clip_seq_state *)_state;
-
- if (n->dev->type != ARPHRD_ATM)
- return NULL;
-
- return clip_seq_vcc_walk(state, neighbour_priv(n), pos);
-}
-
-static void *clip_seq_start(struct seq_file *seq, loff_t * pos)
-{
- struct clip_seq_state *state = seq->private;
- state->ns.neigh_sub_iter = clip_seq_sub_iter;
- return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_NEIGH_ONLY);
-}
-
-static int clip_seq_show(struct seq_file *seq, void *v)
-{
- static char atm_arp_banner[] =
- "IPitf TypeEncp Idle IP address ATM address\n";
-
- if (v == SEQ_START_TOKEN) {
- seq_puts(seq, atm_arp_banner);
- } else {
- struct clip_seq_state *state = seq->private;
- struct clip_vcc *vcc = state->vcc;
- struct neighbour *n = v;
-
- atmarp_info(seq, n, neighbour_priv(n), vcc);
- }
- return 0;
-}
-
-static const struct seq_operations arp_seq_ops = {
- .start = clip_seq_start,
- .next = neigh_seq_next,
- .stop = neigh_seq_stop,
- .show = clip_seq_show,
-};
-#endif
-
-static void atm_clip_exit_noproc(void);
-
-static int __init atm_clip_init(void)
-{
- register_atm_ioctl(&clip_ioctl_ops);
- register_netdevice_notifier(&clip_dev_notifier);
- register_inetaddr_notifier(&clip_inet_notifier);
-
- timer_setup(&idle_timer, idle_timer_check, 0);
-
-#ifdef CONFIG_PROC_FS
- {
- struct proc_dir_entry *p;
-
- p = proc_create_net("arp", 0444, atm_proc_root, &arp_seq_ops,
- sizeof(struct clip_seq_state));
- if (!p) {
- pr_err("Unable to initialize /proc/net/atm/arp\n");
- atm_clip_exit_noproc();
- return -ENOMEM;
- }
- }
-#endif
-
- return 0;
-}
-
-static void atm_clip_exit_noproc(void)
-{
- struct net_device *dev, *next;
-
- unregister_inetaddr_notifier(&clip_inet_notifier);
- unregister_netdevice_notifier(&clip_dev_notifier);
-
- deregister_atm_ioctl(&clip_ioctl_ops);
-
- /* First, stop the idle timer, so it stops banging
- * on the table.
- */
- timer_delete_sync(&idle_timer);
-
- dev = clip_devs;
- while (dev) {
- next = PRIV(dev)->next;
- unregister_netdev(dev);
- free_netdev(dev);
- dev = next;
- }
-}
-
-static void __exit atm_clip_exit(void)
-{
- remove_proc_entry("arp", atm_proc_root);
-
- atm_clip_exit_noproc();
-}
-
-module_init(atm_clip_init);
-module_exit(atm_clip_exit);
-MODULE_AUTHOR("Werner Almesberger");
-MODULE_DESCRIPTION("Classical/IP over ATM interface");
-MODULE_LICENSE("GPL");
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c
index 0f7a39aeccc8..0f3f9ad8301f 100644
--- a/net/atm/ioctl.c
+++ b/net/atm/ioctl.c
@@ -11,14 +11,10 @@
#include <linux/net.h> /* struct socket, struct proto_ops */
#include <linux/atm.h> /* ATM stuff */
#include <linux/atmdev.h>
-#include <linux/atmclip.h> /* CLIP_*ENCAP */
#include <linux/atmarp.h> /* manifest constants */
#include <linux/capability.h>
#include <linux/sonet.h> /* for ioctls */
#include <linux/atmsvc.h>
-#include <linux/atmmpc.h>
-#include <net/atmclip.h>
-#include <linux/atmlec.h>
#include <linux/mutex.h>
#include <asm/ioctls.h>
#include <net/compat.h>
@@ -138,16 +134,6 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
}
break;
}
- case ATMMPC_CTRL:
- case ATMMPC_DATA:
- request_module("mpoa");
- break;
- case ATMARPD_CTRL:
- request_module("clip");
- break;
- case ATMLEC_CTRL:
- request_module("lec");
- break;
}
error = -ENOIOCTLCMD;
diff --git a/net/atm/lec.c b/net/atm/lec.c
deleted file mode 100644
index 10e260acf602..000000000000
--- a/net/atm/lec.c
+++ /dev/null
@@ -1,2274 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * lec.c: Lan Emulation driver
- *
- * Marko Kiiskila <mkiiskila@yahoo.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/bitops.h>
-#include <linux/capability.h>
-
-/* We are ethernet device */
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <net/sock.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-#include <net/arp.h>
-#include <net/dst.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/seq_file.h>
-
-/* And atm device */
-#include <linux/atmdev.h>
-#include <linux/atmlec.h>
-
-/* Proxy LEC knows about bridging */
-#if IS_ENABLED(CONFIG_BRIDGE)
-#include "../bridge/br_private.h"
-
-static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
-#endif
-
-/* Modular too */
-#include <linux/module.h>
-#include <linux/init.h>
-
-/* Hardening for Spectre-v1 */
-#include <linux/nospec.h>
-
-#include "lec.h"
-#include "lec_arpc.h"
-#include "resources.h"
-
-#define DUMP_PACKETS 0 /*
- * 0 = None,
- * 1 = 30 first bytes
- * 2 = Whole packet
- */
-
-#define LEC_UNRES_QUE_LEN 8 /*
- * number of tx packets to queue for a
- * single destination while waiting for SVC
- */
-
-static int lec_open(struct net_device *dev);
-static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static int lec_close(struct net_device *dev);
-static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
- const unsigned char *mac_addr);
-static int lec_arp_remove(struct lec_priv *priv,
- struct lec_arp_table *to_remove);
-/* LANE2 functions */
-static void lane2_associate_ind(struct net_device *dev, const u8 *mac_address,
- const u8 *tlvs, u32 sizeoftlvs);
-static int lane2_resolve(struct net_device *dev, const u8 *dst_mac, int force,
- u8 **tlvs, u32 *sizeoftlvs);
-static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst,
- const u8 *tlvs, u32 sizeoftlvs);
-
-static int lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr,
- unsigned long permanent);
-static void lec_arp_check_empties(struct lec_priv *priv,
- struct atm_vcc *vcc, struct sk_buff *skb);
-static void lec_arp_destroy(struct lec_priv *priv);
-static void lec_arp_init(struct lec_priv *priv);
-static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
- const unsigned char *mac_to_find,
- int is_rdesc,
- struct lec_arp_table **ret_entry);
-static void lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,
- const unsigned char *atm_addr,
- unsigned long remoteflag,
- unsigned int targetless_le_arp);
-static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id);
-static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc);
-static void lec_set_flush_tran_id(struct lec_priv *priv,
- const unsigned char *atm_addr,
- unsigned long tran_id);
-static void lec_vcc_added(struct lec_priv *priv,
- const struct atmlec_ioc *ioc_data,
- struct atm_vcc *vcc,
- void (*old_push)(struct atm_vcc *vcc,
- struct sk_buff *skb));
-static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
-
-/* must be done under lec_arp_lock */
-static inline void lec_arp_hold(struct lec_arp_table *entry)
-{
- refcount_inc(&entry->usage);
-}
-
-static inline void lec_arp_put(struct lec_arp_table *entry)
-{
- if (refcount_dec_and_test(&entry->usage))
- kfree(entry);
-}
-
-static struct lane2_ops lane2_ops = {
- .resolve = lane2_resolve, /* spec 3.1.3 */
- .associate_req = lane2_associate_req, /* spec 3.1.4 */
- .associate_indicator = NULL /* spec 3.1.5 */
-};
-
-static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-/* Device structures */
-static struct net_device *dev_lec[MAX_LEC_ITF];
-static DEFINE_MUTEX(lec_mutex);
-
-#if IS_ENABLED(CONFIG_BRIDGE)
-static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
-{
- char *buff;
- struct lec_priv *priv;
-
- /*
- * Check if this is a BPDU. If so, ask zeppelin to send
- * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit
- * as the Config BPDU has
- */
- buff = skb->data + skb->dev->hard_header_len;
- if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
- struct sock *sk;
- struct sk_buff *skb2;
- struct atmlec_msg *mesg;
-
- skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
- if (skb2 == NULL)
- return;
- skb2->len = sizeof(struct atmlec_msg);
- mesg = (struct atmlec_msg *)skb2->data;
- mesg->type = l_topology_change;
- buff += 4;
- mesg->content.normal.flag = *buff & 0x01;
- /* 0x01 is topology change */
-
- priv = netdev_priv(dev);
- struct atm_vcc *vcc;
-
- rcu_read_lock();
- vcc = rcu_dereference(priv->lecd);
- if (vcc) {
- atm_force_charge(vcc, skb2->truesize);
- sk = sk_atm(vcc);
- skb_queue_tail(&sk->sk_receive_queue, skb2);
- sk->sk_data_ready(sk);
- } else {
- dev_kfree_skb(skb2);
- }
- rcu_read_unlock();
- }
-}
-#endif /* IS_ENABLED(CONFIG_BRIDGE) */
-
-/*
- * Open/initialize the netdevice. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
- */
-
-static int lec_open(struct net_device *dev)
-{
- netif_start_queue(dev);
-
- return 0;
-}
-
-static void
-lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- struct net_device *dev = skb->dev;
- unsigned int len = skb->len;
-
- ATM_SKB(skb)->vcc = vcc;
- atm_account_tx(vcc, skb);
-
- if (vcc->send(vcc, skb) < 0) {
- dev->stats.tx_dropped++;
- return;
- }
-
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += len;
-}
-
-static void lec_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- pr_info("%s\n", dev->name);
- netif_trans_update(dev);
- netif_wake_queue(dev);
-}
-
-static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct sk_buff *skb2;
- struct lec_priv *priv = netdev_priv(dev);
- struct lecdatahdr_8023 *lec_h;
- struct atm_vcc *vcc;
- struct lec_arp_table *entry;
- unsigned char *dst;
- int min_frame_size;
- int is_rdesc;
-
- pr_debug("called\n");
- if (!rcu_access_pointer(priv->lecd)) {
- pr_info("%s:No lecd attached\n", dev->name);
- dev->stats.tx_errors++;
- netif_stop_queue(dev);
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
- (long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb),
- (long)skb_end_pointer(skb));
-#if IS_ENABLED(CONFIG_BRIDGE)
- if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0)
- lec_handle_bridge(skb, dev);
-#endif
-
- /* Make sure we have room for lec_id */
- if (skb_headroom(skb) < 2) {
- pr_debug("reallocating skb\n");
- skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
- if (unlikely(!skb2)) {
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- consume_skb(skb);
- skb = skb2;
- }
- skb_push(skb, 2);
-
- /* Put le header to place */
- lec_h = (struct lecdatahdr_8023 *)skb->data;
- lec_h->le_header = htons(priv->lecid);
-
-#if DUMP_PACKETS >= 2
-#define MAX_DUMP_SKB 99
-#elif DUMP_PACKETS >= 1
-#define MAX_DUMP_SKB 30
-#endif
-#if DUMP_PACKETS >= 1
- printk(KERN_DEBUG "%s: send datalen:%ld lecid:%4.4x\n",
- dev->name, skb->len, priv->lecid);
- print_hex_dump(KERN_DEBUG, "", DUMP_OFFSET, 16, 1,
- skb->data, min(skb->len, MAX_DUMP_SKB), true);
-#endif /* DUMP_PACKETS >= 1 */
-
- /* Minimum ethernet-frame size */
- min_frame_size = LEC_MINIMUM_8023_SIZE;
- if (skb->len < min_frame_size) {
- if ((skb->len + skb_tailroom(skb)) < min_frame_size) {
- skb2 = skb_copy_expand(skb, 0,
- min_frame_size - skb->truesize,
- GFP_ATOMIC);
- dev_kfree_skb(skb);
- if (skb2 == NULL) {
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- skb = skb2;
- }
- skb_put(skb, min_frame_size - skb->len);
- }
-
- /* Send to right vcc */
- is_rdesc = 0;
- dst = lec_h->h_dest;
- entry = NULL;
- vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
- pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p\n",
- dev->name, vcc, vcc ? vcc->flags : 0, entry);
- if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) {
- if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
- pr_debug("%s:queuing packet, MAC address %pM\n",
- dev->name, lec_h->h_dest);
- skb_queue_tail(&entry->tx_wait, skb);
- } else {
- pr_debug("%s:tx queue full or no arp entry, dropping, MAC address: %pM\n",
- dev->name, lec_h->h_dest);
- dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
- }
- goto out;
- }
-#if DUMP_PACKETS > 0
- printk(KERN_DEBUG "%s:sending to vpi:%d vci:%d\n",
- dev->name, vcc->vpi, vcc->vci);
-#endif /* DUMP_PACKETS > 0 */
-
- while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
- pr_debug("emptying tx queue, MAC address %pM\n", lec_h->h_dest);
- lec_send(vcc, skb2);
- }
-
- lec_send(vcc, skb);
-
- if (!atm_may_send(vcc, 0)) {
- struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
-
- vpriv->xoff = 1;
- netif_stop_queue(dev);
-
- /*
- * vcc->pop() might have occurred in between, making
- * the vcc usuable again. Since xmit is serialized,
- * this is the only situation we have to re-test.
- */
-
- if (atm_may_send(vcc, 0))
- netif_wake_queue(dev);
- }
-
-out:
- if (entry)
- lec_arp_put(entry);
- netif_trans_update(dev);
- return NETDEV_TX_OK;
-}
-
-/* The inverse routine to net_open(). */
-static int lec_close(struct net_device *dev)
-{
- netif_stop_queue(dev);
- return 0;
-}
-
-static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- static const u8 zero_addr[ETH_ALEN] = {};
- unsigned long flags;
- struct net_device *dev = (struct net_device *)vcc->proto_data;
- struct lec_priv *priv = netdev_priv(dev);
- struct atmlec_msg *mesg;
- struct lec_arp_table *entry;
- char *tmp; /* FIXME */
-
- WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc));
- mesg = (struct atmlec_msg *)skb->data;
- tmp = skb->data;
- tmp += sizeof(struct atmlec_msg);
- pr_debug("%s: msg from zeppelin:%d\n", dev->name, mesg->type);
- switch (mesg->type) {
- case l_set_mac_addr:
- eth_hw_addr_set(dev, mesg->content.normal.mac_addr);
- break;
- case l_del_mac_addr:
- eth_hw_addr_set(dev, zero_addr);
- break;
- case l_addr_delete:
- lec_addr_delete(priv, mesg->content.normal.atm_addr,
- mesg->content.normal.flag);
- break;
- case l_topology_change:
- priv->topology_change = mesg->content.normal.flag;
- break;
- case l_flush_complete:
- lec_flush_complete(priv, mesg->content.normal.flag);
- break;
- case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
- lec_arp_remove(priv, entry);
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-
- if (mesg->content.normal.no_source_le_narp)
- break;
- fallthrough;
- case l_arp_update:
- lec_arp_update(priv, mesg->content.normal.mac_addr,
- mesg->content.normal.atm_addr,
- mesg->content.normal.flag,
- mesg->content.normal.targetless_le_arp);
- pr_debug("in l_arp_update\n");
- if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */
- pr_debug("LANE2 3.1.5, got tlvs, size %d\n",
- mesg->sizeoftlvs);
- lane2_associate_ind(dev, mesg->content.normal.mac_addr,
- tmp, mesg->sizeoftlvs);
- }
- break;
- case l_config:
- priv->maximum_unknown_frame_count =
- mesg->content.config.maximum_unknown_frame_count;
- priv->max_unknown_frame_time =
- (mesg->content.config.max_unknown_frame_time * HZ);
- priv->max_retry_count = mesg->content.config.max_retry_count;
- priv->aging_time = (mesg->content.config.aging_time * HZ);
- priv->forward_delay_time =
- (mesg->content.config.forward_delay_time * HZ);
- priv->arp_response_time =
- (mesg->content.config.arp_response_time * HZ);
- priv->flush_timeout = (mesg->content.config.flush_timeout * HZ);
- priv->path_switching_delay =
- (mesg->content.config.path_switching_delay * HZ);
- priv->lane_version = mesg->content.config.lane_version;
- /* LANE2 */
- priv->lane2_ops = NULL;
- if (priv->lane_version > 1)
- priv->lane2_ops = &lane2_ops;
- rtnl_lock();
- if (dev_set_mtu(dev, mesg->content.config.mtu))
- pr_info("%s: change_mtu to %d failed\n",
- dev->name, mesg->content.config.mtu);
- rtnl_unlock();
- priv->is_proxy = mesg->content.config.is_proxy;
- break;
- case l_flush_tran_id:
- lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr,
- mesg->content.normal.flag);
- break;
- case l_set_lecid:
- priv->lecid =
- (unsigned short)(0xffff & mesg->content.normal.flag);
- break;
- case l_should_bridge:
-#if IS_ENABLED(CONFIG_BRIDGE)
- {
- pr_debug("%s: bridge zeppelin asks about %pM\n",
- dev->name, mesg->content.proxy.mac_addr);
-
- if (br_fdb_test_addr_hook == NULL)
- break;
-
- if (br_fdb_test_addr_hook(dev, mesg->content.proxy.mac_addr)) {
- /* hit from bridge table, send LE_ARP_RESPONSE */
- struct sk_buff *skb2;
- struct sock *sk;
-
- pr_debug("%s: entry found, responding to zeppelin\n",
- dev->name);
- skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
- if (skb2 == NULL)
- break;
- skb2->len = sizeof(struct atmlec_msg);
- skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg));
- struct atm_vcc *vcc;
-
- rcu_read_lock();
- vcc = rcu_dereference(priv->lecd);
- if (vcc) {
- atm_force_charge(vcc, skb2->truesize);
- sk = sk_atm(vcc);
- skb_queue_tail(&sk->sk_receive_queue, skb2);
- sk->sk_data_ready(sk);
- } else {
- dev_kfree_skb(skb2);
- }
- rcu_read_unlock();
- }
- }
-#endif /* IS_ENABLED(CONFIG_BRIDGE) */
- break;
- default:
- pr_info("%s: Unknown message type %d\n", dev->name, mesg->type);
- dev_kfree_skb(skb);
- return -EINVAL;
- }
- dev_kfree_skb(skb);
- return 0;
-}
-
-static void lec_atm_close(struct atm_vcc *vcc)
-{
- struct net_device *dev = (struct net_device *)vcc->proto_data;
- struct lec_priv *priv = netdev_priv(dev);
-
- rcu_assign_pointer(priv->lecd, NULL);
- synchronize_rcu();
- /* Do something needful? */
-
- netif_stop_queue(dev);
- lec_arp_destroy(priv);
-
- pr_info("%s: Shut down!\n", dev->name);
- module_put(THIS_MODULE);
-}
-
-static const struct atmdev_ops lecdev_ops = {
- .close = lec_atm_close,
- .send = lec_atm_send
-};
-
-static struct atm_dev lecatm_dev = {
- .ops = &lecdev_ops,
- .type = "lec",
- .number = 999, /* dummy device number */
- .lock = __SPIN_LOCK_UNLOCKED(lecatm_dev.lock)
-};
-
-/*
- * LANE2: new argument struct sk_buff *data contains
- * the LE_ARP based TLVs introduced in the LANE2 spec
- */
-static int
-send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
- const unsigned char *mac_addr, const unsigned char *atm_addr,
- struct sk_buff *data)
-{
- struct atm_vcc *vcc;
- struct sock *sk;
- struct sk_buff *skb;
- struct atmlec_msg *mesg;
-
- if (!priv || !rcu_access_pointer(priv->lecd))
- return -1;
-
- skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
- if (!skb)
- return -1;
- skb->len = sizeof(struct atmlec_msg);
- mesg = (struct atmlec_msg *)skb->data;
- memset(mesg, 0, sizeof(struct atmlec_msg));
- mesg->type = type;
- if (data != NULL)
- mesg->sizeoftlvs = data->len;
- if (mac_addr)
- ether_addr_copy(mesg->content.normal.mac_addr, mac_addr);
- else
- mesg->content.normal.targetless_le_arp = 1;
- if (atm_addr)
- memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
-
- rcu_read_lock();
- vcc = rcu_dereference(priv->lecd);
- if (!vcc) {
- rcu_read_unlock();
- kfree_skb(skb);
- return -1;
- }
-
- atm_force_charge(vcc, skb->truesize);
- sk = sk_atm(vcc);
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk);
-
- if (data != NULL) {
- pr_debug("about to send %d bytes of data\n", data->len);
- atm_force_charge(vcc, data->truesize);
- skb_queue_tail(&sk->sk_receive_queue, data);
- sk->sk_data_ready(sk);
- }
-
- rcu_read_unlock();
- return 0;
-}
-
-static void lec_set_multicast_list(struct net_device *dev)
-{
- /*
- * by default, all multicast frames arrive over the bus.
- * eventually support selective multicast service
- */
-}
-
-static const struct net_device_ops lec_netdev_ops = {
- .ndo_open = lec_open,
- .ndo_stop = lec_close,
- .ndo_start_xmit = lec_start_xmit,
- .ndo_tx_timeout = lec_tx_timeout,
- .ndo_set_rx_mode = lec_set_multicast_list,
-};
-
-static const unsigned char lec_ctrl_magic[] = {
- 0xff,
- 0x00,
- 0x01,
- 0x01
-};
-
-#define LEC_DATA_DIRECT_8023 2
-#define LEC_DATA_DIRECT_8025 3
-
-static int lec_is_data_direct(struct atm_vcc *vcc)
-{
- return ((vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8023) ||
- (vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025));
-}
-
-static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- unsigned long flags;
- struct net_device *dev = (struct net_device *)vcc->proto_data;
- struct lec_priv *priv = netdev_priv(dev);
-
-#if DUMP_PACKETS > 0
- printk(KERN_DEBUG "%s: vcc vpi:%d vci:%d\n",
- dev->name, vcc->vpi, vcc->vci);
-#endif
- if (!skb) {
- pr_debug("%s: null skb\n", dev->name);
- lec_vcc_close(priv, vcc);
- return;
- }
-#if DUMP_PACKETS >= 2
-#define MAX_SKB_DUMP 99
-#elif DUMP_PACKETS >= 1
-#define MAX_SKB_DUMP 30
-#endif
-#if DUMP_PACKETS > 0
- printk(KERN_DEBUG "%s: rcv datalen:%ld lecid:%4.4x\n",
- dev->name, skb->len, priv->lecid);
- print_hex_dump(KERN_DEBUG, "", DUMP_OFFSET, 16, 1,
- skb->data, min(MAX_SKB_DUMP, skb->len), true);
-#endif /* DUMP_PACKETS > 0 */
- if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) {
- /* Control frame, to daemon */
- struct sock *sk = sk_atm(vcc);
-
- pr_debug("%s: To daemon\n", dev->name);
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk);
- } else { /* Data frame, queue to protocol handlers */
- struct lec_arp_table *entry;
- unsigned char *src, *dst;
-
- atm_return(vcc, skb->truesize);
- if (*(__be16 *) skb->data == htons(priv->lecid) ||
- !rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) {
- /*
- * Probably looping back, or if lecd is missing,
- * lecd has gone down
- */
- pr_debug("Ignoring frame...\n");
- dev_kfree_skb(skb);
- return;
- }
- dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
-
- /*
- * If this is a Data Direct VCC, and the VCC does not match
- * the LE_ARP cache entry, delete the LE_ARP cache entry.
- */
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- if (lec_is_data_direct(vcc)) {
- src = ((struct lecdatahdr_8023 *)skb->data)->h_source;
- entry = lec_arp_find(priv, src);
- if (entry && entry->vcc != vcc) {
- lec_arp_remove(priv, entry);
- lec_arp_put(entry);
- }
- }
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-
- if (!(dst[0] & 0x01) && /* Never filter Multi/Broadcast */
- !priv->is_proxy && /* Proxy wants all the packets */
- memcmp(dst, dev->dev_addr, dev->addr_len)) {
- dev_kfree_skb(skb);
- return;
- }
- if (!hlist_empty(&priv->lec_arp_empty_ones))
- lec_arp_check_empties(priv, vcc, skb);
- skb_pull(skb, 2); /* skip lec_id */
- skb->protocol = eth_type_trans(skb, dev);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
- memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
- netif_rx(skb);
- }
-}
-
-static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
- struct net_device *dev = skb->dev;
-
- if (vpriv == NULL) {
- pr_info("vpriv = NULL!?!?!?\n");
- return;
- }
-
- vpriv->old_pop(vcc, skb);
-
- if (vpriv->xoff && atm_may_send(vcc, 0)) {
- vpriv->xoff = 0;
- if (netif_running(dev) && netif_queue_stopped(dev))
- netif_wake_queue(dev);
- }
-}
-
-static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
-{
- struct lec_vcc_priv *vpriv;
- int bytes_left;
- struct atmlec_ioc ioc_data;
-
- lockdep_assert_held(&lec_mutex);
- /* Lecd must be up in this case */
- bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
- if (bytes_left != 0)
- pr_info("copy from user failed for %d bytes\n", bytes_left);
- if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF)
- return -EINVAL;
- ioc_data.dev_num = array_index_nospec(ioc_data.dev_num, MAX_LEC_ITF);
- if (!dev_lec[ioc_data.dev_num])
- return -EINVAL;
- vpriv = kmalloc_obj(struct lec_vcc_priv);
- if (!vpriv)
- return -ENOMEM;
- vpriv->xoff = 0;
- vpriv->old_pop = vcc->pop;
- vcc->user_back = vpriv;
- vcc->pop = lec_pop;
- lec_vcc_added(netdev_priv(dev_lec[ioc_data.dev_num]),
- &ioc_data, vcc, vcc->push);
- vcc->proto_data = dev_lec[ioc_data.dev_num];
- vcc->push = lec_push;
- return 0;
-}
-
-static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
-{
- lockdep_assert_held(&lec_mutex);
- if (arg < 0 || arg >= MAX_LEC_ITF)
- return -EINVAL;
- arg = array_index_nospec(arg, MAX_LEC_ITF);
- if (!dev_lec[arg])
- return -EINVAL;
- vcc->proto_data = dev_lec[arg];
- return lec_mcast_make(netdev_priv(dev_lec[arg]), vcc);
-}
-
-/* Initialize device. */
-static int lecd_attach(struct atm_vcc *vcc, int arg)
-{
- int i;
- struct lec_priv *priv;
-
- lockdep_assert_held(&lec_mutex);
- if (arg < 0)
- arg = 0;
- if (arg >= MAX_LEC_ITF)
- return -EINVAL;
- i = array_index_nospec(arg, MAX_LEC_ITF);
- if (!dev_lec[i]) {
- int size;
-
- size = sizeof(struct lec_priv);
- dev_lec[i] = alloc_etherdev(size);
- if (!dev_lec[i])
- return -ENOMEM;
- dev_lec[i]->netdev_ops = &lec_netdev_ops;
- dev_lec[i]->max_mtu = 18190;
- snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
- if (register_netdev(dev_lec[i])) {
- free_netdev(dev_lec[i]);
- dev_lec[i] = NULL;
- return -EINVAL;
- }
-
- priv = netdev_priv(dev_lec[i]);
- } else {
- priv = netdev_priv(dev_lec[i]);
- if (rcu_access_pointer(priv->lecd))
- return -EADDRINUSE;
- }
- lec_arp_init(priv);
- priv->itfnum = i; /* LANE2 addition */
- rcu_assign_pointer(priv->lecd, vcc);
- vcc->dev = &lecatm_dev;
- vcc_insert_socket(sk_atm(vcc));
-
- vcc->proto_data = dev_lec[i];
- set_bit(ATM_VF_META, &vcc->flags);
- set_bit(ATM_VF_READY, &vcc->flags);
-
- /* Set default values to these variables */
- priv->maximum_unknown_frame_count = 1;
- priv->max_unknown_frame_time = (1 * HZ);
- priv->vcc_timeout_period = (1200 * HZ);
- priv->max_retry_count = 1;
- priv->aging_time = (300 * HZ);
- priv->forward_delay_time = (15 * HZ);
- priv->topology_change = 0;
- priv->arp_response_time = (1 * HZ);
- priv->flush_timeout = (4 * HZ);
- priv->path_switching_delay = (6 * HZ);
-
- if (dev_lec[i]->flags & IFF_UP)
- netif_start_queue(dev_lec[i]);
- __module_get(THIS_MODULE);
- return i;
-}
-
-#ifdef CONFIG_PROC_FS
-static const char *lec_arp_get_status_string(unsigned char status)
-{
- static const char *const lec_arp_status_string[] = {
- "ESI_UNKNOWN ",
- "ESI_ARP_PENDING ",
- "ESI_VC_PENDING ",
- "<Undefined> ",
- "ESI_FLUSH_PENDING ",
- "ESI_FORWARD_DIRECT"
- };
-
- if (status > ESI_FORWARD_DIRECT)
- status = 3; /* ESI_UNDEFINED */
- return lec_arp_status_string[status];
-}
-
-static void lec_info(struct seq_file *seq, struct lec_arp_table *entry)
-{
- seq_printf(seq, "%pM ", entry->mac_addr);
- seq_printf(seq, "%*phN ", ATM_ESA_LEN, entry->atm_addr);
- seq_printf(seq, "%s %4.4x", lec_arp_get_status_string(entry->status),
- entry->flags & 0xffff);
- if (entry->vcc)
- seq_printf(seq, "%3d %3d ", entry->vcc->vpi, entry->vcc->vci);
- else
- seq_printf(seq, " ");
- if (entry->recv_vcc) {
- seq_printf(seq, " %3d %3d", entry->recv_vcc->vpi,
- entry->recv_vcc->vci);
- }
- seq_putc(seq, '\n');
-}
-
-struct lec_state {
- unsigned long flags;
- struct lec_priv *locked;
- struct hlist_node *node;
- struct net_device *dev;
- int itf;
- int arp_table;
- int misc_table;
-};
-
-static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl,
- loff_t *l)
-{
- struct hlist_node *e = state->node;
-
- if (!e)
- e = tbl->first;
- if (e == SEQ_START_TOKEN) {
- e = tbl->first;
- --*l;
- }
-
- for (; e; e = e->next) {
- if (--*l < 0)
- break;
- }
- state->node = e;
-
- return (*l < 0) ? state : NULL;
-}
-
-static void *lec_arp_walk(struct lec_state *state, loff_t *l,
- struct lec_priv *priv)
-{
- void *v = NULL;
- int p;
-
- for (p = state->arp_table; p < LEC_ARP_TABLE_SIZE; p++) {
- v = lec_tbl_walk(state, &priv->lec_arp_tables[p], l);
- if (v)
- break;
- }
- state->arp_table = p;
- return v;
-}
-
-static void *lec_misc_walk(struct lec_state *state, loff_t *l,
- struct lec_priv *priv)
-{
- struct hlist_head *lec_misc_tables[] = {
- &priv->lec_arp_empty_ones,
- &priv->lec_no_forward,
- &priv->mcast_fwds
- };
- void *v = NULL;
- int q;
-
- for (q = state->misc_table; q < ARRAY_SIZE(lec_misc_tables); q++) {
- v = lec_tbl_walk(state, lec_misc_tables[q], l);
- if (v)
- break;
- }
- state->misc_table = q;
- return v;
-}
-
-static void *lec_priv_walk(struct lec_state *state, loff_t *l,
- struct lec_priv *priv)
-{
- if (!state->locked) {
- state->locked = priv;
- spin_lock_irqsave(&priv->lec_arp_lock, state->flags);
- }
- if (!lec_arp_walk(state, l, priv) && !lec_misc_walk(state, l, priv)) {
- spin_unlock_irqrestore(&priv->lec_arp_lock, state->flags);
- state->locked = NULL;
- /* Partial state reset for the next time we get called */
- state->arp_table = state->misc_table = 0;
- }
- return state->locked;
-}
-
-static void *lec_itf_walk(struct lec_state *state, loff_t *l)
-{
- struct net_device *dev;
- void *v;
-
- dev = state->dev ? state->dev : dev_lec[state->itf];
- v = (dev && netdev_priv(dev)) ?
- lec_priv_walk(state, l, netdev_priv(dev)) : NULL;
- if (!v && dev) {
- /* Partial state reset for the next time we get called */
- dev = NULL;
- }
- state->dev = dev;
- return v;
-}
-
-static void *lec_get_idx(struct lec_state *state, loff_t l)
-{
- void *v = NULL;
-
- for (; state->itf < MAX_LEC_ITF; state->itf++) {
- v = lec_itf_walk(state, &l);
- if (v)
- break;
- }
- return v;
-}
-
-static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
-{
- struct lec_state *state = seq->private;
-
- mutex_lock(&lec_mutex);
- state->itf = 0;
- state->dev = NULL;
- state->locked = NULL;
- state->arp_table = 0;
- state->misc_table = 0;
- state->node = SEQ_START_TOKEN;
-
- return *pos ? lec_get_idx(state, *pos) : SEQ_START_TOKEN;
-}
-
-static void lec_seq_stop(struct seq_file *seq, void *v)
-{
- struct lec_state *state = seq->private;
-
- if (state->dev) {
- spin_unlock_irqrestore(&state->locked->lec_arp_lock,
- state->flags);
- state->dev = NULL;
- }
- mutex_unlock(&lec_mutex);
-}
-
-static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- struct lec_state *state = seq->private;
-
- ++*pos;
- return lec_get_idx(state, 1);
-}
-
-static int lec_seq_show(struct seq_file *seq, void *v)
-{
- static const char lec_banner[] =
- "Itf MAC ATM destination"
- " Status Flags "
- "VPI/VCI Recv VPI/VCI\n";
-
- if (v == SEQ_START_TOKEN)
- seq_puts(seq, lec_banner);
- else {
- struct lec_state *state = seq->private;
- struct net_device *dev = state->dev;
- struct lec_arp_table *entry = hlist_entry(state->node,
- struct lec_arp_table,
- next);
-
- seq_printf(seq, "%s ", dev->name);
- lec_info(seq, entry);
- }
- return 0;
-}
-
-static const struct seq_operations lec_seq_ops = {
- .start = lec_seq_start,
- .next = lec_seq_next,
- .stop = lec_seq_stop,
- .show = lec_seq_show,
-};
-#endif
-
-static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- struct atm_vcc *vcc = ATM_SD(sock);
- int err = 0;
-
- switch (cmd) {
- case ATMLEC_CTRL:
- case ATMLEC_MCAST:
- case ATMLEC_DATA:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- break;
- default:
- return -ENOIOCTLCMD;
- }
-
- mutex_lock(&lec_mutex);
- switch (cmd) {
- case ATMLEC_CTRL:
- err = lecd_attach(vcc, (int)arg);
- if (err >= 0)
- sock->state = SS_CONNECTED;
- break;
- case ATMLEC_MCAST:
- err = lec_mcast_attach(vcc, (int)arg);
- break;
- case ATMLEC_DATA:
- err = lec_vcc_attach(vcc, (void __user *)arg);
- break;
- }
-
- mutex_unlock(&lec_mutex);
- return err;
-}
-
-static struct atm_ioctl lane_ioctl_ops = {
- .owner = THIS_MODULE,
- .ioctl = lane_ioctl,
-};
-
-static int __init lane_module_init(void)
-{
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *p;
-
- p = proc_create_seq_private("lec", 0444, atm_proc_root, &lec_seq_ops,
- sizeof(struct lec_state), NULL);
- if (!p) {
- pr_err("Unable to initialize /proc/net/atm/lec\n");
- return -ENOMEM;
- }
-#endif
-
- register_atm_ioctl(&lane_ioctl_ops);
- pr_info("lec.c: initialized\n");
- return 0;
-}
-
-static void __exit lane_module_cleanup(void)
-{
- int i;
-
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("lec", atm_proc_root);
-#endif
-
- deregister_atm_ioctl(&lane_ioctl_ops);
-
- for (i = 0; i < MAX_LEC_ITF; i++) {
- if (dev_lec[i] != NULL) {
- unregister_netdev(dev_lec[i]);
- free_netdev(dev_lec[i]);
- dev_lec[i] = NULL;
- }
- }
-}
-
-module_init(lane_module_init);
-module_exit(lane_module_cleanup);
-
-/*
- * LANE2: 3.1.3, LE_RESOLVE.request
- * Non force allocates memory and fills in *tlvs, fills in *sizeoftlvs.
- * If sizeoftlvs == NULL the default TLVs associated with this
- * lec will be used.
- * If dst_mac == NULL, targetless LE_ARP will be sent
- */
-static int lane2_resolve(struct net_device *dev, const u8 *dst_mac, int force,
- u8 **tlvs, u32 *sizeoftlvs)
-{
- unsigned long flags;
- struct lec_priv *priv = netdev_priv(dev);
- struct lec_arp_table *table;
- struct sk_buff *skb;
- int retval;
-
- if (force == 0) {
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- table = lec_arp_find(priv, dst_mac);
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- if (table == NULL)
- return -1;
-
- *tlvs = kmemdup(table->tlvs, table->sizeoftlvs, GFP_ATOMIC);
- if (*tlvs == NULL)
- return -1;
-
- *sizeoftlvs = table->sizeoftlvs;
-
- return 0;
- }
-
- if (sizeoftlvs == NULL)
- retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, NULL);
-
- else {
- skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC);
- if (skb == NULL)
- return -1;
- skb->len = *sizeoftlvs;
- skb_copy_to_linear_data(skb, *tlvs, *sizeoftlvs);
- retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb);
- }
- return retval;
-}
-
-/*
- * LANE2: 3.1.4, LE_ASSOCIATE.request
- * Associate the *tlvs with the *lan_dst address.
- * Will overwrite any previous association
- * Returns 1 for success, 0 for failure (out of memory)
- *
- */
-static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst,
- const u8 *tlvs, u32 sizeoftlvs)
-{
- int retval;
- struct sk_buff *skb;
- struct lec_priv *priv = netdev_priv(dev);
-
- if (!ether_addr_equal(lan_dst, dev->dev_addr))
- return 0; /* not our mac address */
-
- kfree(priv->tlvs); /* NULL if there was no previous association */
-
- priv->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL);
- if (priv->tlvs == NULL)
- return 0;
- priv->sizeoftlvs = sizeoftlvs;
-
- skb = alloc_skb(sizeoftlvs, GFP_ATOMIC);
- if (skb == NULL)
- return 0;
- skb->len = sizeoftlvs;
- skb_copy_to_linear_data(skb, tlvs, sizeoftlvs);
- retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
- if (retval != 0)
- pr_info("lec.c: lane2_associate_req() failed\n");
- /*
- * If the previous association has changed we must
- * somehow notify other LANE entities about the change
- */
- return 1;
-}
-
-/*
- * LANE2: 3.1.5, LE_ASSOCIATE.indication
- *
- */
-static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr,
- const u8 *tlvs, u32 sizeoftlvs)
-{
-#if 0
- int i = 0;
-#endif
- struct lec_priv *priv = netdev_priv(dev);
-#if 0 /*
- * Why have the TLVs in LE_ARP entries
- * since we do not use them? When you
- * uncomment this code, make sure the
- * TLVs get freed when entry is killed
- */
- struct lec_arp_table *entry = lec_arp_find(priv, mac_addr);
-
- if (entry == NULL)
- return; /* should not happen */
-
- kfree(entry->tlvs);
-
- entry->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL);
- if (entry->tlvs == NULL)
- return;
- entry->sizeoftlvs = sizeoftlvs;
-#endif
-#if 0
- pr_info("\n");
- pr_info("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs);
- while (i < sizeoftlvs)
- pr_cont("%02x ", tlvs[i++]);
-
- pr_cont("\n");
-#endif
-
- /* tell MPOA about the TLVs we saw */
- if (priv->lane2_ops && priv->lane2_ops->associate_indicator) {
- priv->lane2_ops->associate_indicator(dev, mac_addr,
- tlvs, sizeoftlvs);
- }
-}
-
-/*
- * Here starts what used to lec_arpc.c
- *
- * lec_arpc.c was added here when making
- * lane client modular. October 1997
- */
-
-#include <linux/types.h>
-#include <linux/timer.h>
-#include <linux/param.h>
-#include <linux/atomic.h>
-#include <linux/inetdevice.h>
-#include <net/route.h>
-
-#if 0
-#define pr_debug(format, args...)
-/*
- #define pr_debug printk
-*/
-#endif
-#define DEBUG_ARP_TABLE 0
-
-#define LEC_ARP_REFRESH_INTERVAL (3*HZ)
-
-static void lec_arp_check_expire(struct work_struct *work);
-static void lec_arp_expire_arp(struct timer_list *t);
-
-/*
- * Arp table funcs
- */
-
-#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE - 1))
-
-/*
- * Initialization of arp-cache
- */
-static void lec_arp_init(struct lec_priv *priv)
-{
- unsigned short i;
-
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
- INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
- INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
- INIT_HLIST_HEAD(&priv->lec_no_forward);
- INIT_HLIST_HEAD(&priv->mcast_fwds);
- spin_lock_init(&priv->lec_arp_lock);
- INIT_DELAYED_WORK(&priv->lec_arp_work, lec_arp_check_expire);
- schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
-}
-
-static void lec_arp_clear_vccs(struct lec_arp_table *entry)
-{
- if (entry->vcc) {
- struct atm_vcc *vcc = entry->vcc;
- struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
- struct net_device *dev = (struct net_device *)vcc->proto_data;
-
- if (vpriv) {
- vcc->pop = vpriv->old_pop;
- if (vpriv->xoff)
- netif_wake_queue(dev);
- kfree(vpriv);
- vcc->user_back = NULL;
- vcc->push = entry->old_push;
- vcc_release_async(vcc, -EPIPE);
- }
- entry->vcc = NULL;
- }
- if (entry->recv_vcc) {
- struct atm_vcc *vcc = entry->recv_vcc;
- struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
-
- if (vpriv) {
- kfree(vpriv);
- vcc->user_back = NULL;
-
- entry->recv_vcc->push = entry->old_recv_push;
- vcc_release_async(entry->recv_vcc, -EPIPE);
- }
- entry->recv_vcc = NULL;
- }
-}
-
-/*
- * Insert entry to lec_arp_table
- * LANE2: Add to the end of the list to satisfy 8.1.13
- */
-static inline void
-lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry)
-{
- struct hlist_head *tmp;
-
- tmp = &priv->lec_arp_tables[HASH(entry->mac_addr[ETH_ALEN - 1])];
- hlist_add_head(&entry->next, tmp);
-
- pr_debug("Added entry:%pM\n", entry->mac_addr);
-}
-
-/*
- * Remove entry from lec_arp_table
- */
-static int
-lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)
-{
- struct lec_arp_table *entry;
- int i, remove_vcc = 1;
-
- if (!to_remove)
- return -1;
-
- hlist_del(&to_remove->next);
- timer_delete(&to_remove->timer);
-
- /*
- * If this is the only MAC connected to this VCC,
- * also tear down the VCC
- */
- if (to_remove->status >= ESI_FLUSH_PENDING) {
- /*
- * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
- */
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- hlist_for_each_entry(entry,
- &priv->lec_arp_tables[i], next) {
- if (memcmp(to_remove->atm_addr,
- entry->atm_addr, ATM_ESA_LEN) == 0) {
- remove_vcc = 0;
- break;
- }
- }
- }
- if (remove_vcc)
- lec_arp_clear_vccs(to_remove);
- }
- skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
-
- pr_debug("Removed entry:%pM\n", to_remove->mac_addr);
- return 0;
-}
-
-#if DEBUG_ARP_TABLE
-static const char *get_status_string(unsigned char st)
-{
- switch (st) {
- case ESI_UNKNOWN:
- return "ESI_UNKNOWN";
- case ESI_ARP_PENDING:
- return "ESI_ARP_PENDING";
- case ESI_VC_PENDING:
- return "ESI_VC_PENDING";
- case ESI_FLUSH_PENDING:
- return "ESI_FLUSH_PENDING";
- case ESI_FORWARD_DIRECT:
- return "ESI_FORWARD_DIRECT";
- }
- return "<UNKNOWN>";
-}
-
-static void dump_arp_table(struct lec_priv *priv)
-{
- struct lec_arp_table *rulla;
- char buf[256];
- int i, offset;
-
- pr_info("Dump %p:\n", priv);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- hlist_for_each_entry(rulla,
- &priv->lec_arp_tables[i], next) {
- offset = 0;
- offset += sprintf(buf, "%d: %p\n", i, rulla);
- offset += sprintf(buf + offset, "Mac: %pM ",
- rulla->mac_addr);
- offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN,
- rulla->atm_addr);
- offset += sprintf(buf + offset,
- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
- rulla->vcc ? rulla->vcc->vpi : 0,
- rulla->vcc ? rulla->vcc->vci : 0,
- rulla->recv_vcc ? rulla->recv_vcc->
- vpi : 0,
- rulla->recv_vcc ? rulla->recv_vcc->
- vci : 0, rulla->last_used,
- rulla->timestamp, rulla->no_tries);
- offset +=
- sprintf(buf + offset,
- "Flags:%x, Packets_flooded:%x, Status: %s ",
- rulla->flags, rulla->packets_flooded,
- get_status_string(rulla->status));
- pr_info("%s\n", buf);
- }
- }
-
- if (!hlist_empty(&priv->lec_no_forward))
- pr_info("No forward\n");
- hlist_for_each_entry(rulla, &priv->lec_no_forward, next) {
- offset = 0;
- offset += sprintf(buf + offset, "Mac: %pM ", rulla->mac_addr);
- offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN,
- rulla->atm_addr);
- offset += sprintf(buf + offset,
- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
- rulla->vcc ? rulla->vcc->vpi : 0,
- rulla->vcc ? rulla->vcc->vci : 0,
- rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
- rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
- rulla->last_used,
- rulla->timestamp, rulla->no_tries);
- offset += sprintf(buf + offset,
- "Flags:%x, Packets_flooded:%x, Status: %s ",
- rulla->flags, rulla->packets_flooded,
- get_status_string(rulla->status));
- pr_info("%s\n", buf);
- }
-
- if (!hlist_empty(&priv->lec_arp_empty_ones))
- pr_info("Empty ones\n");
- hlist_for_each_entry(rulla, &priv->lec_arp_empty_ones, next) {
- offset = 0;
- offset += sprintf(buf + offset, "Mac: %pM ", rulla->mac_addr);
- offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN,
- rulla->atm_addr);
- offset += sprintf(buf + offset,
- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
- rulla->vcc ? rulla->vcc->vpi : 0,
- rulla->vcc ? rulla->vcc->vci : 0,
- rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
- rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
- rulla->last_used,
- rulla->timestamp, rulla->no_tries);
- offset += sprintf(buf + offset,
- "Flags:%x, Packets_flooded:%x, Status: %s ",
- rulla->flags, rulla->packets_flooded,
- get_status_string(rulla->status));
- pr_info("%s", buf);
- }
-
- if (!hlist_empty(&priv->mcast_fwds))
- pr_info("Multicast Forward VCCs\n");
- hlist_for_each_entry(rulla, &priv->mcast_fwds, next) {
- offset = 0;
- offset += sprintf(buf + offset, "Mac: %pM ", rulla->mac_addr);
- offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN,
- rulla->atm_addr);
- offset += sprintf(buf + offset,
- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
- rulla->vcc ? rulla->vcc->vpi : 0,
- rulla->vcc ? rulla->vcc->vci : 0,
- rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
- rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
- rulla->last_used,
- rulla->timestamp, rulla->no_tries);
- offset += sprintf(buf + offset,
- "Flags:%x, Packets_flooded:%x, Status: %s ",
- rulla->flags, rulla->packets_flooded,
- get_status_string(rulla->status));
- pr_info("%s\n", buf);
- }
-
-}
-#else
-#define dump_arp_table(priv) do { } while (0)
-#endif
-
-/*
- * Destruction of arp-cache
- */
-static void lec_arp_destroy(struct lec_priv *priv)
-{
- unsigned long flags;
- struct hlist_node *next;
- struct lec_arp_table *entry;
- int i;
-
- cancel_delayed_work_sync(&priv->lec_arp_work);
-
- /*
- * Remove all entries
- */
-
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- hlist_for_each_entry_safe(entry, next,
- &priv->lec_arp_tables[i], next) {
- lec_arp_remove(priv, entry);
- lec_arp_put(entry);
- }
- INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
- }
-
- hlist_for_each_entry_safe(entry, next,
- &priv->lec_arp_empty_ones, next) {
- timer_delete_sync(&entry->timer);
- lec_arp_clear_vccs(entry);
- hlist_del(&entry->next);
- lec_arp_put(entry);
- }
- INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
-
- hlist_for_each_entry_safe(entry, next,
- &priv->lec_no_forward, next) {
- timer_delete_sync(&entry->timer);
- lec_arp_clear_vccs(entry);
- hlist_del(&entry->next);
- lec_arp_put(entry);
- }
- INIT_HLIST_HEAD(&priv->lec_no_forward);
-
- hlist_for_each_entry_safe(entry, next, &priv->mcast_fwds, next) {
- /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
- lec_arp_clear_vccs(entry);
- hlist_del(&entry->next);
- lec_arp_put(entry);
- }
- INIT_HLIST_HEAD(&priv->mcast_fwds);
- priv->mcast_vcc = NULL;
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-}
-
-/*
- * Find entry by mac_address
- */
-static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
- const unsigned char *mac_addr)
-{
- struct hlist_head *head;
- struct lec_arp_table *entry;
-
- pr_debug("%pM\n", mac_addr);
-
- head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])];
- hlist_for_each_entry(entry, head, next) {
- if (ether_addr_equal(mac_addr, entry->mac_addr))
- return entry;
- }
- return NULL;
-}
-
-static struct lec_arp_table *make_entry(struct lec_priv *priv,
- const unsigned char *mac_addr)
-{
- struct lec_arp_table *to_return;
-
- to_return = kzalloc_obj(struct lec_arp_table, GFP_ATOMIC);
- if (!to_return)
- return NULL;
- ether_addr_copy(to_return->mac_addr, mac_addr);
- INIT_HLIST_NODE(&to_return->next);
- timer_setup(&to_return->timer, lec_arp_expire_arp, 0);
- to_return->last_used = jiffies;
- to_return->priv = priv;
- skb_queue_head_init(&to_return->tx_wait);
- refcount_set(&to_return->usage, 1);
- return to_return;
-}
-
-/* Arp sent timer expired */
-static void lec_arp_expire_arp(struct timer_list *t)
-{
- struct lec_arp_table *entry;
-
- entry = timer_container_of(entry, t, timer);
-
- pr_debug("\n");
- if (entry->status == ESI_ARP_PENDING) {
- if (entry->no_tries <= entry->priv->max_retry_count) {
- if (entry->is_rdesc)
- send_to_lecd(entry->priv, l_rdesc_arp_xmt,
- entry->mac_addr, NULL, NULL);
- else
- send_to_lecd(entry->priv, l_arp_xmt,
- entry->mac_addr, NULL, NULL);
- entry->no_tries++;
- }
- mod_timer(&entry->timer, jiffies + (1 * HZ));
- }
-}
-
-/* Unknown/unused vcc expire, remove associated entry */
-static void lec_arp_expire_vcc(struct timer_list *t)
-{
- unsigned long flags;
- struct lec_arp_table *to_remove = timer_container_of(to_remove, t,
- timer);
- struct lec_priv *priv = to_remove->priv;
-
- timer_delete(&to_remove->timer);
-
- pr_debug("%p %p: vpi:%d vci:%d\n",
- to_remove, priv,
- to_remove->vcc ? to_remove->recv_vcc->vpi : 0,
- to_remove->vcc ? to_remove->recv_vcc->vci : 0);
-
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- hlist_del(&to_remove->next);
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-
- lec_arp_clear_vccs(to_remove);
- lec_arp_put(to_remove);
-}
-
-static bool __lec_arp_check_expire(struct lec_arp_table *entry,
- unsigned long now,
- struct lec_priv *priv)
-{
- unsigned long time_to_check;
-
- if ((entry->flags) & LEC_REMOTE_FLAG && priv->topology_change)
- time_to_check = priv->forward_delay_time;
- else
- time_to_check = priv->aging_time;
-
- pr_debug("About to expire: %lx - %lx > %lx\n",
- now, entry->last_used, time_to_check);
- if (time_after(now, entry->last_used + time_to_check) &&
- !(entry->flags & LEC_PERMANENT_FLAG) &&
- !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */
- /* Remove entry */
- pr_debug("Entry timed out\n");
- lec_arp_remove(priv, entry);
- lec_arp_put(entry);
- } else {
- /* Something else */
- if ((entry->status == ESI_VC_PENDING ||
- entry->status == ESI_ARP_PENDING) &&
- time_after_eq(now, entry->timestamp +
- priv->max_unknown_frame_time)) {
- entry->timestamp = jiffies;
- entry->packets_flooded = 0;
- if (entry->status == ESI_VC_PENDING)
- send_to_lecd(priv, l_svc_setup,
- entry->mac_addr,
- entry->atm_addr,
- NULL);
- }
- if (entry->status == ESI_FLUSH_PENDING &&
- time_after_eq(now, entry->timestamp +
- priv->path_switching_delay)) {
- lec_arp_hold(entry);
- return true;
- }
- }
-
- return false;
-}
-/*
- * Expire entries.
- * 1. Re-set timer
- * 2. For each entry, delete entries that have aged past the age limit.
- * 3. For each entry, depending on the status of the entry, perform
- * the following maintenance.
- * a. If status is ESI_VC_PENDING or ESI_ARP_PENDING then if the
- * tick_count is above the max_unknown_frame_time, clear
- * the tick_count to zero and clear the packets_flooded counter
- * to zero. This supports the packet rate limit per address
- * while flooding unknowns.
- * b. If the status is ESI_FLUSH_PENDING and the tick_count is greater
- * than or equal to the path_switching_delay, change the status
- * to ESI_FORWARD_DIRECT. This causes the flush period to end
- * regardless of the progress of the flush protocol.
- */
-static void lec_arp_check_expire(struct work_struct *work)
-{
- unsigned long flags;
- struct lec_priv *priv =
- container_of(work, struct lec_priv, lec_arp_work.work);
- struct hlist_node *next;
- struct lec_arp_table *entry;
- unsigned long now;
- int i;
-
- pr_debug("%p\n", priv);
- now = jiffies;
-restart:
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- hlist_for_each_entry_safe(entry, next,
- &priv->lec_arp_tables[i], next) {
- if (__lec_arp_check_expire(entry, now, priv)) {
- struct sk_buff *skb;
- struct atm_vcc *vcc = entry->vcc;
-
- spin_unlock_irqrestore(&priv->lec_arp_lock,
- flags);
- while ((skb = skb_dequeue(&entry->tx_wait)))
- lec_send(vcc, skb);
- entry->last_used = jiffies;
- entry->status = ESI_FORWARD_DIRECT;
- lec_arp_put(entry);
-
- goto restart;
- }
- }
- }
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-
- schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
-}
-
-/*
- * Try to find vcc where mac_address is attached.
- *
- */
-static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
- const unsigned char *mac_to_find,
- int is_rdesc,
- struct lec_arp_table **ret_entry)
-{
- unsigned long flags;
- struct lec_arp_table *entry;
- struct atm_vcc *found;
-
- if (mac_to_find[0] & 0x01) {
- switch (priv->lane_version) {
- case 1:
- return priv->mcast_vcc;
- case 2: /* LANE2 wants arp for multicast addresses */
- if (ether_addr_equal(mac_to_find, bus_mac))
- return priv->mcast_vcc;
- break;
- default:
- break;
- }
- }
-
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- entry = lec_arp_find(priv, mac_to_find);
-
- if (entry) {
- if (entry->status == ESI_FORWARD_DIRECT) {
- /* Connection Ok */
- entry->last_used = jiffies;
- lec_arp_hold(entry);
- *ret_entry = entry;
- found = entry->vcc;
- goto out;
- }
- /*
- * If the LE_ARP cache entry is still pending, reset count to 0
- * so another LE_ARP request can be made for this frame.
- */
- if (entry->status == ESI_ARP_PENDING)
- entry->no_tries = 0;
- /*
- * Data direct VC not yet set up, check to see if the unknown
- * frame count is greater than the limit. If the limit has
- * not been reached, allow the caller to send packet to
- * BUS.
- */
- if (entry->status != ESI_FLUSH_PENDING &&
- entry->packets_flooded <
- priv->maximum_unknown_frame_count) {
- entry->packets_flooded++;
- pr_debug("Flooding..\n");
- found = priv->mcast_vcc;
- goto out;
- }
- /*
- * We got here because entry->status == ESI_FLUSH_PENDING
- * or BUS flood limit was reached for an entry which is
- * in ESI_ARP_PENDING or ESI_VC_PENDING state.
- */
- lec_arp_hold(entry);
- *ret_entry = entry;
- pr_debug("entry->status %d entry->vcc %p\n", entry->status,
- entry->vcc);
- found = NULL;
- } else {
- /* No matching entry was found */
- entry = make_entry(priv, mac_to_find);
- pr_debug("Making entry\n");
- if (!entry) {
- found = priv->mcast_vcc;
- goto out;
- }
- lec_arp_add(priv, entry);
- /* We want arp-request(s) to be sent */
- entry->packets_flooded = 1;
- entry->status = ESI_ARP_PENDING;
- entry->no_tries = 1;
- entry->last_used = entry->timestamp = jiffies;
- entry->is_rdesc = is_rdesc;
- if (entry->is_rdesc)
- send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL,
- NULL);
- else
- send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL);
- entry->timer.expires = jiffies + (1 * HZ);
- entry->timer.function = lec_arp_expire_arp;
- add_timer(&entry->timer);
- found = priv->mcast_vcc;
- }
-
-out:
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- return found;
-}
-
-static int
-lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr,
- unsigned long permanent)
-{
- unsigned long flags;
- struct hlist_node *next;
- struct lec_arp_table *entry;
- int i;
-
- pr_debug("\n");
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- hlist_for_each_entry_safe(entry, next,
- &priv->lec_arp_tables[i], next) {
- if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) &&
- (permanent ||
- !(entry->flags & LEC_PERMANENT_FLAG))) {
- lec_arp_remove(priv, entry);
- lec_arp_put(entry);
- }
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- return 0;
- }
- }
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- return -1;
-}
-
-/*
- * Notifies: Response to arp_request (atm_addr != NULL)
- */
-static void
-lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,
- const unsigned char *atm_addr, unsigned long remoteflag,
- unsigned int targetless_le_arp)
-{
- unsigned long flags;
- struct hlist_node *next;
- struct lec_arp_table *entry, *tmp;
- int i;
-
- pr_debug("%smac:%pM\n",
- (targetless_le_arp) ? "targetless " : "", mac_addr);
-
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- entry = lec_arp_find(priv, mac_addr);
- if (entry == NULL && targetless_le_arp)
- goto out; /*
- * LANE2: ignore targetless LE_ARPs for which
- * we have no entry in the cache. 7.1.30
- */
- if (!hlist_empty(&priv->lec_arp_empty_ones)) {
- hlist_for_each_entry_safe(entry, next,
- &priv->lec_arp_empty_ones, next) {
- if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) {
- hlist_del(&entry->next);
- timer_delete(&entry->timer);
- tmp = lec_arp_find(priv, mac_addr);
- if (tmp) {
- timer_delete(&tmp->timer);
- tmp->status = ESI_FORWARD_DIRECT;
- memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN);
- tmp->vcc = entry->vcc;
- tmp->old_push = entry->old_push;
- tmp->last_used = jiffies;
- timer_delete(&entry->timer);
- lec_arp_put(entry);
- entry = tmp;
- } else {
- entry->status = ESI_FORWARD_DIRECT;
- ether_addr_copy(entry->mac_addr,
- mac_addr);
- entry->last_used = jiffies;
- lec_arp_add(priv, entry);
- }
- if (remoteflag)
- entry->flags |= LEC_REMOTE_FLAG;
- else
- entry->flags &= ~LEC_REMOTE_FLAG;
- pr_debug("After update\n");
- dump_arp_table(priv);
- goto out;
- }
- }
- }
-
- entry = lec_arp_find(priv, mac_addr);
- if (!entry) {
- entry = make_entry(priv, mac_addr);
- if (!entry)
- goto out;
- entry->status = ESI_UNKNOWN;
- lec_arp_add(priv, entry);
- /* Temporary, changes before end of function */
- }
- memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
- timer_delete(&entry->timer);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- hlist_for_each_entry(tmp,
- &priv->lec_arp_tables[i], next) {
- if (entry != tmp &&
- !memcmp(tmp->atm_addr, atm_addr, ATM_ESA_LEN)) {
- /* Vcc to this host exists */
- if (tmp->status > ESI_VC_PENDING) {
- /*
- * ESI_FLUSH_PENDING,
- * ESI_FORWARD_DIRECT
- */
- entry->vcc = tmp->vcc;
- entry->old_push = tmp->old_push;
- }
- entry->status = tmp->status;
- break;
- }
- }
- }
- if (remoteflag)
- entry->flags |= LEC_REMOTE_FLAG;
- else
- entry->flags &= ~LEC_REMOTE_FLAG;
- if (entry->status == ESI_ARP_PENDING || entry->status == ESI_UNKNOWN) {
- entry->status = ESI_VC_PENDING;
- send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL);
- }
- pr_debug("After update2\n");
- dump_arp_table(priv);
-out:
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-}
-
-/*
- * Notifies: Vcc setup ready
- */
-static void
-lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,
- struct atm_vcc *vcc,
- void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb))
-{
- unsigned long flags;
- struct lec_arp_table *entry;
- int i, found_entry = 0;
-
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
- if (ioc_data->receive == 2) {
- pr_debug("LEC_ARP: Attaching mcast forward\n");
-#if 0
- entry = lec_arp_find(priv, bus_mac);
- if (!entry) {
- pr_info("LEC_ARP: Multicast entry not found!\n");
- goto out;
- }
- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
- entry->recv_vcc = vcc;
- entry->old_recv_push = old_push;
-#endif
- entry = make_entry(priv, bus_mac);
- if (entry == NULL)
- goto out;
- timer_delete(&entry->timer);
- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
- entry->recv_vcc = vcc;
- entry->old_recv_push = old_push;
- hlist_add_head(&entry->next, &priv->mcast_fwds);
- goto out;
- } else if (ioc_data->receive == 1) {
- /*
- * Vcc which we don't want to make default vcc,
- * attach it anyway.
- */
- pr_debug("LEC_ARP:Attaching data direct, not default: %*phN\n",
- ATM_ESA_LEN, ioc_data->atm_addr);
- entry = make_entry(priv, bus_mac);
- if (entry == NULL)
- goto out;
- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
- eth_zero_addr(entry->mac_addr);
- entry->recv_vcc = vcc;
- entry->old_recv_push = old_push;
- entry->status = ESI_UNKNOWN;
- entry->timer.expires = jiffies + priv->vcc_timeout_period;
- entry->timer.function = lec_arp_expire_vcc;
- hlist_add_head(&entry->next, &priv->lec_no_forward);
- add_timer(&entry->timer);
- dump_arp_table(priv);
- goto out;
- }
- pr_debug("LEC_ARP:Attaching data direct, default: %*phN\n",
- ATM_ESA_LEN, ioc_data->atm_addr);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- hlist_for_each_entry(entry,
- &priv->lec_arp_tables[i], next) {
- if (memcmp
- (ioc_data->atm_addr, entry->atm_addr,
- ATM_ESA_LEN) == 0) {
- pr_debug("LEC_ARP: Attaching data direct\n");
- pr_debug("Currently -> Vcc: %d, Rvcc:%d\n",
- entry->vcc ? entry->vcc->vci : 0,
- entry->recv_vcc ? entry->recv_vcc->
- vci : 0);
- found_entry = 1;
- timer_delete(&entry->timer);
- entry->vcc = vcc;
- entry->old_push = old_push;
- if (entry->status == ESI_VC_PENDING) {
- if (priv->maximum_unknown_frame_count
- == 0)
- entry->status =
- ESI_FORWARD_DIRECT;
- else {
- entry->timestamp = jiffies;
- entry->status =
- ESI_FLUSH_PENDING;
-#if 0
- send_to_lecd(priv, l_flush_xmt,
- NULL,
- entry->atm_addr,
- NULL);
-#endif
- }
- } else {
- /*
- * They were forming a connection
- * to us, and we to them. Our
- * ATM address is numerically lower
- * than theirs, so we make connection
- * we formed into default VCC (8.1.11).
- * Connection they made gets torn
- * down. This might confuse some
- * clients. Can be changed if
- * someone reports trouble...
- */
- ;
- }
- }
- }
- }
- if (found_entry) {
- pr_debug("After vcc was added\n");
- dump_arp_table(priv);
- goto out;
- }
- /*
- * Not found, snatch address from first data packet that arrives
- * from this vcc
- */
- entry = make_entry(priv, bus_mac);
- if (!entry)
- goto out;
- entry->vcc = vcc;
- entry->old_push = old_push;
- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
- eth_zero_addr(entry->mac_addr);
- entry->status = ESI_UNKNOWN;
- hlist_add_head(&entry->next, &priv->lec_arp_empty_ones);
- entry->timer.expires = jiffies + priv->vcc_timeout_period;
- entry->timer.function = lec_arp_expire_vcc;
- add_timer(&entry->timer);
- pr_debug("After vcc was added\n");
- dump_arp_table(priv);
-out:
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-}
-
-static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
-{
- unsigned long flags;
- struct lec_arp_table *entry;
- int i;
-
- pr_debug("%lx\n", tran_id);
-restart:
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- hlist_for_each_entry(entry,
- &priv->lec_arp_tables[i], next) {
- if (entry->flush_tran_id == tran_id &&
- entry->status == ESI_FLUSH_PENDING) {
- struct sk_buff *skb;
- struct atm_vcc *vcc = entry->vcc;
-
- lec_arp_hold(entry);
- spin_unlock_irqrestore(&priv->lec_arp_lock,
- flags);
- while ((skb = skb_dequeue(&entry->tx_wait)))
- lec_send(vcc, skb);
- entry->last_used = jiffies;
- entry->status = ESI_FORWARD_DIRECT;
- lec_arp_put(entry);
- pr_debug("LEC_ARP: Flushed\n");
- goto restart;
- }
- }
- }
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- dump_arp_table(priv);
-}
-
-static void
-lec_set_flush_tran_id(struct lec_priv *priv,
- const unsigned char *atm_addr, unsigned long tran_id)
-{
- unsigned long flags;
- struct lec_arp_table *entry;
- int i;
-
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
- hlist_for_each_entry(entry,
- &priv->lec_arp_tables[i], next) {
- if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
- entry->flush_tran_id = tran_id;
- pr_debug("Set flush transaction id to %lx for %p\n",
- tran_id, entry);
- }
- }
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-}
-
-static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
-{
- unsigned long flags;
- unsigned char mac_addr[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
- struct lec_arp_table *to_add;
- struct lec_vcc_priv *vpriv;
- int err = 0;
-
- vpriv = kmalloc_obj(struct lec_vcc_priv);
- if (!vpriv)
- return -ENOMEM;
- vpriv->xoff = 0;
- vpriv->old_pop = vcc->pop;
- vcc->user_back = vpriv;
- vcc->pop = lec_pop;
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- to_add = make_entry(priv, mac_addr);
- if (!to_add) {
- vcc->pop = vpriv->old_pop;
- kfree(vpriv);
- err = -ENOMEM;
- goto out;
- }
- memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
- to_add->status = ESI_FORWARD_DIRECT;
- to_add->flags |= LEC_PERMANENT_FLAG;
- to_add->vcc = vcc;
- to_add->old_push = vcc->push;
- vcc->push = lec_push;
- priv->mcast_vcc = vcc;
- lec_arp_add(priv, to_add);
-out:
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- return err;
-}
-
-static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
-{
- unsigned long flags;
- struct hlist_node *next;
- struct lec_arp_table *entry;
- int i;
-
- pr_debug("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n", vcc->vpi, vcc->vci);
- dump_arp_table(priv);
-
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
-
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- hlist_for_each_entry_safe(entry, next,
- &priv->lec_arp_tables[i], next) {
- if (vcc == entry->vcc) {
- lec_arp_remove(priv, entry);
- lec_arp_put(entry);
- if (priv->mcast_vcc == vcc)
- priv->mcast_vcc = NULL;
- }
- }
- }
-
- hlist_for_each_entry_safe(entry, next,
- &priv->lec_arp_empty_ones, next) {
- if (entry->vcc == vcc) {
- lec_arp_clear_vccs(entry);
- timer_delete(&entry->timer);
- hlist_del(&entry->next);
- lec_arp_put(entry);
- }
- }
-
- hlist_for_each_entry_safe(entry, next,
- &priv->lec_no_forward, next) {
- if (entry->recv_vcc == vcc) {
- lec_arp_clear_vccs(entry);
- timer_delete(&entry->timer);
- hlist_del(&entry->next);
- lec_arp_put(entry);
- }
- }
-
- hlist_for_each_entry_safe(entry, next, &priv->mcast_fwds, next) {
- if (entry->recv_vcc == vcc) {
- lec_arp_clear_vccs(entry);
- /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
- hlist_del(&entry->next);
- lec_arp_put(entry);
- }
- }
-
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- dump_arp_table(priv);
-}
-
-static void
-lec_arp_check_empties(struct lec_priv *priv,
- struct atm_vcc *vcc, struct sk_buff *skb)
-{
- unsigned long flags;
- struct hlist_node *next;
- struct lec_arp_table *entry, *tmp;
- struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
- unsigned char *src = hdr->h_source;
-
- spin_lock_irqsave(&priv->lec_arp_lock, flags);
- hlist_for_each_entry_safe(entry, next,
- &priv->lec_arp_empty_ones, next) {
- if (vcc == entry->vcc) {
- timer_delete(&entry->timer);
- ether_addr_copy(entry->mac_addr, src);
- entry->status = ESI_FORWARD_DIRECT;
- entry->last_used = jiffies;
- /* We might have got an entry */
- tmp = lec_arp_find(priv, src);
- if (tmp) {
- lec_arp_remove(priv, tmp);
- lec_arp_put(tmp);
- }
- hlist_del(&entry->next);
- lec_arp_add(priv, entry);
- goto out;
- }
- }
- pr_debug("LEC_ARP: Arp_check_empties: entry not found!\n");
-out:
- spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
-}
-
-MODULE_DESCRIPTION("ATM LAN Emulation (LANE) support");
-MODULE_LICENSE("GPL");
diff --git a/net/atm/lec.h b/net/atm/lec.h
deleted file mode 100644
index ec85709bf818..000000000000
--- a/net/atm/lec.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Lan Emulation client header file
- *
- * Marko Kiiskila <mkiiskila@yahoo.com>
- */
-
-#ifndef _LEC_H_
-#define _LEC_H_
-
-#include <linux/atmdev.h>
-#include <linux/netdevice.h>
-#include <linux/atmlec.h>
-
-#define LEC_HEADER_LEN 16
-
-struct lecdatahdr_8023 {
- __be16 le_header;
- unsigned char h_dest[ETH_ALEN];
- unsigned char h_source[ETH_ALEN];
- __be16 h_type;
-};
-
-struct lecdatahdr_8025 {
- __be16 le_header;
- unsigned char ac_pad;
- unsigned char fc;
- unsigned char h_dest[ETH_ALEN];
- unsigned char h_source[ETH_ALEN];
-};
-
-#define LEC_MINIMUM_8023_SIZE 62
-#define LEC_MINIMUM_8025_SIZE 16
-
-/*
- * Operations that LANE2 capable device can do. Two first functions
- * are used to make the device do things. See spec 3.1.3 and 3.1.4.
- *
- * The third function is intended for the MPOA component sitting on
- * top of the LANE device. The MPOA component assigns it's own function
- * to (*associate_indicator)() and the LANE device will use that
- * function to tell about TLVs it sees floating through.
- *
- */
-struct lane2_ops {
- int (*resolve) (struct net_device *dev, const u8 *dst_mac, int force,
- u8 **tlvs, u32 *sizeoftlvs);
- int (*associate_req) (struct net_device *dev, const u8 *lan_dst,
- const u8 *tlvs, u32 sizeoftlvs);
- void (*associate_indicator) (struct net_device *dev, const u8 *mac_addr,
- const u8 *tlvs, u32 sizeoftlvs);
-};
-
-/*
- * ATM LAN Emulation supports both LLC & Dix Ethernet EtherType
- * frames.
- *
- * 1. Dix Ethernet EtherType frames encoded by placing EtherType
- * field in h_type field. Data follows immediately after header.
- * 2. LLC Data frames whose total length, including LLC field and data,
- * but not padding required to meet the minimum data frame length,
- * is less than ETH_P_802_3_MIN MUST be encoded by placing that length
- * in the h_type field. The LLC field follows header immediately.
- * 3. LLC data frames longer than this maximum MUST be encoded by placing
- * the value 0 in the h_type field.
- *
- */
-
-/* Hash table size */
-#define LEC_ARP_TABLE_SIZE 16
-
-struct lec_priv {
- unsigned short lecid; /* Lecid of this client */
- struct hlist_head lec_arp_empty_ones;
- /* Used for storing VCC's that don't have a MAC address attached yet */
- struct hlist_head lec_arp_tables[LEC_ARP_TABLE_SIZE];
- /* Actual LE ARP table */
- struct hlist_head lec_no_forward;
- /*
- * Used for storing VCC's (and forward packets from) which are to
- * age out by not using them to forward packets.
- * This is because to some LE clients there will be 2 VCCs. Only
- * one of them gets used.
- */
- struct hlist_head mcast_fwds;
- /*
- * With LANEv2 it is possible that BUS (or a special multicast server)
- * establishes multiple Multicast Forward VCCs to us. This list
- * collects all those VCCs. LANEv1 client has only one item in this
- * list. These entries are not aged out.
- */
- spinlock_t lec_arp_lock;
- struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
- struct atm_vcc __rcu *lecd;
- struct delayed_work lec_arp_work; /* C10 */
- unsigned int maximum_unknown_frame_count;
- /*
- * Within the period of time defined by this variable, the client will send
- * no more than C10 frames to BUS for a given unicast destination. (C11)
- */
- unsigned long max_unknown_frame_time;
- /*
- * If no traffic has been sent in this vcc for this period of time,
- * vcc will be torn down (C12)
- */
- unsigned long vcc_timeout_period;
- /*
- * An LE Client MUST not retry an LE_ARP_REQUEST for a
- * given frame's LAN Destination more than maximum retry count times,
- * after the first LEC_ARP_REQUEST (C13)
- */
- unsigned short max_retry_count;
- /*
- * Max time the client will maintain an entry in its arp cache in
- * absence of a verification of that relationship (C17)
- */
- unsigned long aging_time;
- /*
- * Max time the client will maintain an entry in cache when
- * topology change flag is true (C18)
- */
- unsigned long forward_delay_time; /* Topology change flag (C19) */
- int topology_change;
- /*
- * Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE
- * cycle to take (C20)
- */
- unsigned long arp_response_time;
- /*
- * Time limit ot wait to receive an LE_FLUSH_RESPONSE after the
- * LE_FLUSH_REQUEST has been sent before taking recover action. (C21)
- */
- unsigned long flush_timeout;
- /* The time since sending a frame to the bus after which the
- * LE Client may assume that the frame has been either discarded or
- * delivered to the recipient (C22)
- */
- unsigned long path_switching_delay;
-
- u8 *tlvs; /* LANE2: TLVs are new */
- u32 sizeoftlvs; /* The size of the tlv array in bytes */
- int lane_version; /* LANE2 */
- int itfnum; /* e.g. 2 for lec2, 5 for lec5 */
- struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */
- int is_proxy; /* bridge between ATM and Ethernet */
-};
-
-struct lec_vcc_priv {
- void (*old_pop) (struct atm_vcc *vcc, struct sk_buff *skb);
- int xoff;
-};
-
-#define LEC_VCC_PRIV(vcc) ((struct lec_vcc_priv *)((vcc)->user_back))
-
-#endif /* _LEC_H_ */
diff --git a/net/atm/lec_arpc.h b/net/atm/lec_arpc.h
deleted file mode 100644
index 39115fe074c4..000000000000
--- a/net/atm/lec_arpc.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Lec arp cache
- *
- * Marko Kiiskila <mkiiskila@yahoo.com>
- */
-#ifndef _LEC_ARP_H_
-#define _LEC_ARP_H_
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/if_ether.h>
-#include <linux/atmlec.h>
-
-struct lec_arp_table {
- struct hlist_node next; /* Linked entry list */
- unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */
- unsigned char mac_addr[ETH_ALEN]; /* Mac address */
- int is_rdesc; /* Mac address is a route descriptor */
- struct atm_vcc *vcc; /* Vcc this entry is attached */
- struct atm_vcc *recv_vcc; /* Vcc we receive data from */
-
- void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb);
- /* Push that leads to daemon */
-
- void (*old_recv_push) (struct atm_vcc *vcc, struct sk_buff *skb);
- /* Push that leads to daemon */
-
- unsigned long last_used; /* For expiry */
- unsigned long timestamp; /* Used for various timestamping things:
- * 1. FLUSH started
- * (status=ESI_FLUSH_PENDING)
- * 2. Counting to
- * max_unknown_frame_time
- * (status=ESI_ARP_PENDING||
- * status=ESI_VC_PENDING)
- */
- unsigned char no_tries; /* No of times arp retry has been tried */
- unsigned char status; /* Status of this entry */
- unsigned short flags; /* Flags for this entry */
- unsigned short packets_flooded; /* Data packets flooded */
- unsigned long flush_tran_id; /* Transaction id in flush protocol */
- struct timer_list timer; /* Arping timer */
- struct lec_priv *priv; /* Pointer back */
- u8 *tlvs;
- u32 sizeoftlvs; /*
- * LANE2: Each MAC address can have TLVs
- * associated with it. sizeoftlvs tells
- * the length of the tlvs array
- */
- struct sk_buff_head tx_wait; /* wait queue for outgoing packets */
- refcount_t usage; /* usage count */
-};
-
-/*
- * LANE2: Template tlv struct for accessing
- * the tlvs in the lec_arp_table->tlvs array
- */
-struct tlv {
- u32 type;
- u8 length;
- u8 value[255];
-};
-
-/* Status fields */
-#define ESI_UNKNOWN 0 /*
- * Next packet sent to this mac address
- * causes ARP-request to be sent
- */
-#define ESI_ARP_PENDING 1 /*
- * There is no ATM address associated with this
- * 48-bit address. The LE-ARP protocol is in
- * progress.
- */
-#define ESI_VC_PENDING 2 /*
- * There is a valid ATM address associated with
- * this 48-bit address but there is no VC set
- * up to that ATM address. The signaling
- * protocol is in process.
- */
-#define ESI_FLUSH_PENDING 4 /*
- * The LEC has been notified of the FLUSH_START
- * status and it is assumed that the flush
- * protocol is in process.
- */
-#define ESI_FORWARD_DIRECT 5 /*
- * Either the Path Switching Delay (C22) has
- * elapsed or the LEC has notified the Mapping
- * that the flush protocol has completed. In
- * either case, it is safe to forward packets
- * to this address via the data direct VC.
- */
-
-/* Flag values */
-#define LEC_REMOTE_FLAG 0x0001
-#define LEC_PERMANENT_FLAG 0x0002
-
-#endif /* _LEC_ARP_H_ */
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
deleted file mode 100644
index ce8e9780373b..000000000000
--- a/net/atm/mpc.c
+++ /dev/null
@@ -1,1538 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/capability.h>
-#include <linux/seq_file.h>
-
-/* We are an ethernet device */
-#include <linux/if_ether.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <net/sock.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <linux/uaccess.h>
-#include <asm/byteorder.h>
-#include <net/checksum.h> /* for ip_fast_csum() */
-#include <net/arp.h>
-#include <net/dst.h>
-#include <linux/proc_fs.h>
-
-/* And atm device */
-#include <linux/atmdev.h>
-#include <linux/atmlec.h>
-#include <linux/atmmpc.h>
-/* Modular too */
-#include <linux/module.h>
-
-#include "lec.h"
-#include "mpc.h"
-#include "resources.h"
-
-/*
- * mpc.c: Implementation of MPOA client kernel part
- */
-
-#if 0
-#define dprintk(format, args...) \
- printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args)
-#define dprintk_cont(format, args...) printk(KERN_CONT format, ##args)
-#else
-#define dprintk(format, args...) \
- do { if (0) \
- printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args);\
- } while (0)
-#define dprintk_cont(format, args...) \
- do { if (0) printk(KERN_CONT format, ##args); } while (0)
-#endif
-
-#if 0
-#define ddprintk(format, args...) \
- printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args)
-#define ddprintk_cont(format, args...) printk(KERN_CONT format, ##args)
-#else
-#define ddprintk(format, args...) \
- do { if (0) \
- printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args);\
- } while (0)
-#define ddprintk_cont(format, args...) \
- do { if (0) printk(KERN_CONT format, ##args); } while (0)
-#endif
-
-/* mpc_daemon -> kernel */
-static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc);
-static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc);
-static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc);
-static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc);
-static void mps_death(struct k_message *msg, struct mpoa_client *mpc);
-static void clean_up(struct k_message *msg, struct mpoa_client *mpc,
- int action);
-static void MPOA_cache_impos_rcvd(struct k_message *msg,
- struct mpoa_client *mpc);
-static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg,
- struct mpoa_client *mpc);
-static void set_mps_mac_addr_rcvd(struct k_message *mesg,
- struct mpoa_client *mpc);
-
-static const uint8_t *copy_macs(struct mpoa_client *mpc,
- const uint8_t *router_mac,
- const uint8_t *tlvs, uint8_t mps_macs,
- uint8_t device_type);
-static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry);
-
-static void send_set_mps_ctrl_addr(const char *addr, struct mpoa_client *mpc);
-static void mpoad_close(struct atm_vcc *vcc);
-static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb);
-
-static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb);
-static netdev_tx_t mpc_send_packet(struct sk_buff *skb,
- struct net_device *dev);
-static int mpoa_event_listener(struct notifier_block *mpoa_notifier,
- unsigned long event, void *dev);
-static void mpc_timer_refresh(void);
-static void mpc_cache_check(struct timer_list *unused);
-
-static struct llc_snap_hdr llc_snap_mpoa_ctrl = {
- 0xaa, 0xaa, 0x03,
- {0x00, 0x00, 0x5e},
- {0x00, 0x03} /* For MPOA control PDUs */
-};
-static struct llc_snap_hdr llc_snap_mpoa_data = {
- 0xaa, 0xaa, 0x03,
- {0x00, 0x00, 0x00},
- {0x08, 0x00} /* This is for IP PDUs only */
-};
-static struct llc_snap_hdr llc_snap_mpoa_data_tagged = {
- 0xaa, 0xaa, 0x03,
- {0x00, 0x00, 0x00},
- {0x88, 0x4c} /* This is for tagged data PDUs */
-};
-
-static struct notifier_block mpoa_notifier = {
- mpoa_event_listener,
- NULL,
- 0
-};
-
-struct mpoa_client *mpcs = NULL; /* FIXME */
-static struct atm_mpoa_qos *qos_head = NULL;
-static DEFINE_TIMER(mpc_timer, mpc_cache_check);
-
-
-static struct mpoa_client *find_mpc_by_itfnum(int itf)
-{
- struct mpoa_client *mpc;
-
- mpc = mpcs; /* our global linked list */
- while (mpc != NULL) {
- if (mpc->dev_num == itf)
- return mpc;
- mpc = mpc->next;
- }
-
- return NULL; /* not found */
-}
-
-static struct mpoa_client *find_mpc_by_vcc(struct atm_vcc *vcc)
-{
- struct mpoa_client *mpc;
-
- mpc = mpcs; /* our global linked list */
- while (mpc != NULL) {
- if (mpc->mpoad_vcc == vcc)
- return mpc;
- mpc = mpc->next;
- }
-
- return NULL; /* not found */
-}
-
-static struct mpoa_client *find_mpc_by_lec(struct net_device *dev)
-{
- struct mpoa_client *mpc;
-
- mpc = mpcs; /* our global linked list */
- while (mpc != NULL) {
- if (mpc->dev == dev)
- return mpc;
- mpc = mpc->next;
- }
-
- return NULL; /* not found */
-}
-
-/*
- * Functions for managing QoS list
- */
-
-/*
- * Overwrites the old entry or makes a new one.
- */
-struct atm_mpoa_qos *atm_mpoa_add_qos(__be32 dst_ip, struct atm_qos *qos)
-{
- struct atm_mpoa_qos *entry;
-
- entry = atm_mpoa_search_qos(dst_ip);
- if (entry != NULL) {
- entry->qos = *qos;
- return entry;
- }
-
- entry = kmalloc_obj(struct atm_mpoa_qos);
- if (entry == NULL) {
- pr_info("mpoa: out of memory\n");
- return entry;
- }
-
- entry->ipaddr = dst_ip;
- entry->qos = *qos;
-
- entry->next = qos_head;
- qos_head = entry;
-
- return entry;
-}
-
-struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip)
-{
- struct atm_mpoa_qos *qos;
-
- qos = qos_head;
- while (qos) {
- if (qos->ipaddr == dst_ip)
- break;
- qos = qos->next;
- }
-
- return qos;
-}
-
-/*
- * Returns 0 for failure
- */
-int atm_mpoa_delete_qos(struct atm_mpoa_qos *entry)
-{
- struct atm_mpoa_qos *curr;
-
- if (entry == NULL)
- return 0;
- if (entry == qos_head) {
- qos_head = qos_head->next;
- kfree(entry);
- return 1;
- }
-
- curr = qos_head;
- while (curr != NULL) {
- if (curr->next == entry) {
- curr->next = entry->next;
- kfree(entry);
- return 1;
- }
- curr = curr->next;
- }
-
- return 0;
-}
-
-/* this is buggered - we need locking for qos_head */
-void atm_mpoa_disp_qos(struct seq_file *m)
-{
- struct atm_mpoa_qos *qos;
-
- qos = qos_head;
- seq_printf(m, "QoS entries for shortcuts:\n");
- seq_printf(m, "IP address\n TX:max_pcr pcr min_pcr max_cdv max_sdu\n RX:max_pcr pcr min_pcr max_cdv max_sdu\n");
-
- while (qos != NULL) {
- seq_printf(m, "%pI4\n %-7d %-7d %-7d %-7d %-7d\n %-7d %-7d %-7d %-7d %-7d\n",
- &qos->ipaddr,
- qos->qos.txtp.max_pcr,
- qos->qos.txtp.pcr,
- qos->qos.txtp.min_pcr,
- qos->qos.txtp.max_cdv,
- qos->qos.txtp.max_sdu,
- qos->qos.rxtp.max_pcr,
- qos->qos.rxtp.pcr,
- qos->qos.rxtp.min_pcr,
- qos->qos.rxtp.max_cdv,
- qos->qos.rxtp.max_sdu);
- qos = qos->next;
- }
-}
-
-static struct net_device *find_lec_by_itfnum(int itf)
-{
- struct net_device *dev;
- char name[IFNAMSIZ];
-
- sprintf(name, "lec%d", itf);
- dev = dev_get_by_name(&init_net, name);
-
- return dev;
-}
-
-static struct mpoa_client *alloc_mpc(void)
-{
- struct mpoa_client *mpc;
-
- mpc = kzalloc_obj(struct mpoa_client);
- if (mpc == NULL)
- return NULL;
- rwlock_init(&mpc->ingress_lock);
- rwlock_init(&mpc->egress_lock);
- mpc->next = mpcs;
- atm_mpoa_init_cache(mpc);
-
- mpc->parameters.mpc_p1 = MPC_P1;
- mpc->parameters.mpc_p2 = MPC_P2;
- memset(mpc->parameters.mpc_p3, 0, sizeof(mpc->parameters.mpc_p3));
- mpc->parameters.mpc_p4 = MPC_P4;
- mpc->parameters.mpc_p5 = MPC_P5;
- mpc->parameters.mpc_p6 = MPC_P6;
-
- mpcs = mpc;
-
- return mpc;
-}
-
-/*
- *
- * start_mpc() puts the MPC on line. All the packets destined
- * to the lec underneath us are now being monitored and
- * shortcuts will be established.
- *
- */
-static void start_mpc(struct mpoa_client *mpc, struct net_device *dev)
-{
-
- dprintk("(%s)\n", mpc->dev->name);
- if (!dev->netdev_ops)
- pr_info("(%s) not starting\n", dev->name);
- else {
- mpc->old_ops = dev->netdev_ops;
- mpc->new_ops = *mpc->old_ops;
- mpc->new_ops.ndo_start_xmit = mpc_send_packet;
- dev->netdev_ops = &mpc->new_ops;
- }
-}
-
-static void stop_mpc(struct mpoa_client *mpc)
-{
- struct net_device *dev = mpc->dev;
- dprintk("(%s)", mpc->dev->name);
-
- /* Lets not nullify lec device's dev->hard_start_xmit */
- if (dev->netdev_ops != &mpc->new_ops) {
- dprintk_cont(" mpc already stopped, not fatal\n");
- return;
- }
- dprintk_cont("\n");
-
- dev->netdev_ops = mpc->old_ops;
- mpc->old_ops = NULL;
-
- /* close_shortcuts(mpc); ??? FIXME */
-}
-
-static const char *mpoa_device_type_string(char type) __attribute__ ((unused));
-
-static const char *mpoa_device_type_string(char type)
-{
- switch (type) {
- case NON_MPOA:
- return "non-MPOA device";
- case MPS:
- return "MPS";
- case MPC:
- return "MPC";
- case MPS_AND_MPC:
- return "both MPS and MPC";
- }
-
- return "unspecified (non-MPOA) device";
-}
-
-/*
- * lec device calls this via its netdev_priv(dev)->lane2_ops
- * ->associate_indicator() when it sees a TLV in LE_ARP packet.
- * We fill in the pointer above when we see a LANE2 lec initializing
- * See LANE2 spec 3.1.5
- *
- * Quite a big and ugly function but when you look at it
- * all it does is to try to locate and parse MPOA Device
- * Type TLV.
- * We give our lec a pointer to this function and when the
- * lec sees a TLV it uses the pointer to call this function.
- *
- */
-static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr,
- const u8 *tlvs, u32 sizeoftlvs)
-{
- uint32_t type;
- uint8_t length, mpoa_device_type, number_of_mps_macs;
- const uint8_t *end_of_tlvs;
- struct mpoa_client *mpc;
-
- mpoa_device_type = number_of_mps_macs = 0; /* silence gcc */
- dprintk("(%s) received TLV(s), ", dev->name);
- dprintk("total length of all TLVs %d\n", sizeoftlvs);
- mpc = find_mpc_by_lec(dev); /* Sampo-Fix: moved here from below */
- if (mpc == NULL) {
- pr_info("(%s) no mpc\n", dev->name);
- return;
- }
- end_of_tlvs = tlvs + sizeoftlvs;
- while (end_of_tlvs - tlvs >= 5) {
- type = ((tlvs[0] << 24) | (tlvs[1] << 16) |
- (tlvs[2] << 8) | tlvs[3]);
- length = tlvs[4];
- tlvs += 5;
- dprintk(" type 0x%x length %02x\n", type, length);
- if (tlvs + length > end_of_tlvs) {
- pr_info("TLV value extends past its buffer, aborting parse\n");
- return;
- }
-
- if (type == 0) {
- pr_info("mpoa: (%s) TLV type was 0, returning\n",
- dev->name);
- return;
- }
-
- if (type != TLV_MPOA_DEVICE_TYPE) {
- tlvs += length;
- continue; /* skip other TLVs */
- }
- mpoa_device_type = *tlvs++;
- number_of_mps_macs = *tlvs++;
- dprintk("(%s) MPOA device type '%s', ",
- dev->name, mpoa_device_type_string(mpoa_device_type));
- if (mpoa_device_type == MPS_AND_MPC &&
- length < (42 + number_of_mps_macs*ETH_ALEN)) { /* :) */
- pr_info("(%s) short MPOA Device Type TLV\n",
- dev->name);
- continue;
- }
- if ((mpoa_device_type == MPS || mpoa_device_type == MPC) &&
- length < 22 + number_of_mps_macs*ETH_ALEN) {
- pr_info("(%s) short MPOA Device Type TLV\n", dev->name);
- continue;
- }
- if (mpoa_device_type != MPS &&
- mpoa_device_type != MPS_AND_MPC) {
- dprintk("ignoring non-MPS device ");
- if (mpoa_device_type == MPC)
- tlvs += 20;
- continue; /* we are only interested in MPSs */
- }
- if (number_of_mps_macs == 0 &&
- mpoa_device_type == MPS_AND_MPC) {
- pr_info("(%s) MPS_AND_MPC has zero MACs\n", dev->name);
- continue; /* someone should read the spec */
- }
- dprintk_cont("this MPS has %d MAC addresses\n",
- number_of_mps_macs);
-
- /*
- * ok, now we can go and tell our daemon
- * the control address of MPS
- */
- send_set_mps_ctrl_addr(tlvs, mpc);
-
- tlvs = copy_macs(mpc, mac_addr, tlvs,
- number_of_mps_macs, mpoa_device_type);
- if (tlvs == NULL)
- return;
- }
- if (end_of_tlvs - tlvs != 0)
- pr_info("(%s) ignoring %zd bytes of trailing TLV garbage\n",
- dev->name, end_of_tlvs - tlvs);
-}
-
-/*
- * Store at least advertizing router's MAC address
- * plus the possible MAC address(es) to mpc->mps_macs.
- * For a freshly allocated MPOA client mpc->mps_macs == 0.
- */
-static const uint8_t *copy_macs(struct mpoa_client *mpc,
- const uint8_t *router_mac,
- const uint8_t *tlvs, uint8_t mps_macs,
- uint8_t device_type)
-{
- int num_macs;
- num_macs = (mps_macs > 1) ? mps_macs : 1;
-
- if (mpc->number_of_mps_macs != num_macs) { /* need to reallocate? */
- if (mpc->number_of_mps_macs != 0)
- kfree(mpc->mps_macs);
- mpc->number_of_mps_macs = 0;
- mpc->mps_macs = kmalloc_array(ETH_ALEN, num_macs, GFP_KERNEL);
- if (mpc->mps_macs == NULL) {
- pr_info("(%s) out of mem\n", mpc->dev->name);
- return NULL;
- }
- }
- ether_addr_copy(mpc->mps_macs, router_mac);
- tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20;
- if (mps_macs > 0)
- memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN);
- tlvs += mps_macs*ETH_ALEN;
- mpc->number_of_mps_macs = num_macs;
-
- return tlvs;
-}
-
-static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
-{
- in_cache_entry *entry;
- struct iphdr *iph;
- char *buff;
- __be32 ipaddr = 0;
-
- static struct {
- struct llc_snap_hdr hdr;
- __be32 tag;
- } tagged_llc_snap_hdr = {
- {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}},
- 0
- };
-
- buff = skb->data + mpc->dev->hard_header_len;
- iph = (struct iphdr *)buff;
- ipaddr = iph->daddr;
-
- ddprintk("(%s) ipaddr 0x%x\n",
- mpc->dev->name, ipaddr);
-
- entry = mpc->in_ops->get(ipaddr, mpc);
- if (entry == NULL) {
- entry = mpc->in_ops->add_entry(ipaddr, mpc);
- if (entry != NULL)
- mpc->in_ops->put(entry);
- return 1;
- }
- /* threshold not exceeded or VCC not ready */
- if (mpc->in_ops->cache_hit(entry, mpc) != OPEN) {
- ddprintk("(%s) cache_hit: returns != OPEN\n",
- mpc->dev->name);
- mpc->in_ops->put(entry);
- return 1;
- }
-
- ddprintk("(%s) using shortcut\n",
- mpc->dev->name);
- /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */
- if (iph->ttl <= 1) {
- ddprintk("(%s) IP ttl = %u, using LANE\n",
- mpc->dev->name, iph->ttl);
- mpc->in_ops->put(entry);
- return 1;
- }
- iph->ttl--;
- iph->check = 0;
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-
- if (entry->ctrl_info.tag != 0) {
- ddprintk("(%s) adding tag 0x%x\n",
- mpc->dev->name, entry->ctrl_info.tag);
- tagged_llc_snap_hdr.tag = entry->ctrl_info.tag;
- skb_pull(skb, ETH_HLEN); /* get rid of Eth header */
- skb_push(skb, sizeof(tagged_llc_snap_hdr));
- /* add LLC/SNAP header */
- skb_copy_to_linear_data(skb, &tagged_llc_snap_hdr,
- sizeof(tagged_llc_snap_hdr));
- } else {
- skb_pull(skb, ETH_HLEN); /* get rid of Eth header */
- skb_push(skb, sizeof(struct llc_snap_hdr));
- /* add LLC/SNAP header + tag */
- skb_copy_to_linear_data(skb, &llc_snap_mpoa_data,
- sizeof(struct llc_snap_hdr));
- }
-
- atm_account_tx(entry->shortcut, skb);
- entry->shortcut->send(entry->shortcut, skb);
- entry->packets_fwded++;
- mpc->in_ops->put(entry);
-
- return 0;
-}
-
-/*
- * Probably needs some error checks and locking, not sure...
- */
-static netdev_tx_t mpc_send_packet(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct mpoa_client *mpc;
- struct ethhdr *eth;
- int i = 0;
-
- mpc = find_mpc_by_lec(dev); /* this should NEVER fail */
- if (mpc == NULL) {
- pr_info("(%s) no MPC found\n", dev->name);
- goto non_ip;
- }
-
- eth = (struct ethhdr *)skb->data;
- if (eth->h_proto != htons(ETH_P_IP))
- goto non_ip; /* Multi-Protocol Over ATM :-) */
-
- /* Weed out funny packets (e.g., AF_PACKET or raw). */
- if (skb->len < ETH_HLEN + sizeof(struct iphdr))
- goto non_ip;
- skb_set_network_header(skb, ETH_HLEN);
- if (skb->len < ETH_HLEN + ip_hdr(skb)->ihl * 4 || ip_hdr(skb)->ihl < 5)
- goto non_ip;
-
- while (i < mpc->number_of_mps_macs) {
- if (ether_addr_equal(eth->h_dest, mpc->mps_macs + i * ETH_ALEN))
- if (send_via_shortcut(skb, mpc) == 0) /* try shortcut */
- return NETDEV_TX_OK;
- i++;
- }
-
-non_ip:
- return __netdev_start_xmit(mpc->old_ops, skb, dev, false);
-}
-
-static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
-{
- int bytes_left;
- struct mpoa_client *mpc;
- struct atmmpc_ioc ioc_data;
- in_cache_entry *in_entry;
- __be32 ipaddr;
-
- bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmmpc_ioc));
- if (bytes_left != 0) {
- pr_info("mpoa:Short read (missed %d bytes) from userland\n",
- bytes_left);
- return -EFAULT;
- }
- ipaddr = ioc_data.ipaddr;
- if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF)
- return -EINVAL;
-
- mpc = find_mpc_by_itfnum(ioc_data.dev_num);
- if (mpc == NULL)
- return -EINVAL;
-
- if (ioc_data.type == MPC_SOCKET_INGRESS) {
- in_entry = mpc->in_ops->get(ipaddr, mpc);
- if (in_entry == NULL ||
- in_entry->entry_state < INGRESS_RESOLVED) {
- pr_info("(%s) did not find RESOLVED entry from ingress cache\n",
- mpc->dev->name);
- if (in_entry != NULL)
- mpc->in_ops->put(in_entry);
- return -EINVAL;
- }
- pr_info("(%s) attaching ingress SVC, entry = %pI4\n",
- mpc->dev->name, &in_entry->ctrl_info.in_dst_ip);
- in_entry->shortcut = vcc;
- mpc->in_ops->put(in_entry);
- } else {
- pr_info("(%s) attaching egress SVC\n", mpc->dev->name);
- }
-
- vcc->proto_data = mpc->dev;
- vcc->push = mpc_push;
-
- return 0;
-}
-
-/*
- *
- */
-static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev)
-{
- struct mpoa_client *mpc;
- in_cache_entry *in_entry;
- eg_cache_entry *eg_entry;
-
- mpc = find_mpc_by_lec(dev);
- if (mpc == NULL) {
- pr_info("(%s) close for unknown MPC\n", dev->name);
- return;
- }
-
- dprintk("(%s)\n", dev->name);
- in_entry = mpc->in_ops->get_by_vcc(vcc, mpc);
- if (in_entry) {
- dprintk("(%s) ingress SVC closed ip = %pI4\n",
- mpc->dev->name, &in_entry->ctrl_info.in_dst_ip);
- in_entry->shortcut = NULL;
- mpc->in_ops->put(in_entry);
- }
- eg_entry = mpc->eg_ops->get_by_vcc(vcc, mpc);
- if (eg_entry) {
- dprintk("(%s) egress SVC closed\n", mpc->dev->name);
- eg_entry->shortcut = NULL;
- mpc->eg_ops->put(eg_entry);
- }
-
- if (in_entry == NULL && eg_entry == NULL)
- dprintk("(%s) unused vcc closed\n", dev->name);
-}
-
-static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- struct net_device *dev = (struct net_device *)vcc->proto_data;
- struct sk_buff *new_skb;
- eg_cache_entry *eg;
- struct mpoa_client *mpc;
- __be32 tag;
- char *tmp;
-
- ddprintk("(%s)\n", dev->name);
- if (skb == NULL) {
- dprintk("(%s) null skb, closing VCC\n", dev->name);
- mpc_vcc_close(vcc, dev);
- return;
- }
-
- skb->dev = dev;
- if (memcmp(skb->data, &llc_snap_mpoa_ctrl,
- sizeof(struct llc_snap_hdr)) == 0) {
- struct sock *sk = sk_atm(vcc);
-
- dprintk("(%s) control packet arrived\n", dev->name);
- /* Pass control packets to daemon */
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk);
- return;
- }
-
- /* data coming over the shortcut */
- atm_return(vcc, skb->truesize);
-
- mpc = find_mpc_by_lec(dev);
- if (mpc == NULL) {
- pr_info("(%s) unknown MPC\n", dev->name);
- return;
- }
-
- if (memcmp(skb->data, &llc_snap_mpoa_data_tagged,
- sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */
- ddprintk("(%s) tagged data packet arrived\n", dev->name);
-
- } else if (memcmp(skb->data, &llc_snap_mpoa_data,
- sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */
- pr_info("(%s) Unsupported non-tagged data packet arrived. Purging\n",
- dev->name);
- dev_kfree_skb_any(skb);
- return;
- } else {
- pr_info("(%s) garbage arrived, purging\n", dev->name);
- dev_kfree_skb_any(skb);
- return;
- }
-
- tmp = skb->data + sizeof(struct llc_snap_hdr);
- tag = *(__be32 *)tmp;
-
- eg = mpc->eg_ops->get_by_tag(tag, mpc);
- if (eg == NULL) {
- pr_info("mpoa: (%s) Didn't find egress cache entry, tag = %u\n",
- dev->name, tag);
- purge_egress_shortcut(vcc, NULL);
- dev_kfree_skb_any(skb);
- return;
- }
-
- /*
- * See if ingress MPC is using shortcut we opened as a return channel.
- * This means we have a bi-directional vcc opened by us.
- */
- if (eg->shortcut == NULL) {
- eg->shortcut = vcc;
- pr_info("(%s) egress SVC in use\n", dev->name);
- }
-
- skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag));
- /* get rid of LLC/SNAP header */
- new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length);
- /* LLC/SNAP is shorter than MAC header :( */
- dev_kfree_skb_any(skb);
- if (new_skb == NULL) {
- mpc->eg_ops->put(eg);
- return;
- }
- skb_push(new_skb, eg->ctrl_info.DH_length); /* add MAC header */
- skb_copy_to_linear_data(new_skb, eg->ctrl_info.DLL_header,
- eg->ctrl_info.DH_length);
- new_skb->protocol = eth_type_trans(new_skb, dev);
- skb_reset_network_header(new_skb);
-
- eg->latest_ip_addr = ip_hdr(new_skb)->saddr;
- eg->packets_rcvd++;
- mpc->eg_ops->put(eg);
-
- memset(ATM_SKB(new_skb), 0, sizeof(struct atm_skb_data));
- netif_rx(new_skb);
-}
-
-static const struct atmdev_ops mpc_ops = { /* only send is required */
- .close = mpoad_close,
- .send = msg_from_mpoad
-};
-
-static struct atm_dev mpc_dev = {
- .ops = &mpc_ops,
- .type = "mpc",
- .number = 42,
- .lock = __SPIN_LOCK_UNLOCKED(mpc_dev.lock)
- /* members not explicitly initialised will be 0 */
-};
-
-static int atm_mpoa_mpoad_attach(struct atm_vcc *vcc, int arg)
-{
- struct mpoa_client *mpc;
- struct lec_priv *priv;
- int err;
-
- if (mpcs == NULL) {
- mpc_timer_refresh();
-
- /* This lets us now how our LECs are doing */
- err = register_netdevice_notifier(&mpoa_notifier);
- if (err < 0) {
- timer_delete(&mpc_timer);
- return err;
- }
- }
-
- mpc = find_mpc_by_itfnum(arg);
- if (mpc == NULL) {
- dprintk("allocating new mpc for itf %d\n", arg);
- mpc = alloc_mpc();
- if (mpc == NULL)
- return -ENOMEM;
- mpc->dev_num = arg;
- mpc->dev = find_lec_by_itfnum(arg);
- /* NULL if there was no lec */
- }
- if (mpc->mpoad_vcc) {
- pr_info("mpoad is already present for itf %d\n", arg);
- return -EADDRINUSE;
- }
-
- if (mpc->dev) { /* check if the lec is LANE2 capable */
- priv = netdev_priv(mpc->dev);
- if (priv->lane_version < 2) {
- dev_put(mpc->dev);
- mpc->dev = NULL;
- } else
- priv->lane2_ops->associate_indicator = lane2_assoc_ind;
- }
-
- mpc->mpoad_vcc = vcc;
- vcc->dev = &mpc_dev;
- vcc_insert_socket(sk_atm(vcc));
- set_bit(ATM_VF_META, &vcc->flags);
- set_bit(ATM_VF_READY, &vcc->flags);
-
- if (mpc->dev) {
- char empty[ATM_ESA_LEN];
- memset(empty, 0, ATM_ESA_LEN);
-
- start_mpc(mpc, mpc->dev);
- /* set address if mpcd e.g. gets killed and restarted.
- * If we do not do it now we have to wait for the next LE_ARP
- */
- if (memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0)
- send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc);
- }
-
- __module_get(THIS_MODULE);
- return arg;
-}
-
-static void send_set_mps_ctrl_addr(const char *addr, struct mpoa_client *mpc)
-{
- struct k_message mesg;
-
- memcpy(mpc->mps_ctrl_addr, addr, ATM_ESA_LEN);
-
- mesg.type = SET_MPS_CTRL_ADDR;
- memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN);
- msg_to_mpoad(&mesg, mpc);
-}
-
-static void mpoad_close(struct atm_vcc *vcc)
-{
- struct mpoa_client *mpc;
- struct sk_buff *skb;
-
- mpc = find_mpc_by_vcc(vcc);
- if (mpc == NULL) {
- pr_info("did not find MPC\n");
- return;
- }
- if (!mpc->mpoad_vcc) {
- pr_info("close for non-present mpoad\n");
- return;
- }
-
- mpc->mpoad_vcc = NULL;
- if (mpc->dev) {
- struct lec_priv *priv = netdev_priv(mpc->dev);
- priv->lane2_ops->associate_indicator = NULL;
- stop_mpc(mpc);
- dev_put(mpc->dev);
- }
-
- mpc->in_ops->destroy_cache(mpc);
- mpc->eg_ops->destroy_cache(mpc);
-
- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
- atm_return(vcc, skb->truesize);
- kfree_skb(skb);
- }
-
- pr_info("(%s) going down\n",
- (mpc->dev) ? mpc->dev->name : "<unknown>");
- module_put(THIS_MODULE);
-}
-
-/*
- *
- */
-static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb)
-{
-
- struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
- struct k_message *mesg = (struct k_message *)skb->data;
- WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc));
-
- if (mpc == NULL) {
- pr_info("no mpc found\n");
- return 0;
- }
- dprintk("(%s)", mpc->dev ? mpc->dev->name : "<unknown>");
- switch (mesg->type) {
- case MPOA_RES_REPLY_RCVD:
- dprintk_cont("mpoa_res_reply_rcvd\n");
- MPOA_res_reply_rcvd(mesg, mpc);
- break;
- case MPOA_TRIGGER_RCVD:
- dprintk_cont("mpoa_trigger_rcvd\n");
- MPOA_trigger_rcvd(mesg, mpc);
- break;
- case INGRESS_PURGE_RCVD:
- dprintk_cont("nhrp_purge_rcvd\n");
- ingress_purge_rcvd(mesg, mpc);
- break;
- case EGRESS_PURGE_RCVD:
- dprintk_cont("egress_purge_reply_rcvd\n");
- egress_purge_rcvd(mesg, mpc);
- break;
- case MPS_DEATH:
- dprintk_cont("mps_death\n");
- mps_death(mesg, mpc);
- break;
- case CACHE_IMPOS_RCVD:
- dprintk_cont("cache_impos_rcvd\n");
- MPOA_cache_impos_rcvd(mesg, mpc);
- break;
- case SET_MPC_CTRL_ADDR:
- dprintk_cont("set_mpc_ctrl_addr\n");
- set_mpc_ctrl_addr_rcvd(mesg, mpc);
- break;
- case SET_MPS_MAC_ADDR:
- dprintk_cont("set_mps_mac_addr\n");
- set_mps_mac_addr_rcvd(mesg, mpc);
- break;
- case CLEAN_UP_AND_EXIT:
- dprintk_cont("clean_up_and_exit\n");
- clean_up(mesg, mpc, DIE);
- break;
- case RELOAD:
- dprintk_cont("reload\n");
- clean_up(mesg, mpc, RELOAD);
- break;
- case SET_MPC_PARAMS:
- dprintk_cont("set_mpc_params\n");
- mpc->parameters = mesg->content.params;
- break;
- default:
- dprintk_cont("unknown message %d\n", mesg->type);
- break;
- }
- kfree_skb(skb);
-
- return 0;
-}
-
-/* Remember that this function may not do things that sleep */
-int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc)
-{
- struct sk_buff *skb;
- struct sock *sk;
-
- if (mpc == NULL || !mpc->mpoad_vcc) {
- pr_info("mesg %d to a non-existent mpoad\n", mesg->type);
- return -ENXIO;
- }
-
- skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC);
- if (skb == NULL)
- return -ENOMEM;
- skb_put(skb, sizeof(struct k_message));
- skb_copy_to_linear_data(skb, mesg, sizeof(*mesg));
- atm_force_charge(mpc->mpoad_vcc, skb->truesize);
-
- sk = sk_atm(mpc->mpoad_vcc);
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk);
-
- return 0;
-}
-
-static int mpoa_event_listener(struct notifier_block *mpoa_notifier,
- unsigned long event, void *ptr)
-{
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- struct mpoa_client *mpc;
- struct lec_priv *priv;
-
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
- if (strncmp(dev->name, "lec", 3))
- return NOTIFY_DONE; /* we are only interested in lec:s */
-
- switch (event) {
- case NETDEV_REGISTER: /* a new lec device was allocated */
- priv = netdev_priv(dev);
- if (priv->lane_version < 2)
- break;
- priv->lane2_ops->associate_indicator = lane2_assoc_ind;
- mpc = find_mpc_by_itfnum(priv->itfnum);
- if (mpc == NULL) {
- dprintk("allocating new mpc for %s\n", dev->name);
- mpc = alloc_mpc();
- if (mpc == NULL) {
- pr_info("no new mpc");
- break;
- }
- }
- mpc->dev_num = priv->itfnum;
- mpc->dev = dev;
- dev_hold(dev);
- dprintk("(%s) was initialized\n", dev->name);
- break;
- case NETDEV_UNREGISTER:
- /* the lec device was deallocated */
- mpc = find_mpc_by_lec(dev);
- if (mpc == NULL)
- break;
- dprintk("device (%s) was deallocated\n", dev->name);
- stop_mpc(mpc);
- dev_put(mpc->dev);
- mpc->dev = NULL;
- break;
- case NETDEV_UP:
- /* the dev was ifconfig'ed up */
- mpc = find_mpc_by_lec(dev);
- if (mpc == NULL)
- break;
- if (mpc->mpoad_vcc != NULL)
- start_mpc(mpc, dev);
- break;
- case NETDEV_DOWN:
- /* the dev was ifconfig'ed down */
- /* this means that the flow of packets from the
- * upper layer stops
- */
- mpc = find_mpc_by_lec(dev);
- if (mpc == NULL)
- break;
- if (mpc->mpoad_vcc != NULL)
- stop_mpc(mpc);
- break;
- case NETDEV_REBOOT:
- case NETDEV_CHANGE:
- case NETDEV_CHANGEMTU:
- case NETDEV_CHANGEADDR:
- case NETDEV_GOING_DOWN:
- break;
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-/*
- * Functions which are called after a message is received from mpcd.
- * Msg is reused on purpose.
- */
-
-
-static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc)
-{
- __be32 dst_ip = msg->content.in_info.in_dst_ip;
- in_cache_entry *entry;
-
- entry = mpc->in_ops->get(dst_ip, mpc);
- if (entry == NULL) {
- entry = mpc->in_ops->add_entry(dst_ip, mpc);
- entry->entry_state = INGRESS_RESOLVING;
- msg->type = SND_MPOA_RES_RQST;
- msg->content.in_info = entry->ctrl_info;
- msg_to_mpoad(msg, mpc);
- entry->reply_wait = ktime_get_seconds();
- mpc->in_ops->put(entry);
- return;
- }
-
- if (entry->entry_state == INGRESS_INVALID) {
- entry->entry_state = INGRESS_RESOLVING;
- msg->type = SND_MPOA_RES_RQST;
- msg->content.in_info = entry->ctrl_info;
- msg_to_mpoad(msg, mpc);
- entry->reply_wait = ktime_get_seconds();
- mpc->in_ops->put(entry);
- return;
- }
-
- pr_info("(%s) entry already in resolving state\n",
- (mpc->dev) ? mpc->dev->name : "<unknown>");
- mpc->in_ops->put(entry);
-}
-
-/*
- * Things get complicated because we have to check if there's an egress
- * shortcut with suitable traffic parameters we could use.
- */
-static void check_qos_and_open_shortcut(struct k_message *msg,
- struct mpoa_client *client,
- in_cache_entry *entry)
-{
- __be32 dst_ip = msg->content.in_info.in_dst_ip;
- struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip);
- eg_cache_entry *eg_entry = client->eg_ops->get_by_src_ip(dst_ip, client);
-
- if (eg_entry && eg_entry->shortcut) {
- if (eg_entry->shortcut->qos.txtp.traffic_class &
- msg->qos.txtp.traffic_class &
- (qos ? qos->qos.txtp.traffic_class : ATM_UBR | ATM_CBR)) {
- if (eg_entry->shortcut->qos.txtp.traffic_class == ATM_UBR)
- entry->shortcut = eg_entry->shortcut;
- else if (eg_entry->shortcut->qos.txtp.max_pcr > 0)
- entry->shortcut = eg_entry->shortcut;
- }
- if (entry->shortcut) {
- dprintk("(%s) using egress SVC to reach %pI4\n",
- client->dev->name, &dst_ip);
- client->eg_ops->put(eg_entry);
- return;
- }
- }
- if (eg_entry != NULL)
- client->eg_ops->put(eg_entry);
-
- /* No luck in the egress cache we must open an ingress SVC */
- msg->type = OPEN_INGRESS_SVC;
- if (qos &&
- (qos->qos.txtp.traffic_class == msg->qos.txtp.traffic_class)) {
- msg->qos = qos->qos;
- pr_info("(%s) trying to get a CBR shortcut\n",
- client->dev->name);
- } else
- memset(&msg->qos, 0, sizeof(struct atm_qos));
- msg_to_mpoad(msg, client);
-}
-
-static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc)
-{
- __be32 dst_ip = msg->content.in_info.in_dst_ip;
- in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc);
-
- dprintk("(%s) ip %pI4\n",
- mpc->dev->name, &dst_ip);
- ddprintk("(%s) entry = %p",
- mpc->dev->name, entry);
- if (entry == NULL) {
- pr_info("(%s) ARGH, received res. reply for an entry that doesn't exist.\n",
- mpc->dev->name);
- return;
- }
- ddprintk_cont(" entry_state = %d ", entry->entry_state);
-
- if (entry->entry_state == INGRESS_RESOLVED) {
- pr_info("(%s) RESOLVED entry!\n", mpc->dev->name);
- mpc->in_ops->put(entry);
- return;
- }
-
- entry->ctrl_info = msg->content.in_info;
- entry->time = ktime_get_seconds();
- /* Used in refreshing func from now on */
- entry->reply_wait = ktime_get_seconds();
- entry->refresh_time = 0;
- ddprintk_cont("entry->shortcut = %p\n", entry->shortcut);
-
- if (entry->entry_state == INGRESS_RESOLVING &&
- entry->shortcut != NULL) {
- entry->entry_state = INGRESS_RESOLVED;
- mpc->in_ops->put(entry);
- return; /* Shortcut already open... */
- }
-
- if (entry->shortcut != NULL) {
- pr_info("(%s) entry->shortcut != NULL, impossible!\n",
- mpc->dev->name);
- mpc->in_ops->put(entry);
- return;
- }
-
- check_qos_and_open_shortcut(msg, mpc, entry);
- entry->entry_state = INGRESS_RESOLVED;
- mpc->in_ops->put(entry);
-
- return;
-
-}
-
-static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc)
-{
- __be32 dst_ip = msg->content.in_info.in_dst_ip;
- __be32 mask = msg->ip_mask;
- in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask);
-
- if (entry == NULL) {
- pr_info("(%s) purge for a non-existing entry, ip = %pI4\n",
- mpc->dev->name, &dst_ip);
- return;
- }
-
- do {
- dprintk("(%s) removing an ingress entry, ip = %pI4\n",
- mpc->dev->name, &dst_ip);
- write_lock_bh(&mpc->ingress_lock);
- mpc->in_ops->remove_entry(entry, mpc);
- write_unlock_bh(&mpc->ingress_lock);
- mpc->in_ops->put(entry);
- entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask);
- } while (entry != NULL);
-}
-
-static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc)
-{
- __be32 cache_id = msg->content.eg_info.cache_id;
- eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(cache_id, mpc);
-
- if (entry == NULL) {
- dprintk("(%s) purge for a non-existing entry\n",
- mpc->dev->name);
- return;
- }
-
- write_lock_irq(&mpc->egress_lock);
- mpc->eg_ops->remove_entry(entry, mpc);
- write_unlock_irq(&mpc->egress_lock);
-
- mpc->eg_ops->put(entry);
-}
-
-static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry)
-{
- struct sock *sk;
- struct k_message *purge_msg;
- struct sk_buff *skb;
-
- dprintk("entering\n");
- if (vcc == NULL) {
- pr_info("vcc == NULL\n");
- return;
- }
-
- skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC);
- if (skb == NULL) {
- pr_info("out of memory\n");
- return;
- }
-
- skb_put(skb, sizeof(struct k_message));
- memset(skb->data, 0, sizeof(struct k_message));
- purge_msg = (struct k_message *)skb->data;
- purge_msg->type = DATA_PLANE_PURGE;
- if (entry != NULL)
- purge_msg->content.eg_info = entry->ctrl_info;
-
- atm_force_charge(vcc, skb->truesize);
-
- sk = sk_atm(vcc);
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk);
- dprintk("exiting\n");
-}
-
-/*
- * Our MPS died. Tell our daemon to send NHRP data plane purge to each
- * of the egress shortcuts we have.
- */
-static void mps_death(struct k_message *msg, struct mpoa_client *mpc)
-{
- eg_cache_entry *entry;
-
- dprintk("(%s)\n", mpc->dev->name);
-
- if (memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)) {
- pr_info("(%s) wrong MPS\n", mpc->dev->name);
- return;
- }
-
- /* FIXME: This knows too much of the cache structure */
- read_lock_irq(&mpc->egress_lock);
- entry = mpc->eg_cache;
- while (entry != NULL) {
- purge_egress_shortcut(entry->shortcut, entry);
- entry = entry->next;
- }
- read_unlock_irq(&mpc->egress_lock);
-
- mpc->in_ops->destroy_cache(mpc);
- mpc->eg_ops->destroy_cache(mpc);
-}
-
-static void MPOA_cache_impos_rcvd(struct k_message *msg,
- struct mpoa_client *mpc)
-{
- uint16_t holding_time;
- eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(msg->content.eg_info.cache_id, mpc);
-
- holding_time = msg->content.eg_info.holding_time;
- dprintk("(%s) entry = %p, holding_time = %u\n",
- mpc->dev->name, entry, holding_time);
- if (entry == NULL && !holding_time)
- return;
- if (entry == NULL && holding_time) {
- entry = mpc->eg_ops->add_entry(msg, mpc);
- mpc->eg_ops->put(entry);
- return;
- }
- if (holding_time) {
- mpc->eg_ops->update(entry, holding_time);
- return;
- }
-
- write_lock_irq(&mpc->egress_lock);
- mpc->eg_ops->remove_entry(entry, mpc);
- write_unlock_irq(&mpc->egress_lock);
-
- mpc->eg_ops->put(entry);
-}
-
-static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg,
- struct mpoa_client *mpc)
-{
- struct lec_priv *priv;
- int i, retval ;
-
- uint8_t tlv[4 + 1 + 1 + 1 + ATM_ESA_LEN];
-
- tlv[0] = 00; tlv[1] = 0xa0; tlv[2] = 0x3e; tlv[3] = 0x2a; /* type */
- tlv[4] = 1 + 1 + ATM_ESA_LEN; /* length */
- tlv[5] = 0x02; /* MPOA client */
- tlv[6] = 0x00; /* number of MPS MAC addresses */
-
- memcpy(&tlv[7], mesg->MPS_ctrl, ATM_ESA_LEN); /* MPC ctrl ATM addr */
- memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN);
-
- dprintk("(%s) setting MPC ctrl ATM address to",
- mpc->dev ? mpc->dev->name : "<unknown>");
- for (i = 7; i < sizeof(tlv); i++)
- dprintk_cont(" %02x", tlv[i]);
- dprintk_cont("\n");
-
- if (mpc->dev) {
- priv = netdev_priv(mpc->dev);
- retval = priv->lane2_ops->associate_req(mpc->dev,
- mpc->dev->dev_addr,
- tlv, sizeof(tlv));
- if (retval == 0)
- pr_info("(%s) MPOA device type TLV association failed\n",
- mpc->dev->name);
- retval = priv->lane2_ops->resolve(mpc->dev, NULL, 1, NULL, NULL);
- if (retval < 0)
- pr_info("(%s) targetless LE_ARP request failed\n",
- mpc->dev->name);
- }
-}
-
-static void set_mps_mac_addr_rcvd(struct k_message *msg,
- struct mpoa_client *client)
-{
-
- if (client->number_of_mps_macs)
- kfree(client->mps_macs);
- client->number_of_mps_macs = 0;
- client->mps_macs = kmemdup(msg->MPS_ctrl, ETH_ALEN, GFP_KERNEL);
- if (client->mps_macs == NULL) {
- pr_info("out of memory\n");
- return;
- }
- client->number_of_mps_macs = 1;
-}
-
-/*
- * purge egress cache and tell daemon to 'action' (DIE, RELOAD)
- */
-static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action)
-{
-
- eg_cache_entry *entry;
- msg->type = SND_EGRESS_PURGE;
-
-
- /* FIXME: This knows too much of the cache structure */
- read_lock_irq(&mpc->egress_lock);
- entry = mpc->eg_cache;
- while (entry != NULL) {
- msg->content.eg_info = entry->ctrl_info;
- dprintk("cache_id %u\n", entry->ctrl_info.cache_id);
- msg_to_mpoad(msg, mpc);
- entry = entry->next;
- }
- read_unlock_irq(&mpc->egress_lock);
-
- msg->type = action;
- msg_to_mpoad(msg, mpc);
-}
-
-static unsigned long checking_time;
-
-static void mpc_timer_refresh(void)
-{
- mpc_timer.expires = jiffies + (MPC_P2 * HZ);
- checking_time = mpc_timer.expires;
- add_timer(&mpc_timer);
-}
-
-static void mpc_cache_check(struct timer_list *unused)
-{
- struct mpoa_client *mpc = mpcs;
- static unsigned long previous_resolving_check_time;
- static unsigned long previous_refresh_time;
-
- while (mpc != NULL) {
- mpc->in_ops->clear_count(mpc);
- mpc->eg_ops->clear_expired(mpc);
- if (checking_time - previous_resolving_check_time >
- mpc->parameters.mpc_p4 * HZ) {
- mpc->in_ops->check_resolving(mpc);
- previous_resolving_check_time = checking_time;
- }
- if (checking_time - previous_refresh_time >
- mpc->parameters.mpc_p5 * HZ) {
- mpc->in_ops->refresh(mpc);
- previous_refresh_time = checking_time;
- }
- mpc = mpc->next;
- }
- mpc_timer_refresh();
-}
-
-static int atm_mpoa_ioctl(struct socket *sock, unsigned int cmd,
- unsigned long arg)
-{
- int err = 0;
- struct atm_vcc *vcc = ATM_SD(sock);
-
- if (cmd != ATMMPC_CTRL && cmd != ATMMPC_DATA)
- return -ENOIOCTLCMD;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- switch (cmd) {
- case ATMMPC_CTRL:
- err = atm_mpoa_mpoad_attach(vcc, (int)arg);
- if (err >= 0)
- sock->state = SS_CONNECTED;
- break;
- case ATMMPC_DATA:
- err = atm_mpoa_vcc_attach(vcc, (void __user *)arg);
- break;
- default:
- break;
- }
- return err;
-}
-
-static struct atm_ioctl atm_ioctl_ops = {
- .owner = THIS_MODULE,
- .ioctl = atm_mpoa_ioctl,
-};
-
-static __init int atm_mpoa_init(void)
-{
- register_atm_ioctl(&atm_ioctl_ops);
-
- if (mpc_proc_init() != 0)
- pr_info("failed to initialize /proc/mpoa\n");
-
- pr_info("mpc.c: initialized\n");
-
- return 0;
-}
-
-static void __exit atm_mpoa_cleanup(void)
-{
- struct mpoa_client *mpc, *tmp;
- struct atm_mpoa_qos *qos, *nextqos;
- struct lec_priv *priv;
-
- mpc_proc_clean();
-
- timer_delete_sync(&mpc_timer);
- unregister_netdevice_notifier(&mpoa_notifier);
- deregister_atm_ioctl(&atm_ioctl_ops);
-
- mpc = mpcs;
- mpcs = NULL;
- while (mpc != NULL) {
- tmp = mpc->next;
- if (mpc->dev != NULL) {
- stop_mpc(mpc);
- priv = netdev_priv(mpc->dev);
- if (priv->lane2_ops != NULL)
- priv->lane2_ops->associate_indicator = NULL;
- }
- ddprintk("about to clear caches\n");
- mpc->in_ops->destroy_cache(mpc);
- mpc->eg_ops->destroy_cache(mpc);
- ddprintk("caches cleared\n");
- kfree(mpc->mps_macs);
- memset(mpc, 0, sizeof(struct mpoa_client));
- ddprintk("about to kfree %p\n", mpc);
- kfree(mpc);
- ddprintk("next mpc is at %p\n", tmp);
- mpc = tmp;
- }
-
- qos = qos_head;
- qos_head = NULL;
- while (qos != NULL) {
- nextqos = qos->next;
- dprintk("freeing qos entry %p\n", qos);
- kfree(qos);
- qos = nextqos;
- }
-}
-
-module_init(atm_mpoa_init);
-module_exit(atm_mpoa_cleanup);
-
-MODULE_DESCRIPTION("Multi-Protocol Over ATM (MPOA) driver");
-MODULE_LICENSE("GPL");
diff --git a/net/atm/mpc.h b/net/atm/mpc.h
deleted file mode 100644
index 454abd07651a..000000000000
--- a/net/atm/mpc.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _MPC_H_
-#define _MPC_H_
-
-#include <linux/types.h>
-#include <linux/atm.h>
-#include <linux/atmmpc.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include "mpoa_caches.h"
-
-/* kernel -> mpc-daemon */
-int msg_to_mpoad(struct k_message *msg, struct mpoa_client *mpc);
-
-struct mpoa_client {
- struct mpoa_client *next;
- struct net_device *dev; /* lec in question */
- int dev_num; /* e.g. 2 for lec2 */
-
- struct atm_vcc *mpoad_vcc; /* control channel to mpoad */
- uint8_t mps_ctrl_addr[ATM_ESA_LEN]; /* MPS control ATM address */
- uint8_t our_ctrl_addr[ATM_ESA_LEN]; /* MPC's control ATM address */
-
- rwlock_t ingress_lock;
- const struct in_cache_ops *in_ops; /* ingress cache operations */
- in_cache_entry *in_cache; /* the ingress cache of this MPC */
-
- rwlock_t egress_lock;
- const struct eg_cache_ops *eg_ops; /* egress cache operations */
- eg_cache_entry *eg_cache; /* the egress cache of this MPC */
-
- uint8_t *mps_macs; /* array of MPS MAC addresses, >=1 */
- int number_of_mps_macs; /* number of the above MAC addresses */
- struct mpc_parameters parameters; /* parameters for this client */
-
- const struct net_device_ops *old_ops;
- struct net_device_ops new_ops;
-};
-
-
-struct atm_mpoa_qos {
- struct atm_mpoa_qos *next;
- __be32 ipaddr;
- struct atm_qos qos;
-};
-
-
-/* MPOA QoS operations */
-struct atm_mpoa_qos *atm_mpoa_add_qos(__be32 dst_ip, struct atm_qos *qos);
-struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip);
-int atm_mpoa_delete_qos(struct atm_mpoa_qos *qos);
-
-/* Display QoS entries. This is for the procfs */
-struct seq_file;
-void atm_mpoa_disp_qos(struct seq_file *m);
-
-#ifdef CONFIG_PROC_FS
-int mpc_proc_init(void);
-void mpc_proc_clean(void);
-#else
-#define mpc_proc_init() (0)
-#define mpc_proc_clean() do { } while(0)
-#endif
-
-#endif /* _MPC_H_ */
diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c
deleted file mode 100644
index c8d4e6f2e831..000000000000
--- a/net/atm/mpoa_caches.c
+++ /dev/null
@@ -1,565 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/types.h>
-#include <linux/atmmpc.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-
-#include "mpoa_caches.h"
-#include "mpc.h"
-
-/*
- * mpoa_caches.c: Implementation of ingress and egress cache
- * handling functions
- */
-
-#if 0
-#define dprintk(format, args...) \
- printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
-#else
-#define dprintk(format, args...) \
- do { if (0) \
- printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
- } while (0)
-#endif
-
-#if 0
-#define ddprintk(format, args...) \
- printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
-#else
-#define ddprintk(format, args...) \
- do { if (0) \
- printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
- } while (0)
-#endif
-
-static in_cache_entry *in_cache_get(__be32 dst_ip,
- struct mpoa_client *client)
-{
- in_cache_entry *entry;
-
- read_lock_bh(&client->ingress_lock);
- entry = client->in_cache;
- while (entry != NULL) {
- if (entry->ctrl_info.in_dst_ip == dst_ip) {
- refcount_inc(&entry->use);
- read_unlock_bh(&client->ingress_lock);
- return entry;
- }
- entry = entry->next;
- }
- read_unlock_bh(&client->ingress_lock);
-
- return NULL;
-}
-
-static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip,
- struct mpoa_client *client,
- __be32 mask)
-{
- in_cache_entry *entry;
-
- read_lock_bh(&client->ingress_lock);
- entry = client->in_cache;
- while (entry != NULL) {
- if ((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask)) {
- refcount_inc(&entry->use);
- read_unlock_bh(&client->ingress_lock);
- return entry;
- }
- entry = entry->next;
- }
- read_unlock_bh(&client->ingress_lock);
-
- return NULL;
-
-}
-
-static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc,
- struct mpoa_client *client)
-{
- in_cache_entry *entry;
-
- read_lock_bh(&client->ingress_lock);
- entry = client->in_cache;
- while (entry != NULL) {
- if (entry->shortcut == vcc) {
- refcount_inc(&entry->use);
- read_unlock_bh(&client->ingress_lock);
- return entry;
- }
- entry = entry->next;
- }
- read_unlock_bh(&client->ingress_lock);
-
- return NULL;
-}
-
-static in_cache_entry *in_cache_add_entry(__be32 dst_ip,
- struct mpoa_client *client)
-{
- in_cache_entry *entry = kzalloc_obj(in_cache_entry);
-
- if (entry == NULL) {
- pr_info("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n");
- return NULL;
- }
-
- dprintk("adding an ingress entry, ip = %pI4\n", &dst_ip);
-
- refcount_set(&entry->use, 1);
- dprintk("new_in_cache_entry: about to lock\n");
- write_lock_bh(&client->ingress_lock);
- entry->next = client->in_cache;
- entry->prev = NULL;
- if (client->in_cache != NULL)
- client->in_cache->prev = entry;
- client->in_cache = entry;
-
- memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN);
- entry->ctrl_info.in_dst_ip = dst_ip;
- entry->time = ktime_get_seconds();
- entry->retry_time = client->parameters.mpc_p4;
- entry->count = 1;
- entry->entry_state = INGRESS_INVALID;
- entry->ctrl_info.holding_time = HOLDING_TIME_DEFAULT;
- refcount_inc(&entry->use);
-
- write_unlock_bh(&client->ingress_lock);
- dprintk("new_in_cache_entry: unlocked\n");
-
- return entry;
-}
-
-static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc)
-{
- struct atm_mpoa_qos *qos;
- struct k_message msg;
-
- entry->count++;
- if (entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL)
- return OPEN;
-
- if (entry->entry_state == INGRESS_REFRESHING) {
- if (entry->count > mpc->parameters.mpc_p1) {
- msg.type = SND_MPOA_RES_RQST;
- msg.content.in_info = entry->ctrl_info;
- memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN);
- qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
- if (qos != NULL)
- msg.qos = qos->qos;
- msg_to_mpoad(&msg, mpc);
- entry->reply_wait = ktime_get_seconds();
- entry->entry_state = INGRESS_RESOLVING;
- }
- if (entry->shortcut != NULL)
- return OPEN;
- return CLOSED;
- }
-
- if (entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL)
- return OPEN;
-
- if (entry->count > mpc->parameters.mpc_p1 &&
- entry->entry_state == INGRESS_INVALID) {
- dprintk("(%s) threshold exceeded for ip %pI4, sending MPOA res req\n",
- mpc->dev->name, &entry->ctrl_info.in_dst_ip);
- entry->entry_state = INGRESS_RESOLVING;
- msg.type = SND_MPOA_RES_RQST;
- memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN);
- msg.content.in_info = entry->ctrl_info;
- qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
- if (qos != NULL)
- msg.qos = qos->qos;
- msg_to_mpoad(&msg, mpc);
- entry->reply_wait = ktime_get_seconds();
- }
-
- return CLOSED;
-}
-
-static void in_cache_put(in_cache_entry *entry)
-{
- if (refcount_dec_and_test(&entry->use)) {
- kfree_sensitive(entry);
- }
-}
-
-/*
- * This should be called with write lock on
- */
-static void in_cache_remove_entry(in_cache_entry *entry,
- struct mpoa_client *client)
-{
- struct atm_vcc *vcc;
- struct k_message msg;
-
- vcc = entry->shortcut;
- dprintk("removing an ingress entry, ip = %pI4\n",
- &entry->ctrl_info.in_dst_ip);
-
- if (entry->prev != NULL)
- entry->prev->next = entry->next;
- else
- client->in_cache = entry->next;
- if (entry->next != NULL)
- entry->next->prev = entry->prev;
- client->in_ops->put(entry);
- if (client->in_cache == NULL && client->eg_cache == NULL) {
- msg.type = STOP_KEEP_ALIVE_SM;
- msg_to_mpoad(&msg, client);
- }
-
- /* Check if the egress side still uses this VCC */
- if (vcc != NULL) {
- eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc,
- client);
- if (eg_entry != NULL) {
- client->eg_ops->put(eg_entry);
- return;
- }
- vcc_release_async(vcc, -EPIPE);
- }
-}
-
-/* Call this every MPC-p2 seconds... Not exactly correct solution,
- but an easy one... */
-static void clear_count_and_expired(struct mpoa_client *client)
-{
- in_cache_entry *entry, *next_entry;
- time64_t now;
-
- now = ktime_get_seconds();
-
- write_lock_bh(&client->ingress_lock);
- entry = client->in_cache;
- while (entry != NULL) {
- entry->count = 0;
- next_entry = entry->next;
- if ((now - entry->time) > entry->ctrl_info.holding_time) {
- dprintk("holding time expired, ip = %pI4\n",
- &entry->ctrl_info.in_dst_ip);
- client->in_ops->remove_entry(entry, client);
- }
- entry = next_entry;
- }
- write_unlock_bh(&client->ingress_lock);
-}
-
-/* Call this every MPC-p4 seconds. */
-static void check_resolving_entries(struct mpoa_client *client)
-{
-
- struct atm_mpoa_qos *qos;
- in_cache_entry *entry;
- time64_t now;
- struct k_message msg;
-
- now = ktime_get_seconds();
-
- read_lock_bh(&client->ingress_lock);
- entry = client->in_cache;
- while (entry != NULL) {
- if (entry->entry_state == INGRESS_RESOLVING) {
-
- if ((now - entry->hold_down)
- < client->parameters.mpc_p6) {
- entry = entry->next; /* Entry in hold down */
- continue;
- }
- if ((now - entry->reply_wait) > entry->retry_time) {
- entry->retry_time = MPC_C1 * (entry->retry_time);
- /*
- * Retry time maximum exceeded,
- * put entry in hold down.
- */
- if (entry->retry_time > client->parameters.mpc_p5) {
- entry->hold_down = ktime_get_seconds();
- entry->retry_time = client->parameters.mpc_p4;
- entry = entry->next;
- continue;
- }
- /* Ask daemon to send a resolution request. */
- memset(&entry->hold_down, 0, sizeof(time64_t));
- msg.type = SND_MPOA_RES_RTRY;
- memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN);
- msg.content.in_info = entry->ctrl_info;
- qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
- if (qos != NULL)
- msg.qos = qos->qos;
- msg_to_mpoad(&msg, client);
- entry->reply_wait = ktime_get_seconds();
- }
- }
- entry = entry->next;
- }
- read_unlock_bh(&client->ingress_lock);
-}
-
-/* Call this every MPC-p5 seconds. */
-static void refresh_entries(struct mpoa_client *client)
-{
- time64_t now;
- struct in_cache_entry *entry = client->in_cache;
-
- ddprintk("refresh_entries\n");
- now = ktime_get_seconds();
-
- read_lock_bh(&client->ingress_lock);
- while (entry != NULL) {
- if (entry->entry_state == INGRESS_RESOLVED) {
- if (!(entry->refresh_time))
- entry->refresh_time = (2 * (entry->ctrl_info.holding_time))/3;
- if ((now - entry->reply_wait) >
- entry->refresh_time) {
- dprintk("refreshing an entry.\n");
- entry->entry_state = INGRESS_REFRESHING;
-
- }
- }
- entry = entry->next;
- }
- read_unlock_bh(&client->ingress_lock);
-}
-
-static void in_destroy_cache(struct mpoa_client *mpc)
-{
- write_lock_irq(&mpc->ingress_lock);
- while (mpc->in_cache != NULL)
- mpc->in_ops->remove_entry(mpc->in_cache, mpc);
- write_unlock_irq(&mpc->ingress_lock);
-}
-
-static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id,
- struct mpoa_client *mpc)
-{
- eg_cache_entry *entry;
-
- read_lock_irq(&mpc->egress_lock);
- entry = mpc->eg_cache;
- while (entry != NULL) {
- if (entry->ctrl_info.cache_id == cache_id) {
- refcount_inc(&entry->use);
- read_unlock_irq(&mpc->egress_lock);
- return entry;
- }
- entry = entry->next;
- }
- read_unlock_irq(&mpc->egress_lock);
-
- return NULL;
-}
-
-/* This can be called from any context since it saves CPU flags */
-static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc)
-{
- unsigned long flags;
- eg_cache_entry *entry;
-
- read_lock_irqsave(&mpc->egress_lock, flags);
- entry = mpc->eg_cache;
- while (entry != NULL) {
- if (entry->ctrl_info.tag == tag) {
- refcount_inc(&entry->use);
- read_unlock_irqrestore(&mpc->egress_lock, flags);
- return entry;
- }
- entry = entry->next;
- }
- read_unlock_irqrestore(&mpc->egress_lock, flags);
-
- return NULL;
-}
-
-/* This can be called from any context since it saves CPU flags */
-static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc,
- struct mpoa_client *mpc)
-{
- unsigned long flags;
- eg_cache_entry *entry;
-
- read_lock_irqsave(&mpc->egress_lock, flags);
- entry = mpc->eg_cache;
- while (entry != NULL) {
- if (entry->shortcut == vcc) {
- refcount_inc(&entry->use);
- read_unlock_irqrestore(&mpc->egress_lock, flags);
- return entry;
- }
- entry = entry->next;
- }
- read_unlock_irqrestore(&mpc->egress_lock, flags);
-
- return NULL;
-}
-
-static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr,
- struct mpoa_client *mpc)
-{
- eg_cache_entry *entry;
-
- read_lock_irq(&mpc->egress_lock);
- entry = mpc->eg_cache;
- while (entry != NULL) {
- if (entry->latest_ip_addr == ipaddr) {
- refcount_inc(&entry->use);
- read_unlock_irq(&mpc->egress_lock);
- return entry;
- }
- entry = entry->next;
- }
- read_unlock_irq(&mpc->egress_lock);
-
- return NULL;
-}
-
-static void eg_cache_put(eg_cache_entry *entry)
-{
- if (refcount_dec_and_test(&entry->use)) {
- kfree_sensitive(entry);
- }
-}
-
-/*
- * This should be called with write lock on
- */
-static void eg_cache_remove_entry(eg_cache_entry *entry,
- struct mpoa_client *client)
-{
- struct atm_vcc *vcc;
- struct k_message msg;
-
- vcc = entry->shortcut;
- dprintk("removing an egress entry.\n");
- if (entry->prev != NULL)
- entry->prev->next = entry->next;
- else
- client->eg_cache = entry->next;
- if (entry->next != NULL)
- entry->next->prev = entry->prev;
- client->eg_ops->put(entry);
- if (client->in_cache == NULL && client->eg_cache == NULL) {
- msg.type = STOP_KEEP_ALIVE_SM;
- msg_to_mpoad(&msg, client);
- }
-
- /* Check if the ingress side still uses this VCC */
- if (vcc != NULL) {
- in_cache_entry *in_entry = client->in_ops->get_by_vcc(vcc, client);
- if (in_entry != NULL) {
- client->in_ops->put(in_entry);
- return;
- }
- vcc_release_async(vcc, -EPIPE);
- }
-}
-
-static eg_cache_entry *eg_cache_add_entry(struct k_message *msg,
- struct mpoa_client *client)
-{
- eg_cache_entry *entry = kzalloc_obj(eg_cache_entry);
-
- if (entry == NULL) {
- pr_info("out of memory\n");
- return NULL;
- }
-
- dprintk("adding an egress entry, ip = %pI4, this should be our IP\n",
- &msg->content.eg_info.eg_dst_ip);
-
- refcount_set(&entry->use, 1);
- dprintk("new_eg_cache_entry: about to lock\n");
- write_lock_irq(&client->egress_lock);
- entry->next = client->eg_cache;
- entry->prev = NULL;
- if (client->eg_cache != NULL)
- client->eg_cache->prev = entry;
- client->eg_cache = entry;
-
- memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN);
- entry->ctrl_info = msg->content.eg_info;
- entry->time = ktime_get_seconds();
- entry->entry_state = EGRESS_RESOLVED;
- dprintk("new_eg_cache_entry cache_id %u\n",
- ntohl(entry->ctrl_info.cache_id));
- dprintk("mps_ip = %pI4\n", &entry->ctrl_info.mps_ip);
- refcount_inc(&entry->use);
-
- write_unlock_irq(&client->egress_lock);
- dprintk("new_eg_cache_entry: unlocked\n");
-
- return entry;
-}
-
-static void update_eg_cache_entry(eg_cache_entry *entry, uint16_t holding_time)
-{
- entry->time = ktime_get_seconds();
- entry->entry_state = EGRESS_RESOLVED;
- entry->ctrl_info.holding_time = holding_time;
-}
-
-static void clear_expired(struct mpoa_client *client)
-{
- eg_cache_entry *entry, *next_entry;
- time64_t now;
- struct k_message msg;
-
- now = ktime_get_seconds();
-
- write_lock_irq(&client->egress_lock);
- entry = client->eg_cache;
- while (entry != NULL) {
- next_entry = entry->next;
- if ((now - entry->time) > entry->ctrl_info.holding_time) {
- msg.type = SND_EGRESS_PURGE;
- msg.content.eg_info = entry->ctrl_info;
- dprintk("egress_cache: holding time expired, cache_id = %u.\n",
- ntohl(entry->ctrl_info.cache_id));
- msg_to_mpoad(&msg, client);
- client->eg_ops->remove_entry(entry, client);
- }
- entry = next_entry;
- }
- write_unlock_irq(&client->egress_lock);
-}
-
-static void eg_destroy_cache(struct mpoa_client *mpc)
-{
- write_lock_irq(&mpc->egress_lock);
- while (mpc->eg_cache != NULL)
- mpc->eg_ops->remove_entry(mpc->eg_cache, mpc);
- write_unlock_irq(&mpc->egress_lock);
-}
-
-
-static const struct in_cache_ops ingress_ops = {
- .add_entry = in_cache_add_entry,
- .get = in_cache_get,
- .get_with_mask = in_cache_get_with_mask,
- .get_by_vcc = in_cache_get_by_vcc,
- .put = in_cache_put,
- .remove_entry = in_cache_remove_entry,
- .cache_hit = cache_hit,
- .clear_count = clear_count_and_expired,
- .check_resolving = check_resolving_entries,
- .refresh = refresh_entries,
- .destroy_cache = in_destroy_cache
-};
-
-static const struct eg_cache_ops egress_ops = {
- .add_entry = eg_cache_add_entry,
- .get_by_cache_id = eg_cache_get_by_cache_id,
- .get_by_tag = eg_cache_get_by_tag,
- .get_by_vcc = eg_cache_get_by_vcc,
- .get_by_src_ip = eg_cache_get_by_src_ip,
- .put = eg_cache_put,
- .remove_entry = eg_cache_remove_entry,
- .update = update_eg_cache_entry,
- .clear_expired = clear_expired,
- .destroy_cache = eg_destroy_cache
-};
-
-void atm_mpoa_init_cache(struct mpoa_client *mpc)
-{
- mpc->in_ops = &ingress_ops;
- mpc->eg_ops = &egress_ops;
-}
diff --git a/net/atm/mpoa_caches.h b/net/atm/mpoa_caches.h
deleted file mode 100644
index 464c4c7f8d1f..000000000000
--- a/net/atm/mpoa_caches.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef MPOA_CACHES_H
-#define MPOA_CACHES_H
-
-#include <linux/time64.h>
-#include <linux/netdevice.h>
-#include <linux/types.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/atmmpc.h>
-#include <linux/refcount.h>
-
-struct mpoa_client;
-
-void atm_mpoa_init_cache(struct mpoa_client *mpc);
-
-typedef struct in_cache_entry {
- struct in_cache_entry *next;
- struct in_cache_entry *prev;
- time64_t time;
- time64_t reply_wait;
- time64_t hold_down;
- uint32_t packets_fwded;
- uint16_t entry_state;
- uint32_t retry_time;
- uint32_t refresh_time;
- uint32_t count;
- struct atm_vcc *shortcut;
- uint8_t MPS_ctrl_ATM_addr[ATM_ESA_LEN];
- struct in_ctrl_info ctrl_info;
- refcount_t use;
-} in_cache_entry;
-
-struct in_cache_ops{
- in_cache_entry *(*add_entry)(__be32 dst_ip,
- struct mpoa_client *client);
- in_cache_entry *(*get)(__be32 dst_ip, struct mpoa_client *client);
- in_cache_entry *(*get_with_mask)(__be32 dst_ip,
- struct mpoa_client *client,
- __be32 mask);
- in_cache_entry *(*get_by_vcc)(struct atm_vcc *vcc,
- struct mpoa_client *client);
- void (*put)(in_cache_entry *entry);
- void (*remove_entry)(in_cache_entry *delEntry,
- struct mpoa_client *client );
- int (*cache_hit)(in_cache_entry *entry,
- struct mpoa_client *client);
- void (*clear_count)(struct mpoa_client *client);
- void (*check_resolving)(struct mpoa_client *client);
- void (*refresh)(struct mpoa_client *client);
- void (*destroy_cache)(struct mpoa_client *mpc);
-};
-
-typedef struct eg_cache_entry{
- struct eg_cache_entry *next;
- struct eg_cache_entry *prev;
- time64_t time;
- uint8_t MPS_ctrl_ATM_addr[ATM_ESA_LEN];
- struct atm_vcc *shortcut;
- uint32_t packets_rcvd;
- uint16_t entry_state;
- __be32 latest_ip_addr; /* The src IP address of the last packet */
- struct eg_ctrl_info ctrl_info;
- refcount_t use;
-} eg_cache_entry;
-
-struct eg_cache_ops{
- eg_cache_entry *(*add_entry)(struct k_message *msg, struct mpoa_client *client);
- eg_cache_entry *(*get_by_cache_id)(__be32 cache_id, struct mpoa_client *client);
- eg_cache_entry *(*get_by_tag)(__be32 cache_id, struct mpoa_client *client);
- eg_cache_entry *(*get_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client);
- eg_cache_entry *(*get_by_src_ip)(__be32 ipaddr, struct mpoa_client *client);
- void (*put)(eg_cache_entry *entry);
- void (*remove_entry)(eg_cache_entry *entry, struct mpoa_client *client);
- void (*update)(eg_cache_entry *entry, uint16_t holding_time);
- void (*clear_expired)(struct mpoa_client *client);
- void (*destroy_cache)(struct mpoa_client *mpc);
-};
-
-
-/* Ingress cache entry states */
-
-#define INGRESS_REFRESHING 3
-#define INGRESS_RESOLVED 2
-#define INGRESS_RESOLVING 1
-#define INGRESS_INVALID 0
-
-/* VCC states */
-
-#define OPEN 1
-#define CLOSED 0
-
-/* Egress cache entry states */
-
-#define EGRESS_RESOLVED 2
-#define EGRESS_PURGE 1
-#define EGRESS_INVALID 0
-
-#endif
diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c
deleted file mode 100644
index aaf64b953915..000000000000
--- a/net/atm/mpoa_proc.c
+++ /dev/null
@@ -1,307 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
-
-#ifdef CONFIG_PROC_FS
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/ktime.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
-#include <linux/atmmpc.h>
-#include <linux/atm.h>
-#include <linux/gfp.h>
-#include "mpc.h"
-#include "mpoa_caches.h"
-
-/*
- * mpoa_proc.c: Implementation MPOA client's proc
- * file system statistics
- */
-
-#if 1
-#define dprintk(format, args...) \
- printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
-#else
-#define dprintk(format, args...) \
- do { if (0) \
- printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
- } while (0)
-#endif
-
-#if 0
-#define ddprintk(format, args...) \
- printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
-#else
-#define ddprintk(format, args...) \
- do { if (0) \
- printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
- } while (0)
-#endif
-
-#define STAT_FILE_NAME "mpc" /* Our statistic file's name */
-
-extern struct mpoa_client *mpcs;
-extern struct proc_dir_entry *atm_proc_root; /* from proc.c. */
-
-static int proc_mpc_open(struct inode *inode, struct file *file);
-static ssize_t proc_mpc_write(struct file *file, const char __user *buff,
- size_t nbytes, loff_t *ppos);
-
-static int parse_qos(const char *buff);
-
-static const struct proc_ops mpc_proc_ops = {
- .proc_open = proc_mpc_open,
- .proc_read = seq_read,
- .proc_lseek = seq_lseek,
- .proc_write = proc_mpc_write,
- .proc_release = seq_release,
-};
-
-/*
- * Returns the state of an ingress cache entry as a string
- */
-static const char *ingress_state_string(int state)
-{
- switch (state) {
- case INGRESS_RESOLVING:
- return "resolving ";
- case INGRESS_RESOLVED:
- return "resolved ";
- case INGRESS_INVALID:
- return "invalid ";
- case INGRESS_REFRESHING:
- return "refreshing ";
- }
-
- return "";
-}
-
-/*
- * Returns the state of an egress cache entry as a string
- */
-static const char *egress_state_string(int state)
-{
- switch (state) {
- case EGRESS_RESOLVED:
- return "resolved ";
- case EGRESS_PURGE:
- return "purge ";
- case EGRESS_INVALID:
- return "invalid ";
- }
-
- return "";
-}
-
-/*
- * FIXME: mpcs (and per-mpc lists) have no locking whatsoever.
- */
-
-static void *mpc_start(struct seq_file *m, loff_t *pos)
-{
- loff_t l = *pos;
- struct mpoa_client *mpc;
-
- if (!l--)
- return SEQ_START_TOKEN;
- for (mpc = mpcs; mpc; mpc = mpc->next)
- if (!l--)
- return mpc;
- return NULL;
-}
-
-static void *mpc_next(struct seq_file *m, void *v, loff_t *pos)
-{
- struct mpoa_client *p = v;
- (*pos)++;
- return v == SEQ_START_TOKEN ? mpcs : p->next;
-}
-
-static void mpc_stop(struct seq_file *m, void *v)
-{
-}
-
-/*
- * READING function - called when the /proc/atm/mpoa file is read from.
- */
-static int mpc_show(struct seq_file *m, void *v)
-{
- struct mpoa_client *mpc = v;
- int i;
- in_cache_entry *in_entry;
- eg_cache_entry *eg_entry;
- time64_t now;
- unsigned char ip_string[16];
-
- if (v == SEQ_START_TOKEN) {
- atm_mpoa_disp_qos(m);
- return 0;
- }
-
- seq_printf(m, "\nInterface %d:\n\n", mpc->dev_num);
- seq_printf(m, "Ingress Entries:\nIP address State Holding time Packets fwded VPI VCI\n");
- now = ktime_get_seconds();
-
- for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) {
- unsigned long seconds_delta = now - in_entry->time;
-
- sprintf(ip_string, "%pI4", &in_entry->ctrl_info.in_dst_ip);
- seq_printf(m, "%-16s%s%-14lu%-12u",
- ip_string,
- ingress_state_string(in_entry->entry_state),
- in_entry->ctrl_info.holding_time -
- seconds_delta,
- in_entry->packets_fwded);
- if (in_entry->shortcut)
- seq_printf(m, " %-3d %-3d",
- in_entry->shortcut->vpi,
- in_entry->shortcut->vci);
- seq_printf(m, "\n");
- }
-
- seq_printf(m, "\n");
- seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n");
- for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) {
- unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr;
- unsigned long seconds_delta = now - eg_entry->time;
-
- for (i = 0; i < ATM_ESA_LEN; i++)
- seq_printf(m, "%02x", p[i]);
- seq_printf(m, "\n%-16lu%s%-14lu%-15u",
- (unsigned long)ntohl(eg_entry->ctrl_info.cache_id),
- egress_state_string(eg_entry->entry_state),
- (eg_entry->ctrl_info.holding_time - seconds_delta),
- eg_entry->packets_rcvd);
-
- /* latest IP address */
- sprintf(ip_string, "%pI4", &eg_entry->latest_ip_addr);
- seq_printf(m, "%-16s", ip_string);
-
- if (eg_entry->shortcut)
- seq_printf(m, " %-3d %-3d",
- eg_entry->shortcut->vpi,
- eg_entry->shortcut->vci);
- seq_printf(m, "\n");
- }
- seq_printf(m, "\n");
- return 0;
-}
-
-static const struct seq_operations mpc_op = {
- .start = mpc_start,
- .next = mpc_next,
- .stop = mpc_stop,
- .show = mpc_show
-};
-
-static int proc_mpc_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &mpc_op);
-}
-
-static ssize_t proc_mpc_write(struct file *file, const char __user *buff,
- size_t nbytes, loff_t *ppos)
-{
- char *page, *p;
- unsigned int len;
-
- if (nbytes == 0)
- return 0;
-
- if (nbytes >= PAGE_SIZE)
- nbytes = PAGE_SIZE-1;
-
- page = (char *)__get_free_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
-
- for (p = page, len = 0; len < nbytes; p++) {
- if (get_user(*p, buff++)) {
- free_page((unsigned long)page);
- return -EFAULT;
- }
- len += 1;
- if (*p == '\0' || *p == '\n')
- break;
- }
-
- *p = '\0';
-
- if (!parse_qos(page))
- printk("mpoa: proc_mpc_write: could not parse '%s'\n", page);
-
- free_page((unsigned long)page);
-
- return len;
-}
-
-static int parse_qos(const char *buff)
-{
- /* possible lines look like this
- * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu
- */
- unsigned char ip[4];
- int tx_pcr, tx_sdu, rx_pcr, rx_sdu;
- __be32 ipaddr;
- struct atm_qos qos;
-
- memset(&qos, 0, sizeof(struct atm_qos));
-
- if (sscanf(buff, "del %hhu.%hhu.%hhu.%hhu",
- ip, ip+1, ip+2, ip+3) == 4) {
- ipaddr = *(__be32 *)ip;
- return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr));
- }
-
- if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=tx",
- ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu) == 6) {
- rx_pcr = tx_pcr;
- rx_sdu = tx_sdu;
- } else if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=%d,%d",
- ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu, &rx_pcr, &rx_sdu) != 8)
- return 0;
-
- ipaddr = *(__be32 *)ip;
- qos.txtp.traffic_class = ATM_CBR;
- qos.txtp.max_pcr = tx_pcr;
- qos.txtp.max_sdu = tx_sdu;
- qos.rxtp.traffic_class = ATM_CBR;
- qos.rxtp.max_pcr = rx_pcr;
- qos.rxtp.max_sdu = rx_sdu;
- qos.aal = ATM_AAL5;
- dprintk("parse_qos(): setting qos parameters to tx=%d,%d rx=%d,%d\n",
- qos.txtp.max_pcr, qos.txtp.max_sdu,
- qos.rxtp.max_pcr, qos.rxtp.max_sdu);
-
- atm_mpoa_add_qos(ipaddr, &qos);
- return 1;
-}
-
-/*
- * INITIALIZATION function - called when module is initialized/loaded.
- */
-int mpc_proc_init(void)
-{
- struct proc_dir_entry *p;
-
- p = proc_create(STAT_FILE_NAME, 0, atm_proc_root, &mpc_proc_ops);
- if (!p) {
- pr_err("Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
- return -ENOMEM;
- }
- return 0;
-}
-
-/*
- * DELETING function - called when module is removed.
- */
-void mpc_proc_clean(void)
-{
- remove_proc_entry(STAT_FILE_NAME, atm_proc_root);
-}
-
-#endif /* CONFIG_PROC_FS */
diff --git a/net/atm/proc.c b/net/atm/proc.c
index 9bf736290e48..b650da764a23 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -21,11 +21,9 @@
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/netdevice.h>
-#include <linux/atmclip.h>
#include <linux/init.h> /* for __init */
#include <linux/slab.h>
#include <net/net_namespace.h>
-#include <net/atmclip.h>
#include <linux/uaccess.h>
#include <linux/param.h> /* for HZ */
#include <linux/atomic.h>
@@ -155,15 +153,6 @@ static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
class_name[vcc->qos.rxtp.traffic_class],
vcc->qos.txtp.min_pcr,
class_name[vcc->qos.txtp.traffic_class]);
- if (test_bit(ATM_VF_IS_CLIP, &vcc->flags)) {
- struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
- struct net_device *dev;
-
- dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL;
- seq_printf(seq, "CLIP, Itf:%s, Encap:",
- dev ? dev->name : "none?");
- seq_printf(seq, "%s", clip_vcc->encap ? "LLC/SNAP" : "None");
- }
seq_putc(seq, '\n');
}
diff --git a/net/bridge/br.c b/net/bridge/br.c
index c37e52e2f29a..a5e5b2db110e 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -464,10 +464,6 @@ static int __init br_init(void)
brioctl_set(br_ioctl_stub);
-#if IS_ENABLED(CONFIG_ATM_LANE)
- br_fdb_test_addr_hook = br_fdb_test_addr;
-#endif
-
#if IS_MODULE(CONFIG_BRIDGE_NETFILTER)
pr_info("bridge: filtering via arp/ip/ip6tables is no longer available "
"by default. Update your scripts to load br_netfilter if you "
@@ -506,9 +502,6 @@ static void __exit br_deinit(void)
rcu_barrier(); /* Wait for completion of call_rcu()'s */
br_nf_core_fini();
-#if IS_ENABLED(CONFIG_ATM_LANE)
- br_fdb_test_addr_hook = NULL;
-#endif
br_fdb_fini();
}
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index e2c17f620f00..9bcf6243914b 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -892,35 +892,6 @@ void br_fdb_delete_by_port(struct net_bridge *br,
spin_unlock_bh(&br->hash_lock);
}
-#if IS_ENABLED(CONFIG_ATM_LANE)
-/* Interface used by ATM LANE hook to test
- * if an addr is on some other bridge port */
-int br_fdb_test_addr(struct net_device *dev, unsigned char *addr)
-{
- struct net_bridge_fdb_entry *fdb;
- struct net_bridge_port *port;
- int ret;
-
- rcu_read_lock();
- port = br_port_get_rcu(dev);
- if (!port)
- ret = 0;
- else {
- const struct net_bridge_port *dst = NULL;
-
- fdb = br_fdb_find_rcu(port->br, addr, 0);
- if (fdb)
- dst = READ_ONCE(fdb->dst);
-
- ret = dst && dst->dev != dev &&
- dst->state == BR_STATE_FORWARDING;
- }
- rcu_read_unlock();
-
- return ret;
-}
-#endif /* CONFIG_ATM_LANE */
-
/*
* Fill buffer with forwarding table records in
* the API format.
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 361a9b84451e..bed1b1d9b282 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -855,7 +855,6 @@ void br_fdb_delete_by_port(struct net_bridge *br,
struct net_bridge_fdb_entry *br_fdb_find_rcu(struct net_bridge *br,
const unsigned char *addr,
__u16 vid);
-int br_fdb_test_addr(struct net_device *dev, unsigned char *addr);
int br_fdb_fillbuf(struct net_bridge *br, void *buf, unsigned long count,
unsigned long off);
int br_fdb_add_local(struct net_bridge *br, struct net_bridge_port *source,
@@ -2065,9 +2064,6 @@ void br_stp_port_timer_init(struct net_bridge_port *p);
unsigned long br_timer_value(const struct timer_list *timer);
/* br.c */
-#if IS_ENABLED(CONFIG_ATM_LANE)
-extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr);
-#endif
/* br_mrp.c */
#if IS_ENABLED(CONFIG_BRIDGE_MRP)
diff --git a/net/core/dev.c b/net/core/dev.c
index e59f6025067c..1be81928d6c7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5862,13 +5862,6 @@ static __latent_entropy void net_tx_action(void)
xfrm_dev_backlog(sd);
}
-#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_ATM_LANE)
-/* This hook is defined here for ATM LANE */
-int (*br_fdb_test_addr_hook)(struct net_device *dev,
- unsigned char *addr) __read_mostly;
-EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook);
-#endif
-
/**
* netdev_is_rx_handler_busy - check if receive handler is registered
* @dev: device to check