Blame view

net/atm/lec.c 58.2 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
3
   * lec.c: Lan Emulation driver
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   *
d44f77466   Chas Williams   [ATM]: [lec] inde...
5
   * Marko Kiiskila <mkiiskila@yahoo.com>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
   */
99824461e   Joe Perches   net/atm: Convert ...
7
  #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
5a0e3ad6a   Tejun Heo   include cleanup: ...
8
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
  #include <linux/kernel.h>
  #include <linux/bitops.h>
4fc268d24   Randy Dunlap   [PATCH] capable/c...
11
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
18
19
20
  
  /* 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>
c48192a70   Joe Perches   net/atm/lec.c: ch...
21
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
  #include <net/arp.h>
  #include <net/dst.h>
  #include <linux/proc_fs.h>
  #include <linux/spinlock.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
  /* And atm device */
  #include <linux/atmdev.h>
  #include <linux/atmlec.h>
  
  /* Proxy LEC knows about bridging */
9a81c34ac   Javier Martinez Canillas   lec: use IS_ENABL...
32
  #if IS_ENABLED(CONFIG_BRIDGE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #include "../bridge/br_private.h"
d44f77466   Chas Williams   [ATM]: [lec] inde...
34
  static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
  #endif
  
  /* Modular too */
  #include <linux/module.h>
  #include <linux/init.h>
acf784bd0   Gustavo A. R. Silva   net: atm: Fix pot...
40
41
  /* Hardening for Spectre-v1 */
  #include <linux/nospec.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  #include "lec.h"
  #include "lec_arpc.h"
  #include "resources.h"
d44f77466   Chas Williams   [ATM]: [lec] inde...
45
46
47
48
49
  #define DUMP_PACKETS 0		/*
  				 * 0 = None,
  				 * 1 = 30 first bytes
  				 * 2 = Whole packet
  				 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

d44f77466   Chas Williams   [ATM]: [lec] inde...
51
52
53
54
  #define LEC_UNRES_QUE_LEN 8	/*
  				 * number of tx packets to queue for a
  				 * single destination while waiting for SVC
  				 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
  
  static int lec_open(struct net_device *dev);
3c805a22a   Stephen Hemminger   convert ATM drive...
57
58
  static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
  				  struct net_device *dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  static int lec_close(struct net_device *dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
60
  static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
61c33e012   Mitchell Blank Jr   atm: use const wh...
61
  					  const unsigned char *mac_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  static int lec_arp_remove(struct lec_priv *priv,
d44f77466   Chas Williams   [ATM]: [lec] inde...
63
  			  struct lec_arp_table *to_remove);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  /* LANE2 functions */
61c33e012   Mitchell Blank Jr   atm: use const wh...
65
66
67
  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,
d44f77466   Chas Williams   [ATM]: [lec] inde...
68
  			 u8 **tlvs, u32 *sizeoftlvs);
61c33e012   Mitchell Blank Jr   atm: use const wh...
69
70
  static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst,
  			       const u8 *tlvs, u32 sizeoftlvs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71

61c33e012   Mitchell Blank Jr   atm: use const wh...
72
  static int lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
  			   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);
d44f77466   Chas Williams   [ATM]: [lec] inde...
78
  static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
61c33e012   Mitchell Blank Jr   atm: use const wh...
79
  				       const unsigned char *mac_to_find,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
  				       int is_rdesc,
  				       struct lec_arp_table **ret_entry);
61c33e012   Mitchell Blank Jr   atm: use const wh...
82
  static void lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,
c48192a70   Joe Perches   net/atm/lec.c: ch...
83
84
  			   const unsigned char *atm_addr,
  			   unsigned long remoteflag,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
  			   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,
61c33e012   Mitchell Blank Jr   atm: use const wh...
89
  				  const unsigned char *atm_addr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  				  unsigned long tran_id);
c48192a70   Joe Perches   net/atm/lec.c: ch...
91
92
  static void lec_vcc_added(struct lec_priv *priv,
  			  const struct atmlec_ioc *ioc_data,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  			  struct atm_vcc *vcc,
c48192a70   Joe Perches   net/atm/lec.c: ch...
94
95
  			  void (*old_push)(struct atm_vcc *vcc,
  					   struct sk_buff *skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
97
98
99
  /* must be done under lec_arp_lock */
  static inline void lec_arp_hold(struct lec_arp_table *entry)
  {
788936641   Reshetova, Elena   net, atm: convert...
100
  	refcount_inc(&entry->usage);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
101
102
103
104
  }
  
  static inline void lec_arp_put(struct lec_arp_table *entry)
  {
788936641   Reshetova, Elena   net, atm: convert...
105
  	if (refcount_dec_and_test(&entry->usage))
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
106
107
  		kfree(entry);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  static struct lane2_ops lane2_ops = {
99a5e178b   Kees Cook   ATM: use designat...
109
110
111
  	.resolve = lane2_resolve,		/* spec 3.1.3 */
  	.associate_req = lane2_associate_req,	/* spec 3.1.4 */
  	.associate_indicator = NULL             /* spec 3.1.5 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  };
d44f77466   Chas Williams   [ATM]: [lec] inde...
113
  static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
  
  /* Device structures */
  static struct net_device *dev_lec[MAX_LEC_ITF];
9a81c34ac   Javier Martinez Canillas   lec: use IS_ENABL...
117
  #if IS_ENABLED(CONFIG_BRIDGE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
  static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
120
121
122
123
124
125
126
127
  	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
  	 */
d44f77466   Chas Williams   [ATM]: [lec] inde...
128
129
  	buff = skb->data + skb->dev->hard_header_len;
  	if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  		struct sock *sk;
d44f77466   Chas Williams   [ATM]: [lec] inde...
131
132
133
134
135
136
137
138
139
140
  		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;
c48192a70   Joe Perches   net/atm/lec.c: ch...
141
142
  		mesg->content.normal.flag = *buff & 0x01;
  					/* 0x01 is topology change */
d44f77466   Chas Williams   [ATM]: [lec] inde...
143

524ad0a79   Wang Chen   netdevice: safe c...
144
  		priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
145
  		atm_force_charge(priv->lecd, skb2->truesize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  		sk = sk_atm(priv->lecd);
d44f77466   Chas Williams   [ATM]: [lec] inde...
147
  		skb_queue_tail(&sk->sk_receive_queue, skb2);
676d23690   David S. Miller   net: Fix use afte...
148
  		sk->sk_data_ready(sk);
d44f77466   Chas Williams   [ATM]: [lec] inde...
149
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  }
9a81c34ac   Javier Martinez Canillas   lec: use IS_ENABL...
151
  #endif /* IS_ENABLED(CONFIG_BRIDGE) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
   * 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.
   */
d44f77466   Chas Williams   [ATM]: [lec] inde...
161
  static int lec_open(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  	netif_start_queue(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
164
165
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  }
162619e59   Stephen Hemminger   lec: convert to i...
167
168
  static void
  lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  {
162619e59   Stephen Hemminger   lec: convert to i...
170
  	struct net_device *dev = skb->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  	ATM_SKB(skb)->vcc = vcc;
9bbe60a67   David Woodhouse   atm: Preserve val...
172
  	atm_account_tx(vcc, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  	if (vcc->send(vcc, skb) < 0) {
162619e59   Stephen Hemminger   lec: convert to i...
175
  		dev->stats.tx_dropped++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
  		return;
  	}
162619e59   Stephen Hemminger   lec: convert to i...
178
179
  	dev->stats.tx_packets++;
  	dev->stats.tx_bytes += skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  }
0290bd291   Michael S. Tsirkin   netdev: pass the ...
181
  static void lec_tx_timeout(struct net_device *dev, unsigned int txqueue)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  {
99824461e   Joe Perches   net/atm: Convert ...
183
184
  	pr_info("%s
  ", dev->name);
860e9538a   Florian Westphal   treewide: replace...
185
  	netif_trans_update(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
  	netif_wake_queue(dev);
  }
3c805a22a   Stephen Hemminger   convert ATM drive...
188
189
  static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
  				  struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
191
  	struct sk_buff *skb2;
524ad0a79   Wang Chen   netdevice: safe c...
192
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
193
194
  	struct lecdatahdr_8023 *lec_h;
  	struct atm_vcc *vcc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  	struct lec_arp_table *entry;
d44f77466   Chas Williams   [ATM]: [lec] inde...
196
  	unsigned char *dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
  	int min_frame_size;
d44f77466   Chas Williams   [ATM]: [lec] inde...
198
  	int is_rdesc;
d44f77466   Chas Williams   [ATM]: [lec] inde...
199

99824461e   Joe Perches   net/atm: Convert ...
200
201
  	pr_debug("called
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
202
  	if (!priv->lecd) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
203
204
  		pr_info("%s:No lecd attached
  ", dev->name);
162619e59   Stephen Hemminger   lec: convert to i...
205
  		dev->stats.tx_errors++;
d44f77466   Chas Williams   [ATM]: [lec] inde...
206
  		netif_stop_queue(dev);
81fbbf604   Patrick McHardy   net: fix network ...
207
208
  		kfree_skb(skb);
  		return NETDEV_TX_OK;
d44f77466   Chas Williams   [ATM]: [lec] inde...
209
  	}
522400623   Stephen Hemminger   [ATM]: Replace DP...
210
211
  	pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx
  ",
99824461e   Joe Perches   net/atm: Convert ...
212
213
  		 (long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb),
  		 (long)skb_end_pointer(skb));
9a81c34ac   Javier Martinez Canillas   lec: use IS_ENABL...
214
  #if IS_ENABLED(CONFIG_BRIDGE)
d44f77466   Chas Williams   [ATM]: [lec] inde...
215
216
  	if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0)
  		lec_handle_bridge(skb, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
218
219
  	/* Make sure we have room for lec_id */
  	if (skb_headroom(skb) < 2) {
99824461e   Joe Perches   net/atm: Convert ...
220
221
  		pr_debug("reallocating skb
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
222
  		skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
5d0ba55b6   Eric Dumazet   net: use consume_...
223
224
  		if (unlikely(!skb2)) {
  			kfree_skb(skb);
6ed106549   Patrick McHardy   net: use NETDEV_T...
225
  			return NETDEV_TX_OK;
5d0ba55b6   Eric Dumazet   net: use consume_...
226
227
  		}
  		consume_skb(skb);
d44f77466   Chas Williams   [ATM]: [lec] inde...
228
229
230
  		skb = skb2;
  	}
  	skb_push(skb, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231

60eea6cf2   Paul Gortmaker   atm: remove the c...
232
  	/* Put le header to place */
d44f77466   Chas Williams   [ATM]: [lec] inde...
233
234
  	lec_h = (struct lecdatahdr_8023 *)skb->data;
  	lec_h->le_header = htons(priv->lecid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
  #if DUMP_PACKETS >= 2
c48192a70   Joe Perches   net/atm/lec.c: ch...
237
  #define MAX_DUMP_SKB 99
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  #elif DUMP_PACKETS >= 1
c48192a70   Joe Perches   net/atm/lec.c: ch...
239
240
241
242
243
244
245
246
  #define MAX_DUMP_SKB 30
  #endif
  #if DUMP_PACKETS >= 1
  	printk(KERN_DEBUG "%s: send datalen:%ld lecid:%4.4x
  ",
  	       dev->name, skb->len, priv->lecid);
  	print_hex_dump(KERN_DEBUG, "", DUMP_OFFSET, 16, 1,
  		       skb->data, min(skb->len, MAX_DUMP_SKB), true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  #endif /* DUMP_PACKETS >= 1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248

d44f77466   Chas Williams   [ATM]: [lec] inde...
249
  	/* Minimum ethernet-frame size */
60eea6cf2   Paul Gortmaker   atm: remove the c...
250
  	min_frame_size = LEC_MINIMUM_8023_SIZE;
d44f77466   Chas Williams   [ATM]: [lec] inde...
251
252
253
254
255
256
257
  	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) {
162619e59   Stephen Hemminger   lec: convert to i...
258
  				dev->stats.tx_dropped++;
6ed106549   Patrick McHardy   net: use NETDEV_T...
259
  				return NETDEV_TX_OK;
d44f77466   Chas Williams   [ATM]: [lec] inde...
260
261
262
  			}
  			skb = skb2;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  		skb_put(skb, min_frame_size - skb->len);
d44f77466   Chas Williams   [ATM]: [lec] inde...
264
265
266
267
268
  	}
  
  	/* Send to right vcc */
  	is_rdesc = 0;
  	dst = lec_h->h_dest;
d44f77466   Chas Williams   [ATM]: [lec] inde...
269
270
  	entry = NULL;
  	vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
99824461e   Joe Perches   net/atm: Convert ...
271
272
273
  	pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p
  ",
  		 dev->name, vcc, vcc ? vcc->flags : 0, entry);
d44f77466   Chas Williams   [ATM]: [lec] inde...
274
275
  	if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) {
  		if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
99824461e   Joe Perches   net/atm: Convert ...
276
277
278
  			pr_debug("%s:queuing packet, MAC address %pM
  ",
  				 dev->name, lec_h->h_dest);
d44f77466   Chas Williams   [ATM]: [lec] inde...
279
280
  			skb_queue_tail(&entry->tx_wait, skb);
  		} else {
99824461e   Joe Perches   net/atm: Convert ...
281
282
283
  			pr_debug("%s:tx queue full or no arp entry, dropping, MAC address: %pM
  ",
  				 dev->name, lec_h->h_dest);
162619e59   Stephen Hemminger   lec: convert to i...
284
  			dev->stats.tx_dropped++;
d44f77466   Chas Williams   [ATM]: [lec] inde...
285
286
  			dev_kfree_skb(skb);
  		}
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
287
  		goto out;
d44f77466   Chas Williams   [ATM]: [lec] inde...
288
289
  	}
  #if DUMP_PACKETS > 0
c48192a70   Joe Perches   net/atm/lec.c: ch...
290
291
292
  	printk(KERN_DEBUG "%s:sending to vpi:%d vci:%d
  ",
  	       dev->name, vcc->vpi, vcc->vci);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  #endif /* DUMP_PACKETS > 0 */
d44f77466   Chas Williams   [ATM]: [lec] inde...
294
295
  
  	while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
99824461e   Joe Perches   net/atm: Convert ...
296
297
  		pr_debug("emptying tx queue, MAC address %pM
  ", lec_h->h_dest);
162619e59   Stephen Hemminger   lec: convert to i...
298
  		lec_send(vcc, skb2);
d44f77466   Chas Williams   [ATM]: [lec] inde...
299
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300

162619e59   Stephen Hemminger   lec: convert to i...
301
  	lec_send(vcc, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
  
  	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);
  	}
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
318
319
320
  out:
  	if (entry)
  		lec_arp_put(entry);
860e9538a   Florian Westphal   treewide: replace...
321
  	netif_trans_update(dev);
6ed106549   Patrick McHardy   net: use NETDEV_T...
322
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
  }
  
  /* The inverse routine to net_open(). */
d44f77466   Chas Williams   [ATM]: [lec] inde...
326
  static int lec_close(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
328
329
  	netif_stop_queue(dev);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
331
  static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
  {
  	unsigned long flags;
d44f77466   Chas Williams   [ATM]: [lec] inde...
334
  	struct net_device *dev = (struct net_device *)vcc->proto_data;
524ad0a79   Wang Chen   netdevice: safe c...
335
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
336
337
338
339
  	struct atmlec_msg *mesg;
  	struct lec_arp_table *entry;
  	int i;
  	char *tmp;		/* FIXME */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340

14afee4b6   Reshetova, Elena   net: convert sock...
341
  	WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc));
d44f77466   Chas Williams   [ATM]: [lec] inde...
342
343
344
  	mesg = (struct atmlec_msg *)skb->data;
  	tmp = skb->data;
  	tmp += sizeof(struct atmlec_msg);
522400623   Stephen Hemminger   [ATM]: Replace DP...
345
346
  	pr_debug("%s: msg from zeppelin:%d
  ", dev->name, mesg->type);
d44f77466   Chas Williams   [ATM]: [lec] inde...
347
348
  	switch (mesg->type) {
  	case l_set_mac_addr:
c48192a70   Joe Perches   net/atm/lec.c: ch...
349
  		for (i = 0; i < 6; i++)
d44f77466   Chas Williams   [ATM]: [lec] inde...
350
  			dev->dev_addr[i] = mesg->content.normal.mac_addr[i];
d44f77466   Chas Williams   [ATM]: [lec] inde...
351
352
  		break;
  	case l_del_mac_addr:
c48192a70   Joe Perches   net/atm/lec.c: ch...
353
  		for (i = 0; i < 6; i++)
d44f77466   Chas Williams   [ATM]: [lec] inde...
354
  			dev->dev_addr[i] = 0;
d44f77466   Chas Williams   [ATM]: [lec] inde...
355
356
357
358
359
360
361
362
363
364
365
366
  		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 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  		spin_lock_irqsave(&priv->lec_arp_lock, flags);
d44f77466   Chas Williams   [ATM]: [lec] inde...
368
369
  		entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
  		lec_arp_remove(priv, entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  		spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
d44f77466   Chas Williams   [ATM]: [lec] inde...
371
372
  		if (mesg->content.normal.no_source_le_narp)
  			break;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
373
  		fallthrough;
d44f77466   Chas Williams   [ATM]: [lec] inde...
374
375
376
377
378
  	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);
99824461e   Joe Perches   net/atm: Convert ...
379
380
  		pr_debug("in l_arp_update
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
381
  		if (mesg->sizeoftlvs != 0) {	/* LANE2 3.1.5 */
99824461e   Joe Perches   net/atm: Convert ...
382
383
384
  			pr_debug("LANE2 3.1.5, got tlvs, size %d
  ",
  				 mesg->sizeoftlvs);
d44f77466   Chas Williams   [ATM]: [lec] inde...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
  			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);
c48192a70   Joe Perches   net/atm/lec.c: ch...
403
404
  		priv->lane_version = mesg->content.config.lane_version;
  					/* LANE2 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
  		priv->lane2_ops = NULL;
  		if (priv->lane_version > 1)
  			priv->lane2_ops = &lane2_ops;
6df378d2d   chas williams - CONTRACTOR   lec: Use rtnl loc...
408
  		rtnl_lock();
1f1900f93   Stephen Hemminger   atm: lec use dev_...
409
  		if (dev_set_mtu(dev, mesg->content.config.mtu))
c48192a70   Joe Perches   net/atm/lec.c: ch...
410
411
412
  			pr_info("%s: change_mtu to %d failed
  ",
  				dev->name, mesg->content.config.mtu);
6df378d2d   chas williams - CONTRACTOR   lec: Use rtnl loc...
413
  		rtnl_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  		priv->is_proxy = mesg->content.config.is_proxy;
d44f77466   Chas Williams   [ATM]: [lec] inde...
415
416
417
418
419
420
421
422
423
424
  		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:
9a81c34ac   Javier Martinez Canillas   lec: use IS_ENABL...
425
  #if IS_ENABLED(CONFIG_BRIDGE)
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
426
427
428
429
  	{
  		pr_debug("%s: bridge zeppelin asks about %pM
  ",
  			 dev->name, mesg->content.proxy.mac_addr);
d44f77466   Chas Williams   [ATM]: [lec] inde...
430

b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
431
432
  		if (br_fdb_test_addr_hook == NULL)
  			break;
d44f77466   Chas Williams   [ATM]: [lec] inde...
433

b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
  		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
  ",
  				 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));
  			atm_force_charge(priv->lecd, skb2->truesize);
  			sk = sk_atm(priv->lecd);
  			skb_queue_tail(&sk->sk_receive_queue, skb2);
676d23690   David S. Miller   net: Fix use afte...
450
  			sk->sk_data_ready(sk);
d44f77466   Chas Williams   [ATM]: [lec] inde...
451
  		}
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
452
  	}
9a81c34ac   Javier Martinez Canillas   lec: use IS_ENABL...
453
  #endif /* IS_ENABLED(CONFIG_BRIDGE) */
d44f77466   Chas Williams   [ATM]: [lec] inde...
454
455
  		break;
  	default:
c48192a70   Joe Perches   net/atm/lec.c: ch...
456
457
  		pr_info("%s: Unknown message type %d
  ", dev->name, mesg->type);
d44f77466   Chas Williams   [ATM]: [lec] inde...
458
459
460
461
462
  		dev_kfree_skb(skb);
  		return -EINVAL;
  	}
  	dev_kfree_skb(skb);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
464
  static void lec_atm_close(struct atm_vcc *vcc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
466
467
  	struct sk_buff *skb;
  	struct net_device *dev = (struct net_device *)vcc->proto_data;
524ad0a79   Wang Chen   netdevice: safe c...
468
  	struct lec_priv *priv = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469

d44f77466   Chas Williams   [ATM]: [lec] inde...
470
471
  	priv->lecd = NULL;
  	/* Do something needful? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

d44f77466   Chas Williams   [ATM]: [lec] inde...
473
474
  	netif_stop_queue(dev);
  	lec_arp_destroy(priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475

d44f77466   Chas Williams   [ATM]: [lec] inde...
476
  	if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
c48192a70   Joe Perches   net/atm/lec.c: ch...
477
478
  		pr_info("%s closing with messages pending
  ", dev->name);
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
479
  	while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
d44f77466   Chas Williams   [ATM]: [lec] inde...
480
  		atm_return(vcc, skb->truesize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  		dev_kfree_skb(skb);
d44f77466   Chas Williams   [ATM]: [lec] inde...
482
  	}
c48192a70   Joe Perches   net/atm/lec.c: ch...
483
484
  	pr_info("%s: Shut down!
  ", dev->name);
d44f77466   Chas Williams   [ATM]: [lec] inde...
485
  	module_put(THIS_MODULE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
  }
800bb47e7   Bhumika Goyal   net: atm: make at...
487
  static const struct atmdev_ops lecdev_ops = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
488
489
  	.close = lec_atm_close,
  	.send = lec_atm_send
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
  };
  
  static struct atm_dev lecatm_dev = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
493
494
495
  	.ops = &lecdev_ops,
  	.type = "lec",
  	.number = 999,		/* dummy device number */
4ef8d0aea   Milind Arun Choudhary   [NET]: SPIN_LOCK_...
496
  	.lock = __SPIN_LOCK_UNLOCKED(lecatm_dev.lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
502
  };
  
  /*
   * LANE2: new argument struct sk_buff *data contains
   * the LE_ARP based TLVs introduced in the LANE2 spec
   */
d44f77466   Chas Williams   [ATM]: [lec] inde...
503
504
  static int
  send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
61c33e012   Mitchell Blank Jr   atm: use const wh...
505
  	     const unsigned char *mac_addr, const unsigned char *atm_addr,
d44f77466   Chas Williams   [ATM]: [lec] inde...
506
  	     struct sk_buff *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
  {
  	struct sock *sk;
  	struct sk_buff *skb;
  	struct atmlec_msg *mesg;
c48192a70   Joe Perches   net/atm/lec.c: ch...
511
  	if (!priv || !priv->lecd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
516
517
  	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;
d44f77466   Chas Williams   [ATM]: [lec] inde...
518
  	memset(mesg, 0, sizeof(struct atmlec_msg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  	mesg->type = type;
d44f77466   Chas Williams   [ATM]: [lec] inde...
520
521
  	if (data != NULL)
  		mesg->sizeoftlvs = data->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  	if (mac_addr)
9be68c1ae   David S. Miller   net: Fix some fal...
523
  		ether_addr_copy(mesg->content.normal.mac_addr, mac_addr);
d44f77466   Chas Williams   [ATM]: [lec] inde...
524
525
  	else
  		mesg->content.normal.targetless_le_arp = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
  	if (atm_addr)
  		memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
d44f77466   Chas Williams   [ATM]: [lec] inde...
528
  	atm_force_charge(priv->lecd, skb->truesize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
  	sk = sk_atm(priv->lecd);
  	skb_queue_tail(&sk->sk_receive_queue, skb);
676d23690   David S. Miller   net: Fix use afte...
531
  	sk->sk_data_ready(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532

d44f77466   Chas Williams   [ATM]: [lec] inde...
533
  	if (data != NULL) {
99824461e   Joe Perches   net/atm: Convert ...
534
535
  		pr_debug("about to send %d bytes of data
  ", data->len);
d44f77466   Chas Williams   [ATM]: [lec] inde...
536
537
  		atm_force_charge(priv->lecd, data->truesize);
  		skb_queue_tail(&sk->sk_receive_queue, data);
676d23690   David S. Miller   net: Fix use afte...
538
  		sk->sk_data_ready(sk);
d44f77466   Chas Williams   [ATM]: [lec] inde...
539
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540

d44f77466   Chas Williams   [ATM]: [lec] inde...
541
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
  static void lec_set_multicast_list(struct net_device *dev)
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
545
546
547
548
  	/*
  	 * by default, all multicast frames arrive over the bus.
  	 * eventually support selective multicast service
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  }
004b3225c   Stephen Hemminger   lec: convert to n...
550
551
552
553
  static const struct net_device_ops lec_netdev_ops = {
  	.ndo_open		= lec_open,
  	.ndo_stop		= lec_close,
  	.ndo_start_xmit		= lec_start_xmit,
004b3225c   Stephen Hemminger   lec: convert to n...
554
  	.ndo_tx_timeout		= lec_tx_timeout,
afc4b13df   Jiri Pirko   net: remove use o...
555
  	.ndo_set_rx_mode	= lec_set_multicast_list,
004b3225c   Stephen Hemminger   lec: convert to n...
556
  };
61c33e012   Mitchell Blank Jr   atm: use const wh...
557
  static const unsigned char lec_ctrl_magic[] = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
558
559
560
561
562
  	0xff,
  	0x00,
  	0x01,
  	0x01
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563

4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
564
565
566
567
  #define LEC_DATA_DIRECT_8023  2
  #define LEC_DATA_DIRECT_8025  3
  
  static int lec_is_data_direct(struct atm_vcc *vcc)
d44f77466   Chas Williams   [ATM]: [lec] inde...
568
  {
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
569
570
  	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));
d44f77466   Chas Williams   [ATM]: [lec] inde...
571
  }
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
572

d44f77466   Chas Williams   [ATM]: [lec] inde...
573
  static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
  {
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
575
  	unsigned long flags;
d44f77466   Chas Williams   [ATM]: [lec] inde...
576
  	struct net_device *dev = (struct net_device *)vcc->proto_data;
524ad0a79   Wang Chen   netdevice: safe c...
577
  	struct lec_priv *priv = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578

c48192a70   Joe Perches   net/atm/lec.c: ch...
579
  #if DUMP_PACKETS > 0
99824461e   Joe Perches   net/atm: Convert ...
580
581
582
  	printk(KERN_DEBUG "%s: vcc vpi:%d vci:%d
  ",
  	       dev->name, vcc->vpi, vcc->vci);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
584
  	if (!skb) {
522400623   Stephen Hemminger   [ATM]: Replace DP...
585
586
  		pr_debug("%s: null skb
  ", dev->name);
d44f77466   Chas Williams   [ATM]: [lec] inde...
587
588
589
  		lec_vcc_close(priv, vcc);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
  #if DUMP_PACKETS >= 2
99824461e   Joe Perches   net/atm: Convert ...
591
  #define MAX_SKB_DUMP 99
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  #elif DUMP_PACKETS >= 1
99824461e   Joe Perches   net/atm: Convert ...
593
594
595
596
597
598
599
600
  #define MAX_SKB_DUMP 30
  #endif
  #if DUMP_PACKETS > 0
  	printk(KERN_DEBUG "%s: rcv datalen:%ld lecid:%4.4x
  ",
  	       dev->name, skb->len, priv->lecid);
  	print_hex_dump(KERN_DEBUG, "", DUMP_OFFSET, 16, 1,
  		       skb->data, min(MAX_SKB_DUMP, skb->len), true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
  #endif /* DUMP_PACKETS > 0 */
99824461e   Joe Perches   net/atm: Convert ...
602
603
  	if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) {
  				/* Control frame, to daemon */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  		struct sock *sk = sk_atm(vcc);
522400623   Stephen Hemminger   [ATM]: Replace DP...
605
606
  		pr_debug("%s: To daemon
  ", dev->name);
d44f77466   Chas Williams   [ATM]: [lec] inde...
607
  		skb_queue_tail(&sk->sk_receive_queue, skb);
676d23690   David S. Miller   net: Fix use afte...
608
  		sk->sk_data_ready(sk);
d44f77466   Chas Williams   [ATM]: [lec] inde...
609
  	} else {		/* Data frame, queue to protocol handlers */
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
610
  		struct lec_arp_table *entry;
d44f77466   Chas Williams   [ATM]: [lec] inde...
611
612
613
  		unsigned char *src, *dst;
  
  		atm_return(vcc, skb->truesize);
30d492da7   Al Viro   [ATM]: Annotations.
614
  		if (*(__be16 *) skb->data == htons(priv->lecid) ||
d44f77466   Chas Williams   [ATM]: [lec] inde...
615
616
617
618
619
  		    !priv->lecd || !(dev->flags & IFF_UP)) {
  			/*
  			 * Probably looping back, or if lecd is missing,
  			 * lecd has gone down
  			 */
522400623   Stephen Hemminger   [ATM]: Replace DP...
620
621
  			pr_debug("Ignoring frame...
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
622
623
624
  			dev_kfree_skb(skb);
  			return;
  		}
60eea6cf2   Paul Gortmaker   atm: remove the c...
625
  		dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
626

d44f77466   Chas Williams   [ATM]: [lec] inde...
627
628
  		/*
  		 * If this is a Data Direct VCC, and the VCC does not match
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
629
630
631
632
  		 * 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)) {
60eea6cf2   Paul Gortmaker   atm: remove the c...
633
  			src = ((struct lecdatahdr_8023 *)skb->data)->h_source;
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
634
635
636
  			entry = lec_arp_find(priv, src);
  			if (entry && entry->vcc != vcc) {
  				lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
637
  				lec_arp_put(entry);
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
638
639
640
  			}
  		}
  		spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641

d44f77466   Chas Williams   [ATM]: [lec] inde...
642
643
  		if (!(dst[0] & 0x01) &&	/* Never filter Multi/Broadcast */
  		    !priv->is_proxy &&	/* Proxy wants all the packets */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  		    memcmp(dst, dev->dev_addr, dev->addr_len)) {
d44f77466   Chas Williams   [ATM]: [lec] inde...
645
646
647
  			dev_kfree_skb(skb);
  			return;
  		}
c48192a70   Joe Perches   net/atm/lec.c: ch...
648
  		if (!hlist_empty(&priv->lec_arp_empty_ones))
d44f77466   Chas Williams   [ATM]: [lec] inde...
649
  			lec_arp_check_empties(priv, vcc, skb);
d44f77466   Chas Williams   [ATM]: [lec] inde...
650
  		skb_pull(skb, 2);	/* skip lec_id */
60eea6cf2   Paul Gortmaker   atm: remove the c...
651
  		skb->protocol = eth_type_trans(skb, dev);
162619e59   Stephen Hemminger   lec: convert to i...
652
653
  		dev->stats.rx_packets++;
  		dev->stats.rx_bytes += skb->len;
d44f77466   Chas Williams   [ATM]: [lec] inde...
654
655
656
  		memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
  		netif_rx(skb);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
658
  static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
663
  {
  	struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
  	struct net_device *dev = skb->dev;
  
  	if (vpriv == NULL) {
99824461e   Joe Perches   net/atm: Convert ...
664
665
  		pr_info("vpriv = NULL!?!?!?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
667
668
669
670
671
672
673
674
675
676
  		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);
  	}
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
677
  static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
  {
  	struct lec_vcc_priv *vpriv;
d44f77466   Chas Williams   [ATM]: [lec] inde...
680
681
682
683
684
  	int bytes_left;
  	struct atmlec_ioc ioc_data;
  
  	/* Lecd must be up in this case */
  	bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
99824461e   Joe Perches   net/atm: Convert ...
685
686
687
  	if (bytes_left != 0)
  		pr_info("copy from user failed for %d bytes
  ", bytes_left);
acf784bd0   Gustavo A. R. Silva   net: atm: Fix pot...
688
689
690
691
  	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])
d44f77466   Chas Williams   [ATM]: [lec] inde...
692
  		return -EINVAL;
c48192a70   Joe Perches   net/atm/lec.c: ch...
693
694
  	vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
  	if (!vpriv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
697
698
699
  		return -ENOMEM;
  	vpriv->xoff = 0;
  	vpriv->old_pop = vcc->pop;
  	vcc->user_back = vpriv;
  	vcc->pop = lec_pop;
524ad0a79   Wang Chen   netdevice: safe c...
700
  	lec_vcc_added(netdev_priv(dev_lec[ioc_data.dev_num]),
d44f77466   Chas Williams   [ATM]: [lec] inde...
701
702
703
704
  		      &ioc_data, vcc, vcc->push);
  	vcc->proto_data = dev_lec[ioc_data.dev_num];
  	vcc->push = lec_push;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
706
  static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
  {
899537b73   Gustavo A. R. Silva   net: atm: Fix pot...
708
709
710
711
  	if (arg < 0 || arg >= MAX_LEC_ITF)
  		return -EINVAL;
  	arg = array_index_nospec(arg, MAX_LEC_ITF);
  	if (!dev_lec[arg])
d44f77466   Chas Williams   [ATM]: [lec] inde...
712
713
  		return -EINVAL;
  	vcc->proto_data = dev_lec[arg];
37d668004   Joe Perches   net/atm: Remove u...
714
  	return lec_mcast_make(netdev_priv(dev_lec[arg]), vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
  }
  
  /* Initialize device. */
d44f77466   Chas Williams   [ATM]: [lec] inde...
718
719
720
721
722
723
  static int lecd_attach(struct atm_vcc *vcc, int arg)
  {
  	int i;
  	struct lec_priv *priv;
  
  	if (arg < 0)
fdd1a8103   Dan Carpenter   net: atm: clean u...
724
  		arg = 0;
d44f77466   Chas Williams   [ATM]: [lec] inde...
725
726
  	if (arg >= MAX_LEC_ITF)
  		return -EINVAL;
899537b73   Gustavo A. R. Silva   net: atm: Fix pot...
727
  	i = array_index_nospec(arg, MAX_LEC_ITF);
d44f77466   Chas Williams   [ATM]: [lec] inde...
728
  	if (!dev_lec[i]) {
60eea6cf2   Paul Gortmaker   atm: remove the c...
729
  		int size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730

d44f77466   Chas Williams   [ATM]: [lec] inde...
731
  		size = sizeof(struct lec_priv);
60eea6cf2   Paul Gortmaker   atm: remove the c...
732
  		dev_lec[i] = alloc_etherdev(size);
d44f77466   Chas Williams   [ATM]: [lec] inde...
733
734
  		if (!dev_lec[i])
  			return -ENOMEM;
eb0445887   chas williams - CONTRACTOR   atm: [lec] initia...
735
  		dev_lec[i]->netdev_ops = &lec_netdev_ops;
8b6b4135e   Jarod Wilson   net: use core MTU...
736
  		dev_lec[i]->max_mtu = 18190;
d44f77466   Chas Williams   [ATM]: [lec] inde...
737
738
739
740
741
  		snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
  		if (register_netdev(dev_lec[i])) {
  			free_netdev(dev_lec[i]);
  			return -EINVAL;
  		}
524ad0a79   Wang Chen   netdevice: safe c...
742
  		priv = netdev_priv(dev_lec[i]);
d44f77466   Chas Williams   [ATM]: [lec] inde...
743
  	} else {
524ad0a79   Wang Chen   netdevice: safe c...
744
  		priv = netdev_priv(dev_lec[i]);
d44f77466   Chas Williams   [ATM]: [lec] inde...
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
  		if (priv->lecd)
  			return -EADDRINUSE;
  	}
  	lec_arp_init(priv);
  	priv->itfnum = i;	/* LANE2 addition */
  	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);
c48192a70   Joe Perches   net/atm/lec.c: ch...
769
  	if (dev_lec[i]->flags & IFF_UP)
d44f77466   Chas Williams   [ATM]: [lec] inde...
770
  		netif_start_queue(dev_lec[i]);
d44f77466   Chas Williams   [ATM]: [lec] inde...
771
772
  	__module_get(THIS_MODULE);
  	return i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
  }
  
  #ifdef CONFIG_PROC_FS
36cbd3dcc   Jan Engelhardt   net: mark read-on...
776
  static const char *lec_arp_get_status_string(unsigned char status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
  {
36cbd3dcc   Jan Engelhardt   net: mark read-on...
778
  	static const char *const lec_arp_status_string[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
  		"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)
  {
79ac52240   Andy Shevchenko   net: atm: use %*p...
794
795
796
  	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),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
799
800
  		   entry->flags & 0xffff);
  	if (entry->vcc)
  		seq_printf(seq, "%3d %3d ", entry->vcc->vpi, entry->vcc->vci);
  	else
d44f77466   Chas Williams   [ATM]: [lec] inde...
801
  		seq_printf(seq, "        ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
804
  	if (entry->recv_vcc) {
  		seq_printf(seq, "     %3d %3d", entry->recv_vcc->vpi,
  			   entry->recv_vcc->vci);
d44f77466   Chas Williams   [ATM]: [lec] inde...
805
806
807
  	}
  	seq_putc(seq, '
  ');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
811
  struct lec_state {
  	unsigned long flags;
  	struct lec_priv *locked;
d0732f649   Chas Williams   [ATM]: [lec] conv...
812
  	struct hlist_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
814
815
816
817
  	struct net_device *dev;
  	int itf;
  	int arp_table;
  	int misc_table;
  };
d0732f649   Chas Williams   [ATM]: [lec] conv...
818
  static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
820
  			  loff_t *l)
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
821
  	struct hlist_node *e = state->node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
  
  	if (!e)
d0732f649   Chas Williams   [ATM]: [lec] conv...
824
  		e = tbl->first;
2e1e9848a   Joe Perches   [ATM]: Use SEQ_ST...
825
  	if (e == SEQ_START_TOKEN) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
826
  		e = tbl->first;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
  		--*l;
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
829

8356f9d56   chas williams - CONTRACTOR   lec: Fix bug intr...
830
  	for (; e; e = e->next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
  		if (--*l < 0)
  			break;
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
834
  	state->node = e;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
838
  	return (*l < 0) ? state : NULL;
  }
  
  static void *lec_arp_walk(struct lec_state *state, loff_t *l,
d44f77466   Chas Williams   [ATM]: [lec] inde...
839
  			  struct lec_priv *priv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
842
843
844
  {
  	void *v = NULL;
  	int p;
  
  	for (p = state->arp_table; p < LEC_ARP_TABLE_SIZE; p++) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
845
  		v = lec_tbl_walk(state, &priv->lec_arp_tables[p], l);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
847
848
849
850
851
852
853
854
855
  		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)
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
856
857
858
859
  	struct hlist_head *lec_misc_tables[] = {
  		&priv->lec_arp_empty_ones,
  		&priv->lec_no_forward,
  		&priv->mcast_fwds
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
  	};
  	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);
  	}
d44f77466   Chas Williams   [ATM]: [lec] inde...
880
  	if (!lec_arp_walk(state, l, priv) && !lec_misc_walk(state, l, priv)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881
882
883
884
885
886
887
888
889
890
891
892
893
894
  		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];
524ad0a79   Wang Chen   netdevice: safe c...
895
896
  	v = (dev && netdev_priv(dev)) ?
  		lec_priv_walk(state, l, netdev_priv(dev)) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
  	if (!v && dev) {
  		dev_put(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;
  	}
d44f77466   Chas Williams   [ATM]: [lec] inde...
915
  	return v;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
917
918
919
920
921
922
923
924
925
926
  }
  
  static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
  {
  	struct lec_state *state = seq->private;
  
  	state->itf = 0;
  	state->dev = NULL;
  	state->locked = NULL;
  	state->arp_table = 0;
  	state->misc_table = 0;
2e1e9848a   Joe Perches   [ATM]: Use SEQ_ST...
927
  	state->node = SEQ_START_TOKEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928

2e1e9848a   Joe Perches   [ATM]: Use SEQ_ST...
929
  	return *pos ? lec_get_idx(state, *pos) : SEQ_START_TOKEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
  }
  
  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);
  		dev_put(state->dev);
  	}
  }
  
  static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	struct lec_state *state = seq->private;
2f71e0061   Colin Ian King   net: atm: fix upd...
946
947
  	++*pos;
  	return lec_get_idx(state, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
949
950
951
  }
  
  static int lec_seq_show(struct seq_file *seq, void *v)
  {
36cbd3dcc   Jan Engelhardt   net: mark read-on...
952
953
  	static const char lec_banner[] =
  	    "Itf  MAC          ATM destination"
d44f77466   Chas Williams   [ATM]: [lec] inde...
954
955
956
  	    "                          Status            Flags "
  	    "VPI/VCI Recv VPI/VCI
  ";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957

2e1e9848a   Joe Perches   [ATM]: Use SEQ_ST...
958
  	if (v == SEQ_START_TOKEN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
960
961
  		seq_puts(seq, lec_banner);
  	else {
  		struct lec_state *state = seq->private;
d44f77466   Chas Williams   [ATM]: [lec] inde...
962
  		struct net_device *dev = state->dev;
c48192a70   Joe Perches   net/atm/lec.c: ch...
963
964
965
  		struct lec_arp_table *entry = hlist_entry(state->node,
  							  struct lec_arp_table,
  							  next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
967
  
  		seq_printf(seq, "%s ", dev->name);
d0732f649   Chas Williams   [ATM]: [lec] conv...
968
  		lec_info(seq, entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
970
971
  	}
  	return 0;
  }
56b3d975b   Philippe De Muyter   [NET]: Make all i...
972
  static const struct seq_operations lec_seq_ops = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
973
974
975
976
  	.start = lec_seq_start,
  	.next = lec_seq_next,
  	.stop = lec_seq_stop,
  	.show = lec_seq_show,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
979
980
981
982
983
  #endif
  
  static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
  {
  	struct atm_vcc *vcc = ATM_SD(sock);
  	int err = 0;
d44f77466   Chas Williams   [ATM]: [lec] inde...
984

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
  	switch (cmd) {
d44f77466   Chas Williams   [ATM]: [lec] inde...
986
987
988
989
990
991
992
993
  	case ATMLEC_CTRL:
  	case ATMLEC_MCAST:
  	case ATMLEC_DATA:
  		if (!capable(CAP_NET_ADMIN))
  			return -EPERM;
  		break;
  	default:
  		return -ENOIOCTLCMD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
995
996
  	}
  
  	switch (cmd) {
d44f77466   Chas Williams   [ATM]: [lec] inde...
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
  	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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
1010
1011
1012
1013
  	}
  
  	return err;
  }
  
  static struct atm_ioctl lane_ioctl_ops = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
1014
1015
  	.owner = THIS_MODULE,
  	.ioctl = lane_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
1018
1019
1020
1021
  };
  
  static int __init lane_module_init(void)
  {
  #ifdef CONFIG_PROC_FS
  	struct proc_dir_entry *p;
44414d82c   Christoph Hellwig   proc: introduce p...
1022
1023
  	p = proc_create_seq_private("lec", 0444, atm_proc_root, &lec_seq_ops,
  			sizeof(struct lec_state), NULL);
dbee0d3f4   Wang Chen   [ATM]: When proc_...
1024
  	if (!p) {
99824461e   Joe Perches   net/atm: Convert ...
1025
1026
  		pr_err("Unable to initialize /proc/net/atm/lec
  ");
dbee0d3f4   Wang Chen   [ATM]: When proc_...
1027
1028
  		return -ENOMEM;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
1030
1031
  #endif
  
  	register_atm_ioctl(&lane_ioctl_ops);
36a9f77e5   Michal Marek   atm: Drop __TIME_...
1032
1033
  	pr_info("lec.c: initialized
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
1034
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
1036
1037
1038
  }
  
  static void __exit lane_module_cleanup(void)
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
1039
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040

9dd0f896d   Augusto Mecking Caringi   net: atm: Fix war...
1041
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
  	remove_proc_entry("lec", atm_proc_root);
9dd0f896d   Augusto Mecking Caringi   net: atm: Fix war...
1043
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
  
  	deregister_atm_ioctl(&lane_ioctl_ops);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1046
1047
  	for (i = 0; i < MAX_LEC_ITF; i++) {
  		if (dev_lec[i] != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
  			unregister_netdev(dev_lec[i]);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1049
1050
1051
1052
  			free_netdev(dev_lec[i]);
  			dev_lec[i] = NULL;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
1054
1055
1056
1057
1058
1059
1060
  }
  
  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.
563f63e39   Randy Dunlap   net: atm: delete ...
1061
   * If sizeoftlvs == NULL the default TLVs associated with this
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
1063
1064
   * lec will be used.
   * If dst_mac == NULL, targetless LE_ARP will be sent
   */
61c33e012   Mitchell Blank Jr   atm: use const wh...
1065
  static int lane2_resolve(struct net_device *dev, const u8 *dst_mac, int force,
d44f77466   Chas Williams   [ATM]: [lec] inde...
1066
  			 u8 **tlvs, u32 *sizeoftlvs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
  {
  	unsigned long flags;
524ad0a79   Wang Chen   netdevice: safe c...
1069
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1070
1071
1072
  	struct lec_arp_table *table;
  	struct sk_buff *skb;
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073

d44f77466   Chas Williams   [ATM]: [lec] inde...
1074
  	if (force == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1075
  		spin_lock_irqsave(&priv->lec_arp_lock, flags);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1076
  		table = lec_arp_find(priv, dst_mac);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
  		spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1078
1079
  		if (table == NULL)
  			return -1;
2afe37cdf   Arnaldo Carvalho de Melo   [ATM]: Use kmemdu...
1080
  		*tlvs = kmemdup(table->tlvs, table->sizeoftlvs, GFP_ATOMIC);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1081
1082
  		if (*tlvs == NULL)
  			return -1;
d44f77466   Chas Williams   [ATM]: [lec] inde...
1083
1084
1085
1086
  		*sizeoftlvs = table->sizeoftlvs;
  
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
1088
1089
  
  	if (sizeoftlvs == NULL)
  		retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, NULL);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1090

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
1092
1093
1094
1095
  	else {
  		skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC);
  		if (skb == NULL)
  			return -1;
  		skb->len = *sizeoftlvs;
27d7ff46a   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1096
  		skb_copy_to_linear_data(skb, *tlvs, *sizeoftlvs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
1098
  		retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb);
  	}
d44f77466   Chas Williams   [ATM]: [lec] inde...
1099
1100
  	return retval;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
1103
1104
1105
1106
1107
1108
  
  /*
   * 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)
   *
   */
61c33e012   Mitchell Blank Jr   atm: use const wh...
1109
1110
  static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst,
  			       const u8 *tlvs, u32 sizeoftlvs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1111
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
1112
1113
  	int retval;
  	struct sk_buff *skb;
524ad0a79   Wang Chen   netdevice: safe c...
1114
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1115

150238ebb   Joe Perches   atm: Convert comp...
1116
  	if (!ether_addr_equal(lan_dst, dev->dev_addr))
c48192a70   Joe Perches   net/atm/lec.c: ch...
1117
  		return 0;	/* not our mac address */
d44f77466   Chas Williams   [ATM]: [lec] inde...
1118
1119
  
  	kfree(priv->tlvs);	/* NULL if there was no previous association */
2afe37cdf   Arnaldo Carvalho de Melo   [ATM]: Use kmemdu...
1120
  	priv->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1121
  	if (priv->tlvs == NULL)
c48192a70   Joe Perches   net/atm/lec.c: ch...
1122
  		return 0;
d44f77466   Chas Williams   [ATM]: [lec] inde...
1123
  	priv->sizeoftlvs = sizeoftlvs;
d44f77466   Chas Williams   [ATM]: [lec] inde...
1124
1125
1126
1127
1128
  
  	skb = alloc_skb(sizeoftlvs, GFP_ATOMIC);
  	if (skb == NULL)
  		return 0;
  	skb->len = sizeoftlvs;
27d7ff46a   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1129
  	skb_copy_to_linear_data(skb, tlvs, sizeoftlvs);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1130
1131
  	retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
  	if (retval != 0)
c48192a70   Joe Perches   net/atm/lec.c: ch...
1132
1133
  		pr_info("lec.c: lane2_associate_req() failed
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
1134
1135
1136
1137
  	/*
  	 * If the previous association has changed we must
  	 * somehow notify other LANE entities about the change
  	 */
c48192a70   Joe Perches   net/atm/lec.c: ch...
1138
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
1140
1141
1142
1143
1144
  }
  
  /*
   * LANE2: 3.1.5, LE_ASSOCIATE.indication
   *
   */
61c33e012   Mitchell Blank Jr   atm: use const wh...
1145
1146
  static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr,
  				const u8 *tlvs, u32 sizeoftlvs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
  {
  #if 0
d44f77466   Chas Williams   [ATM]: [lec] inde...
1149
  	int i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
  #endif
524ad0a79   Wang Chen   netdevice: safe c...
1151
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1152
1153
1154
1155
1156
1157
1158
  #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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159

d44f77466   Chas Williams   [ATM]: [lec] inde...
1160
1161
  	if (entry == NULL)
  		return;		/* should not happen */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1162

d44f77466   Chas Williams   [ATM]: [lec] inde...
1163
  	kfree(entry->tlvs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164

2afe37cdf   Arnaldo Carvalho de Melo   [ATM]: Use kmemdu...
1165
  	entry->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1166
1167
  	if (entry->tlvs == NULL)
  		return;
d44f77466   Chas Williams   [ATM]: [lec] inde...
1168
  	entry->sizeoftlvs = sizeoftlvs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
1170
  #endif
  #if 0
c48192a70   Joe Perches   net/atm/lec.c: ch...
1171
1172
1173
1174
  	pr_info("
  ");
  	pr_info("dump of tlvs, sizeoftlvs=%d
  ", sizeoftlvs);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1175
  	while (i < sizeoftlvs)
c48192a70   Joe Perches   net/atm/lec.c: ch...
1176
  		pr_cont("%02x ", tlvs[i++]);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1177

c48192a70   Joe Perches   net/atm/lec.c: ch...
1178
1179
  	pr_cont("
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
1181
1182
1183
1184
1185
  	/* 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);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1186
1187
1188
1189
1190
1191
1192
  }
  
  /*
   * Here starts what used to lec_arpc.c
   *
   * lec_arpc.c was added here when making
   * lane client modular. October 1997
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
1194
1195
   */
  
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
  #include <linux/timer.h>
c48192a70   Joe Perches   net/atm/lec.c: ch...
1197
  #include <linux/param.h>
60063497a   Arun Sharma   atomic: use <linu...
1198
  #include <linux/atomic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
1200
  #include <linux/inetdevice.h>
  #include <net/route.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
  #if 0
c48192a70   Joe Perches   net/atm/lec.c: ch...
1202
  #define pr_debug(format, args...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203
  /*
99824461e   Joe Perches   net/atm: Convert ...
1204
    #define pr_debug printk
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1205
1206
1207
1208
1209
  */
  #endif
  #define DEBUG_ARP_TABLE 0
  
  #define LEC_ARP_REFRESH_INTERVAL (3*HZ)
c4028958b   David Howells   WorkStruct: make ...
1210
  static void lec_arp_check_expire(struct work_struct *work);
ba4217935   Kees Cook   net: atm: Convert...
1211
  static void lec_arp_expire_arp(struct timer_list *t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212

f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1213
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1214
1215
   * Arp table funcs
   */
c48192a70   Joe Perches   net/atm/lec.c: ch...
1216
  #define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE - 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
1218
1219
1220
  
  /*
   * Initialization of arp-cache
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1221
  static void lec_arp_init(struct lec_priv *priv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1223
  	unsigned short i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224

c48192a70   Joe Perches   net/atm/lec.c: ch...
1225
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
d0732f649   Chas Williams   [ATM]: [lec] conv...
1226
  		INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1227
1228
1229
  	INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
  	INIT_HLIST_HEAD(&priv->lec_no_forward);
  	INIT_HLIST_HEAD(&priv->mcast_fwds);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230
  	spin_lock_init(&priv->lec_arp_lock);
c4028958b   David Howells   WorkStruct: make ...
1231
  	INIT_DELAYED_WORK(&priv->lec_arp_work, lec_arp_check_expire);
987e46bdf   Chas Williams   [ATM]: [lec] use ...
1232
  	schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1234
  static void lec_arp_clear_vccs(struct lec_arp_table *entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1236
  	if (entry->vcc) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
1238
  		struct atm_vcc *vcc = entry->vcc;
  		struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1239
  		struct net_device *dev = (struct net_device *)vcc->proto_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1240

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1241
  		vcc->pop = vpriv->old_pop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242
1243
1244
1245
  		if (vpriv->xoff)
  			netif_wake_queue(dev);
  		kfree(vpriv);
  		vcc->user_back = NULL;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1246
  		vcc->push = entry->old_push;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
  		vcc_release_async(vcc, -EPIPE);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1248
  		entry->vcc = NULL;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1249
1250
  	}
  	if (entry->recv_vcc) {
8d9f73c0a   Cong Wang   atm: fix a memory...
1251
1252
1253
1254
1255
  		struct atm_vcc *vcc = entry->recv_vcc;
  		struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
  
  		kfree(vpriv);
  		vcc->user_back = NULL;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1256
  		entry->recv_vcc->push = entry->old_recv_push;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1257
  		vcc_release_async(entry->recv_vcc, -EPIPE);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1258
1259
  		entry->recv_vcc = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1260
1261
1262
1263
1264
1265
  }
  
  /*
   * Insert entry to lec_arp_table
   * LANE2: Add to the end of the list to satisfy 8.1.13
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1266
  static inline void
d0732f649   Chas Williams   [ATM]: [lec] conv...
1267
  lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1269
  	struct hlist_head *tmp;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1270

d0732f649   Chas Williams   [ATM]: [lec] conv...
1271
1272
  	tmp = &priv->lec_arp_tables[HASH(entry->mac_addr[ETH_ALEN - 1])];
  	hlist_add_head(&entry->next, tmp);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1273

99824461e   Joe Perches   net/atm: Convert ...
1274
1275
  	pr_debug("Added entry:%pM
  ", entry->mac_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
1278
1279
1280
  }
  
  /*
   * Remove entry from lec_arp_table
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1281
1282
  static int
  lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1283
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1284
1285
  	struct lec_arp_table *entry;
  	int i, remove_vcc = 1;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1286

c48192a70   Joe Perches   net/atm/lec.c: ch...
1287
  	if (!to_remove)
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1288
  		return -1;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1289
1290
  
  	hlist_del(&to_remove->next);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1291
  	del_timer(&to_remove->timer);
c48192a70   Joe Perches   net/atm/lec.c: ch...
1292
1293
1294
1295
  	/*
  	 * If this is the only MAC connected to this VCC,
  	 * also tear down the VCC
  	 */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1296
1297
1298
1299
  	if (to_remove->status >= ESI_FLUSH_PENDING) {
  		/*
  		 * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
  		 */
d0732f649   Chas Williams   [ATM]: [lec] conv...
1300
  		for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1301
  			hlist_for_each_entry(entry,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1302
  					     &priv->lec_arp_tables[i], next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1303
1304
  				if (memcmp(to_remove->atm_addr,
  					   entry->atm_addr, ATM_ESA_LEN) == 0) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1305
1306
1307
1308
1309
1310
1311
1312
1313
  					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? */
99824461e   Joe Perches   net/atm: Convert ...
1314
1315
  	pr_debug("Removed entry:%pM
  ", to_remove->mac_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1316
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317
1318
1319
  }
  
  #if DEBUG_ARP_TABLE
36cbd3dcc   Jan Engelhardt   net: mark read-on...
1320
  static const char *get_status_string(unsigned char st)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
  	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";
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1333
  	}
c48192a70   Joe Perches   net/atm/lec.c: ch...
1334
  	return "<UNKNOWN>";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1337
  static void dump_arp_table(struct lec_priv *priv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1339
  	struct lec_arp_table *rulla;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1340
  	char buf[256];
79ac52240   Andy Shevchenko   net: atm: use %*p...
1341
  	int i, offset;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1342

c48192a70   Joe Perches   net/atm/lec.c: ch...
1343
1344
  	pr_info("Dump %p:
  ", priv);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1345
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1346
  		hlist_for_each_entry(rulla,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1347
  				     &priv->lec_arp_tables[i], next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1348
1349
1350
  			offset = 0;
  			offset += sprintf(buf, "%d: %p
  ", i, rulla);
79ac52240   Andy Shevchenko   net: atm: use %*p...
1351
  			offset += sprintf(buf + offset, "Mac: %pM ",
c48192a70   Joe Perches   net/atm/lec.c: ch...
1352
  					  rulla->mac_addr);
79ac52240   Andy Shevchenko   net: atm: use %*p...
1353
1354
  			offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN,
  					  rulla->atm_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
  			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));
c48192a70   Joe Perches   net/atm/lec.c: ch...
1369
1370
  			pr_info("%s
  ", buf);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1371
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1372
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1373
1374
  
  	if (!hlist_empty(&priv->lec_no_forward))
c48192a70   Joe Perches   net/atm/lec.c: ch...
1375
1376
  		pr_info("No forward
  ");
b67bfe0d4   Sasha Levin   hlist: drop the n...
1377
  	hlist_for_each_entry(rulla, &priv->lec_no_forward, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1378
  		offset = 0;
79ac52240   Andy Shevchenko   net: atm: use %*p...
1379
1380
1381
  		offset += sprintf(buf + offset, "Mac: %pM ", rulla->mac_addr);
  		offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN,
  				  rulla->atm_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
  		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));
c48192a70   Joe Perches   net/atm/lec.c: ch...
1394
1395
  		pr_info("%s
  ", buf);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1396
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1397
1398
  
  	if (!hlist_empty(&priv->lec_arp_empty_ones))
c48192a70   Joe Perches   net/atm/lec.c: ch...
1399
1400
  		pr_info("Empty ones
  ");
b67bfe0d4   Sasha Levin   hlist: drop the n...
1401
  	hlist_for_each_entry(rulla, &priv->lec_arp_empty_ones, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1402
  		offset = 0;
79ac52240   Andy Shevchenko   net: atm: use %*p...
1403
1404
1405
  		offset += sprintf(buf + offset, "Mac: %pM ", rulla->mac_addr);
  		offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN,
  				  rulla->atm_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
  		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));
c48192a70   Joe Perches   net/atm/lec.c: ch...
1418
  		pr_info("%s", buf);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1419
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1420
  	if (!hlist_empty(&priv->mcast_fwds))
c48192a70   Joe Perches   net/atm/lec.c: ch...
1421
1422
  		pr_info("Multicast Forward VCCs
  ");
b67bfe0d4   Sasha Levin   hlist: drop the n...
1423
  	hlist_for_each_entry(rulla, &priv->mcast_fwds, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1424
  		offset = 0;
79ac52240   Andy Shevchenko   net: atm: use %*p...
1425
1426
1427
  		offset += sprintf(buf + offset, "Mac: %pM ", rulla->mac_addr);
  		offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN,
  				  rulla->atm_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
  		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));
c48192a70   Joe Perches   net/atm/lec.c: ch...
1440
1441
  		pr_info("%s
  ", buf);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1442
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1443

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444
  }
d0732f649   Chas Williams   [ATM]: [lec] conv...
1445
1446
1447
  #else
  #define dump_arp_table(priv) do { } while (0)
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1448
1449
1450
1451
  
  /*
   * Destruction of arp-cache
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1452
  static void lec_arp_destroy(struct lec_priv *priv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453
1454
  {
  	unsigned long flags;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1455
  	struct hlist_node *next;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1456
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1457
  	int i;
afe2c511f   Tejun Heo   workqueue: conver...
1458
  	cancel_delayed_work_sync(&priv->lec_arp_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1459

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1460
1461
1462
  	/*
  	 * Remove all entries
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463
1464
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1465
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1466
  		hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1467
  					  &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1468
  			lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1469
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1470
  		}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1471
  		INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1472
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1473

b67bfe0d4   Sasha Levin   hlist: drop the n...
1474
  	hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1475
  				  &priv->lec_arp_empty_ones, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1476
1477
  		del_timer_sync(&entry->timer);
  		lec_arp_clear_vccs(entry);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1478
  		hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1479
  		lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1480
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1481
  	INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
b67bfe0d4   Sasha Levin   hlist: drop the n...
1482
  	hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1483
  				  &priv->lec_no_forward, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1484
1485
  		del_timer_sync(&entry->timer);
  		lec_arp_clear_vccs(entry);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1486
  		hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1487
  		lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1488
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1489
  	INIT_HLIST_HEAD(&priv->lec_no_forward);
b67bfe0d4   Sasha Levin   hlist: drop the n...
1490
  	hlist_for_each_entry_safe(entry, next, &priv->mcast_fwds, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1491
1492
  		/* No timer, LANEv2 7.1.20 and 2.3.5.3 */
  		lec_arp_clear_vccs(entry);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1493
  		hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1494
  		lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1495
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1496
  	INIT_HLIST_HEAD(&priv->mcast_fwds);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1497
  	priv->mcast_vcc = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1498
1499
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1500
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
1502
   * Find entry by mac_address
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1503
  static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
61c33e012   Mitchell Blank Jr   atm: use const wh...
1504
  					  const unsigned char *mac_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1505
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1506
1507
  	struct hlist_head *head;
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1508

99824461e   Joe Perches   net/atm: Convert ...
1509
1510
  	pr_debug("%pM
  ", mac_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1511

d0732f649   Chas Williams   [ATM]: [lec] conv...
1512
  	head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])];
b67bfe0d4   Sasha Levin   hlist: drop the n...
1513
  	hlist_for_each_entry(entry, head, next) {
150238ebb   Joe Perches   atm: Convert comp...
1514
  		if (ether_addr_equal(mac_addr, entry->mac_addr))
d0732f649   Chas Williams   [ATM]: [lec] conv...
1515
  			return entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1516
1517
  	}
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1519
  static struct lec_arp_table *make_entry(struct lec_priv *priv,
61c33e012   Mitchell Blank Jr   atm: use const wh...
1520
  					const unsigned char *mac_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1521
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1522
1523
1524
  	struct lec_arp_table *to_return;
  
  	to_return = kzalloc(sizeof(struct lec_arp_table), GFP_ATOMIC);
bf97bac9d   Liao Pingfang   net: atm: Remove ...
1525
  	if (!to_return)
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1526
  		return NULL;
116e853f7   Joe Perches   atm: Use ether_ad...
1527
  	ether_addr_copy(to_return->mac_addr, mac_addr);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1528
  	INIT_HLIST_NODE(&to_return->next);
ba4217935   Kees Cook   net: atm: Convert...
1529
  	timer_setup(&to_return->timer, lec_arp_expire_arp, 0);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1530
1531
1532
  	to_return->last_used = jiffies;
  	to_return->priv = priv;
  	skb_queue_head_init(&to_return->tx_wait);
788936641   Reshetova, Elena   net, atm: convert...
1533
  	refcount_set(&to_return->usage, 1);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1534
  	return to_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1536
  /* Arp sent timer expired */
ba4217935   Kees Cook   net: atm: Convert...
1537
  static void lec_arp_expire_arp(struct timer_list *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1538
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1539
  	struct lec_arp_table *entry;
ba4217935   Kees Cook   net: atm: Convert...
1540
  	entry = from_timer(entry, t, timer);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1541

99824461e   Joe Perches   net/atm: Convert ...
1542
1543
  	pr_debug("
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
  	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));
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1556
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1557
  /* Unknown/unused vcc expire, remove associated entry */
ba4217935   Kees Cook   net: atm: Convert...
1558
  static void lec_arp_expire_vcc(struct timer_list *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
1560
  {
  	unsigned long flags;
ba4217935   Kees Cook   net: atm: Convert...
1561
  	struct lec_arp_table *to_remove = from_timer(to_remove, t, timer);
e3192690a   Joe Perches   net: Remove casts...
1562
  	struct lec_priv *priv = to_remove->priv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1564
  	del_timer(&to_remove->timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565

99824461e   Joe Perches   net/atm: Convert ...
1566
1567
1568
1569
1570
  	pr_debug("%p %p: vpi:%d vci:%d
  ",
  		 to_remove, priv,
  		 to_remove->vcc ? to_remove->recv_vcc->vpi : 0,
  		 to_remove->vcc ? to_remove->recv_vcc->vci : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
1572
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1573
  	hlist_del(&to_remove->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1574
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1575
  	lec_arp_clear_vccs(to_remove);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1576
  	lec_arp_put(to_remove);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1577
  }
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
  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
  ",
  		 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
  ");
  		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;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
  /*
   * 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.
   */
c4028958b   David Howells   WorkStruct: make ...
1640
  static void lec_arp_check_expire(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1641
1642
  {
  	unsigned long flags;
c4028958b   David Howells   WorkStruct: make ...
1643
1644
  	struct lec_priv *priv =
  		container_of(work, struct lec_priv, lec_arp_work.work);
b67bfe0d4   Sasha Levin   hlist: drop the n...
1645
  	struct hlist_node *next;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1646
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1647
  	unsigned long now;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1648
  	int i;
99824461e   Joe Perches   net/atm: Convert ...
1649
1650
  	pr_debug("%p
  ", priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651
  	now = jiffies;
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
1652
  restart:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1653
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1654
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1655
  		hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1656
  					  &priv->lec_arp_tables[i], next) {
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
  			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;
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1667
  				lec_arp_put(entry);
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
1668
1669
  
  				goto restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1670
1671
1672
1673
  			}
  		}
  	}
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
987e46bdf   Chas Williams   [ATM]: [lec] use ...
1674
  	schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1675
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1676

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
1678
  /*
   * Try to find vcc where mac_address is attached.
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1679
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1680
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1681
  static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1682
1683
  				       const unsigned char *mac_to_find,
  				       int is_rdesc,
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1684
  				       struct lec_arp_table **ret_entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1685
1686
  {
  	unsigned long flags;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1687
  	struct lec_arp_table *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688
  	struct atm_vcc *found;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1689
1690
1691
1692
  	if (mac_to_find[0] & 0x01) {
  		switch (priv->lane_version) {
  		case 1:
  			return priv->mcast_vcc;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1693
  		case 2:	/* LANE2 wants arp for multicast addresses */
150238ebb   Joe Perches   atm: Convert comp...
1694
  			if (ether_addr_equal(mac_to_find, bus_mac))
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1695
1696
1697
1698
1699
1700
  				return priv->mcast_vcc;
  			break;
  		default:
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1701
1702
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1703
1704
1705
1706
1707
1708
  	entry = lec_arp_find(priv, mac_to_find);
  
  	if (entry) {
  		if (entry->status == ESI_FORWARD_DIRECT) {
  			/* Connection Ok */
  			entry->last_used = jiffies;
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
1709
  			lec_arp_hold(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1710
1711
  			*ret_entry = entry;
  			found = entry->vcc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1712
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1713
1714
1715
  		}
  		/*
  		 * If the LE_ARP cache entry is still pending, reset count to 0
75b895c15   Scott Talbert   [ATM]: [lec] rese...
1716
1717
  		 * so another LE_ARP request can be made for this frame.
  		 */
c48192a70   Joe Perches   net/atm/lec.c: ch...
1718
  		if (entry->status == ESI_ARP_PENDING)
75b895c15   Scott Talbert   [ATM]: [lec] rese...
1719
  			entry->no_tries = 0;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
  		/*
  		 * 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++;
99824461e   Joe Perches   net/atm: Convert ...
1730
1731
  			pr_debug("Flooding..
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1732
  			found = priv->mcast_vcc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1733
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1734
1735
1736
  		}
  		/*
  		 * We got here because entry->status == ESI_FLUSH_PENDING
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1737
1738
1739
  		 * or BUS flood limit was reached for an entry which is
  		 * in ESI_ARP_PENDING or ESI_VC_PENDING state.
  		 */
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
1740
  		lec_arp_hold(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1741
  		*ret_entry = entry;
99824461e   Joe Perches   net/atm: Convert ...
1742
1743
1744
  		pr_debug("entry->status %d entry->vcc %p
  ", entry->status,
  			 entry->vcc);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1745
1746
1747
1748
  		found = NULL;
  	} else {
  		/* No matching entry was found */
  		entry = make_entry(priv, mac_to_find);
99824461e   Joe Perches   net/atm: Convert ...
1749
1750
  		pr_debug("Making entry
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1751
1752
  		if (!entry) {
  			found = priv->mcast_vcc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1753
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
  		}
  		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);
841b86f32   Kees Cook   treewide: Remove ...
1768
  		entry->timer.function = lec_arp_expire_arp;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1769
1770
1771
  		add_timer(&entry->timer);
  		found = priv->mcast_vcc;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1772
1773
1774
1775
1776
1777
1778
  
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  	return found;
  }
  
  static int
61c33e012   Mitchell Blank Jr   atm: use const wh...
1779
  lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr,
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1780
  		unsigned long permanent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1781
1782
  {
  	unsigned long flags;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1783
  	struct hlist_node *next;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1784
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1785
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1786

99824461e   Joe Perches   net/atm: Convert ...
1787
1788
  	pr_debug("
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1789
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1790
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1791
  		hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1792
1793
1794
1795
  					  &priv->lec_arp_tables[i], next) {
  			if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) &&
  			    (permanent ||
  			     !(entry->flags & LEC_PERMANENT_FLAG))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1796
  				lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1797
  				lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1798
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1799
  			spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1800
1801
1802
  			return 0;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1803
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1804
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1805
1806
1807
  }
  
  /*
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1808
   * Notifies:  Response to arp_request (atm_addr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1809
1810
   */
  static void
61c33e012   Mitchell Blank Jr   atm: use const wh...
1811
1812
  lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,
  	       const unsigned char *atm_addr, unsigned long remoteflag,
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1813
  	       unsigned int targetless_le_arp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1814
1815
  {
  	unsigned long flags;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1816
  	struct hlist_node *next;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1817
1818
  	struct lec_arp_table *entry, *tmp;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1819

99824461e   Joe Perches   net/atm: Convert ...
1820
1821
1822
  	pr_debug("%smac:%pM
  ",
  		 (targetless_le_arp) ? "targetless " : "", mac_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1823
1824
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1825
1826
1827
1828
1829
1830
  	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
  				 */
d0732f649   Chas Williams   [ATM]: [lec] conv...
1831
  	if (!hlist_empty(&priv->lec_arp_empty_ones)) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1832
  		hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1833
  					  &priv->lec_arp_empty_ones, next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1834
1835
  			if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) {
  				hlist_del(&entry->next);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1836
  				del_timer(&entry->timer);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1837
1838
1839
1840
1841
1842
1843
1844
1845
  				tmp = lec_arp_find(priv, mac_addr);
  				if (tmp) {
  					del_timer(&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;
  					del_timer(&entry->timer);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1846
  					lec_arp_put(entry);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1847
1848
1849
  					entry = tmp;
  				} else {
  					entry->status = ESI_FORWARD_DIRECT;
116e853f7   Joe Perches   atm: Use ether_ad...
1850
1851
  					ether_addr_copy(entry->mac_addr,
  							mac_addr);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1852
1853
1854
1855
1856
1857
1858
  					entry->last_used = jiffies;
  					lec_arp_add(priv, entry);
  				}
  				if (remoteflag)
  					entry->flags |= LEC_REMOTE_FLAG;
  				else
  					entry->flags &= ~LEC_REMOTE_FLAG;
522400623   Stephen Hemminger   [ATM]: Replace DP...
1859
1860
  				pr_debug("After update
  ");
d0732f649   Chas Williams   [ATM]: [lec] conv...
1861
1862
  				dump_arp_table(priv);
  				goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1863
  			}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1864
1865
  		}
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1866

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
  	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);
  	del_timer(&entry->timer);
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1879
  		hlist_for_each_entry(tmp,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1880
  				     &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
  			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;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1903
  		send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1904
  	}
522400623   Stephen Hemminger   [ATM]: Replace DP...
1905
1906
  	pr_debug("After update2
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1907
  	dump_arp_table(priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1908
1909
1910
1911
1912
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
  
  /*
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1913
   * Notifies: Vcc setup ready
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1914
1915
   */
  static void
61c33e012   Mitchell Blank Jr   atm: use const wh...
1916
  lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1917
1918
  	      struct atm_vcc *vcc,
  	      void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1919
1920
  {
  	unsigned long flags;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1921
1922
  	struct lec_arp_table *entry;
  	int i, found_entry = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1923
1924
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
c48192a70   Joe Perches   net/atm/lec.c: ch...
1925
  	/* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1926
  	if (ioc_data->receive == 2) {
522400623   Stephen Hemminger   [ATM]: Replace DP...
1927
1928
  		pr_debug("LEC_ARP: Attaching mcast forward
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1929
  #if 0
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1930
1931
  		entry = lec_arp_find(priv, bus_mac);
  		if (!entry) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
1932
1933
  			pr_info("LEC_ARP: Multicast entry not found!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1934
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1935
1936
1937
1938
  		}
  		memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
  		entry->recv_vcc = vcc;
  		entry->old_recv_push = old_push;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1939
  #endif
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1940
1941
  		entry = make_entry(priv, bus_mac);
  		if (entry == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1942
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1943
1944
1945
1946
  		del_timer(&entry->timer);
  		memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
  		entry->recv_vcc = vcc;
  		entry->old_recv_push = old_push;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1947
  		hlist_add_head(&entry->next, &priv->mcast_fwds);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1948
1949
1950
1951
1952
1953
  		goto out;
  	} else if (ioc_data->receive == 1) {
  		/*
  		 * Vcc which we don't want to make default vcc,
  		 * attach it anyway.
  		 */
79ac52240   Andy Shevchenko   net: atm: use %*p...
1954
1955
1956
  		pr_debug("LEC_ARP:Attaching data direct, not default: %*phN
  ",
  			 ATM_ESA_LEN, ioc_data->atm_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1957
1958
  		entry = make_entry(priv, bus_mac);
  		if (entry == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1959
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1960
  		memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
19ffa562e   Joe Perches   atm: Use eth_<foo...
1961
  		eth_zero_addr(entry->mac_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1962
1963
1964
1965
  		entry->recv_vcc = vcc;
  		entry->old_recv_push = old_push;
  		entry->status = ESI_UNKNOWN;
  		entry->timer.expires = jiffies + priv->vcc_timeout_period;
841b86f32   Kees Cook   treewide: Remove ...
1966
  		entry->timer.function = lec_arp_expire_vcc;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1967
  		hlist_add_head(&entry->next, &priv->lec_no_forward);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1968
  		add_timer(&entry->timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1969
1970
  		dump_arp_table(priv);
  		goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1971
  	}
79ac52240   Andy Shevchenko   net: atm: use %*p...
1972
1973
1974
  	pr_debug("LEC_ARP:Attaching data direct, default: %*phN
  ",
  		 ATM_ESA_LEN, ioc_data->atm_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1975
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1976
  		hlist_for_each_entry(entry,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1977
  				     &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1978
1979
1980
  			if (memcmp
  			    (ioc_data->atm_addr, entry->atm_addr,
  			     ATM_ESA_LEN) == 0) {
522400623   Stephen Hemminger   [ATM]: Replace DP...
1981
1982
1983
1984
  				pr_debug("LEC_ARP: Attaching data direct
  ");
  				pr_debug("Currently -> Vcc: %d, Rvcc:%d
  ",
99824461e   Joe Perches   net/atm: Convert ...
1985
1986
1987
  					 entry->vcc ? entry->vcc->vci : 0,
  					 entry->recv_vcc ? entry->recv_vcc->
  					 vci : 0);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
  				found_entry = 1;
  				del_timer(&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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2001
  #if 0
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2002
2003
2004
2005
  						send_to_lecd(priv, l_flush_xmt,
  							     NULL,
  							     entry->atm_addr,
  							     NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2006
  #endif
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
  					}
  				} 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) {
522400623   Stephen Hemminger   [ATM]: Replace DP...
2026
2027
  		pr_debug("After vcc was added
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2028
  		dump_arp_table(priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2029
  		goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2030
2031
2032
2033
2034
2035
2036
  	}
  	/*
  	 * Not found, snatch address from first data packet that arrives
  	 * from this vcc
  	 */
  	entry = make_entry(priv, bus_mac);
  	if (!entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2037
  		goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2038
2039
2040
  	entry->vcc = vcc;
  	entry->old_push = old_push;
  	memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
19ffa562e   Joe Perches   atm: Use eth_<foo...
2041
  	eth_zero_addr(entry->mac_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2042
  	entry->status = ESI_UNKNOWN;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2043
  	hlist_add_head(&entry->next, &priv->lec_arp_empty_ones);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2044
  	entry->timer.expires = jiffies + priv->vcc_timeout_period;
841b86f32   Kees Cook   treewide: Remove ...
2045
  	entry->timer.function = lec_arp_expire_vcc;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2046
  	add_timer(&entry->timer);
522400623   Stephen Hemminger   [ATM]: Replace DP...
2047
2048
  	pr_debug("After vcc was added
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049
2050
2051
2052
  	dump_arp_table(priv);
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2053
  static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2054
2055
  {
  	unsigned long flags;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2056
2057
  	struct lec_arp_table *entry;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2058

99824461e   Joe Perches   net/atm: Convert ...
2059
2060
  	pr_debug("%lx
  ", tran_id);
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2061
  restart:
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2062
2063
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
2064
  		hlist_for_each_entry(entry,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2065
2066
2067
  				     &priv->lec_arp_tables[i], next) {
  			if (entry->flush_tran_id == tran_id &&
  			    entry->status == ESI_FLUSH_PENDING) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2068
  				struct sk_buff *skb;
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2069
  				struct atm_vcc *vcc = entry->vcc;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2070

6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2071
  				lec_arp_hold(entry);
c48192a70   Joe Perches   net/atm/lec.c: ch...
2072
2073
  				spin_unlock_irqrestore(&priv->lec_arp_lock,
  						       flags);
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
2074
  				while ((skb = skb_dequeue(&entry->tx_wait)))
162619e59   Stephen Hemminger   lec: convert to i...
2075
  					lec_send(vcc, skb);
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2076
  				entry->last_used = jiffies;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2077
  				entry->status = ESI_FORWARD_DIRECT;
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2078
  				lec_arp_put(entry);
522400623   Stephen Hemminger   [ATM]: Replace DP...
2079
2080
  				pr_debug("LEC_ARP: Flushed
  ");
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2081
  				goto restart;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2082
2083
2084
  			}
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2085
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2086
  	dump_arp_table(priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2087
2088
2089
2090
  }
  
  static void
  lec_set_flush_tran_id(struct lec_priv *priv,
61c33e012   Mitchell Blank Jr   atm: use const wh...
2091
  		      const unsigned char *atm_addr, unsigned long tran_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2092
2093
  {
  	unsigned long flags;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2094
2095
  	struct lec_arp_table *entry;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2096
2097
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2098
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
b67bfe0d4   Sasha Levin   hlist: drop the n...
2099
  		hlist_for_each_entry(entry,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2100
  				     &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2101
2102
  			if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
  				entry->flush_tran_id = tran_id;
522400623   Stephen Hemminger   [ATM]: Replace DP...
2103
2104
  				pr_debug("Set flush transaction id to %lx for %p
  ",
99824461e   Joe Perches   net/atm: Convert ...
2105
  					 tran_id, entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2106
  			}
d0732f649   Chas Williams   [ATM]: [lec] conv...
2107
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2108
2109
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2110
  static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
2112
  {
  	unsigned long flags;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2113
2114
2115
2116
  	unsigned char mac_addr[] = {
  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  	};
  	struct lec_arp_table *to_add;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2117
2118
  	struct lec_vcc_priv *vpriv;
  	int err = 0;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2119

c48192a70   Joe Perches   net/atm/lec.c: ch...
2120
2121
  	vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
  	if (!vpriv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2122
2123
2124
2125
  		return -ENOMEM;
  	vpriv->xoff = 0;
  	vpriv->old_pop = vcc->pop;
  	vcc->user_back = vpriv;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2126
  	vcc->pop = lec_pop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2127
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2128
2129
  	to_add = make_entry(priv, mac_addr);
  	if (!to_add) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2130
2131
  		vcc->pop = vpriv->old_pop;
  		kfree(vpriv);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2132
  		err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2133
  		goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2134
2135
2136
2137
2138
2139
2140
2141
2142
  	}
  	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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
2144
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2145
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2146
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2147
  static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2148
2149
  {
  	unsigned long flags;
b67bfe0d4   Sasha Levin   hlist: drop the n...
2150
  	struct hlist_node *next;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2151
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2152
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2153

522400623   Stephen Hemminger   [ATM]: Replace DP...
2154
2155
  	pr_debug("LEC_ARP: lec_vcc_close vpi:%d vci:%d
  ", vcc->vpi, vcc->vci);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2156
  	dump_arp_table(priv);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2157

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2158
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2159

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2160
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
2161
  		hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2162
  					  &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2163
2164
  			if (vcc == entry->vcc) {
  				lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2165
  				lec_arp_put(entry);
c48192a70   Joe Perches   net/atm/lec.c: ch...
2166
  				if (priv->mcast_vcc == vcc)
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2167
  					priv->mcast_vcc = NULL;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2168
2169
2170
  			}
  		}
  	}
b67bfe0d4   Sasha Levin   hlist: drop the n...
2171
  	hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2172
  				  &priv->lec_arp_empty_ones, next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
2173
  		if (entry->vcc == vcc) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2174
2175
  			lec_arp_clear_vccs(entry);
  			del_timer(&entry->timer);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2176
  			hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2177
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2178
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2179
  	}
b67bfe0d4   Sasha Levin   hlist: drop the n...
2180
  	hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2181
  				  &priv->lec_no_forward, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2182
2183
2184
  		if (entry->recv_vcc == vcc) {
  			lec_arp_clear_vccs(entry);
  			del_timer(&entry->timer);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2185
  			hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2186
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2187
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2188
  	}
b67bfe0d4   Sasha Levin   hlist: drop the n...
2189
  	hlist_for_each_entry_safe(entry, next, &priv->mcast_fwds, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2190
2191
2192
  		if (entry->recv_vcc == vcc) {
  			lec_arp_clear_vccs(entry);
  			/* No timer, LANEv2 7.1.20 and 2.3.5.3 */
d0732f649   Chas Williams   [ATM]: [lec] conv...
2193
  			hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2194
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2195
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2196
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2197
2198
2199
2200
2201
2202
2203
  
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  	dump_arp_table(priv);
  }
  
  static void
  lec_arp_check_empties(struct lec_priv *priv,
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2204
  		      struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2205
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2206
  	unsigned long flags;
b67bfe0d4   Sasha Levin   hlist: drop the n...
2207
  	struct hlist_node *next;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2208
  	struct lec_arp_table *entry, *tmp;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2209
  	struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
60eea6cf2   Paul Gortmaker   atm: remove the c...
2210
  	unsigned char *src = hdr->h_source;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2211
2212
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
b67bfe0d4   Sasha Levin   hlist: drop the n...
2213
  	hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2214
  				  &priv->lec_arp_empty_ones, next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
2215
2216
  		if (vcc == entry->vcc) {
  			del_timer(&entry->timer);
116e853f7   Joe Perches   atm: Use ether_ad...
2217
  			ether_addr_copy(entry->mac_addr, src);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2218
2219
2220
  			entry->status = ESI_FORWARD_DIRECT;
  			entry->last_used = jiffies;
  			/* We might have got an entry */
c48192a70   Joe Perches   net/atm/lec.c: ch...
2221
2222
  			tmp = lec_arp_find(priv, src);
  			if (tmp) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
2223
  				lec_arp_remove(priv, tmp);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2224
  				lec_arp_put(tmp);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2225
2226
2227
2228
  			}
  			hlist_del(&entry->next);
  			lec_arp_add(priv, entry);
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2229
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2230
  	}
522400623   Stephen Hemminger   [ATM]: Replace DP...
2231
2232
  	pr_debug("LEC_ARP: Arp_check_empties: entry not found!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2233
2234
2235
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2236

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2237
  MODULE_LICENSE("GPL");