linux/net/atm/lec.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * lec.c: Lan Emulation driver
 *
 * Marko Kiiskila <[email protected]>
 */

#define pr_fmt(fmt)

#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[] =;
#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

#define LEC_UNRES_QUE_LEN

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)
{}

static inline void lec_arp_put(struct lec_arp_table *entry)
{}

static struct lane2_ops lane2_ops =;

static unsigned char bus_mac[ETH_ALEN] =;

/* Device structures */
static struct net_device *dev_lec[MAX_LEC_ITF];

#if IS_ENABLED(CONFIG_BRIDGE)
static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
{}
#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)
{}

static void
lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
{}

static void lec_tx_timeout(struct net_device *dev, unsigned int txqueue)
{}

static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
				  struct net_device *dev)
{}

/* The inverse routine to net_open(). */
static int lec_close(struct net_device *dev)
{}

static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
{}

static void lec_atm_close(struct atm_vcc *vcc)
{}

static const struct atmdev_ops lecdev_ops =;

static struct atm_dev lecatm_dev =;

/*
 * 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)
{}

static void lec_set_multicast_list(struct net_device *dev)
{}

static const struct net_device_ops lec_netdev_ops =;

static const unsigned char lec_ctrl_magic[] =;

#define LEC_DATA_DIRECT_8023
#define LEC_DATA_DIRECT_8025

static int lec_is_data_direct(struct atm_vcc *vcc)
{}

static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
{}

static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
{}

static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
{}

static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
{}

/* Initialize device. */
static int lecd_attach(struct atm_vcc *vcc, int arg)
{}

#ifdef CONFIG_PROC_FS
static const char *lec_arp_get_status_string(unsigned char status)
{}

static void lec_info(struct seq_file *seq, struct lec_arp_table *entry)
{}

struct lec_state {};

static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl,
			  loff_t *l)
{}

static void *lec_arp_walk(struct lec_state *state, loff_t *l,
			  struct lec_priv *priv)
{}

static void *lec_misc_walk(struct lec_state *state, loff_t *l,
			   struct lec_priv *priv)
{}

static void *lec_priv_walk(struct lec_state *state, loff_t *l,
			   struct lec_priv *priv)
{}

static void *lec_itf_walk(struct lec_state *state, loff_t *l)
{}

static void *lec_get_idx(struct lec_state *state, loff_t l)
{}

static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
{}

static void lec_seq_stop(struct seq_file *seq, void *v)
{}

static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{}

static int lec_seq_show(struct seq_file *seq, void *v)
{}

static const struct seq_operations lec_seq_ops =;
#endif

static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{}

static struct atm_ioctl lane_ioctl_ops =;

static int __init lane_module_init(void)
{}

static void __exit lane_module_cleanup(void)
{}

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)
{}

/*
 * 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)
{}

/*
 * 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)
{}

/*
 * 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
/*
  #define pr_debug printk
*/
#endif
#define DEBUG_ARP_TABLE

#define LEC_ARP_REFRESH_INTERVAL

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)

/*
 * Initialization of arp-cache
 */
static void lec_arp_init(struct lec_priv *priv)
{}

static void lec_arp_clear_vccs(struct lec_arp_table *entry)
{}

/*
 * 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)
{}

/*
 * Remove entry from lec_arp_table
 */
static int
lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)
{}

#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)
#endif

/*
 * Destruction of arp-cache
 */
static void lec_arp_destroy(struct lec_priv *priv)
{}

/*
 * Find entry by mac_address
 */
static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
					  const unsigned char *mac_addr)
{}

static struct lec_arp_table *make_entry(struct lec_priv *priv,
					const unsigned char *mac_addr)
{}

/* Arp sent timer expired */
static void lec_arp_expire_arp(struct timer_list *t)
{}

/* Unknown/unused vcc expire, remove associated entry */
static void lec_arp_expire_vcc(struct timer_list *t)
{}

static bool __lec_arp_check_expire(struct lec_arp_table *entry,
				   unsigned long now,
				   struct lec_priv *priv)
{}
/*
 * 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)
{}

/*
 * 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)
{}

static int
lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr,
		unsigned long permanent)
{}

/*
 * 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)
{}

/*
 * 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))
{}

static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
{}

static void
lec_set_flush_tran_id(struct lec_priv *priv,
		      const unsigned char *atm_addr, unsigned long tran_id)
{}

static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
{}

static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
{}

static void
lec_arp_check_empties(struct lec_priv *priv,
		      struct atm_vcc *vcc, struct sk_buff *skb)
{}

MODULE_DESCRIPTION();
MODULE_LICENSE();