Blame view

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

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

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

524ad0a79   Wang Chen   netdevice: safe c...
143
  		priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
144
  		atm_force_charge(priv->lecd, skb2->truesize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  		sk = sk_atm(priv->lecd);
d44f77466   Chas Williams   [ATM]: [lec] inde...
146
  		skb_queue_tail(&sk->sk_receive_queue, skb2);
676d23690   David S. Miller   net: Fix use afte...
147
  		sk->sk_data_ready(sk);
d44f77466   Chas Williams   [ATM]: [lec] inde...
148
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  }
9a81c34ac   Javier Martinez Canillas   lec: use IS_ENABL...
150
  #endif /* IS_ENABLED(CONFIG_BRIDGE) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
   * 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...
160
  static int lec_open(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  	netif_start_queue(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
163
164
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  }
162619e59   Stephen Hemminger   lec: convert to i...
166
167
  static void
  lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
162619e59   Stephen Hemminger   lec: convert to i...
169
  	struct net_device *dev = skb->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
  	ATM_SKB(skb)->vcc = vcc;
  	ATM_SKB(skb)->atm_options = vcc->atm_options;
14afee4b6   Reshetova, Elena   net: convert sock...
172
  	refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  	if (vcc->send(vcc, skb) < 0) {
162619e59   Stephen Hemminger   lec: convert to i...
174
  		dev->stats.tx_dropped++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
  		return;
  	}
162619e59   Stephen Hemminger   lec: convert to i...
177
178
  	dev->stats.tx_packets++;
  	dev->stats.tx_bytes += skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
180
  static void lec_tx_timeout(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  {
99824461e   Joe Perches   net/atm: Convert ...
182
183
  	pr_info("%s
  ", dev->name);
860e9538a   Florian Westphal   treewide: replace...
184
  	netif_trans_update(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
  	netif_wake_queue(dev);
  }
3c805a22a   Stephen Hemminger   convert ATM drive...
187
188
  static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
  				  struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
190
  	struct sk_buff *skb2;
524ad0a79   Wang Chen   netdevice: safe c...
191
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
192
193
  	struct lecdatahdr_8023 *lec_h;
  	struct atm_vcc *vcc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  	struct lec_arp_table *entry;
d44f77466   Chas Williams   [ATM]: [lec] inde...
195
  	unsigned char *dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  	int min_frame_size;
d44f77466   Chas Williams   [ATM]: [lec] inde...
197
  	int is_rdesc;
d44f77466   Chas Williams   [ATM]: [lec] inde...
198

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  #if DUMP_PACKETS >= 2
c48192a70   Joe Perches   net/atm/lec.c: ch...
236
  #define MAX_DUMP_SKB 99
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  #elif DUMP_PACKETS >= 1
c48192a70   Joe Perches   net/atm/lec.c: ch...
238
239
240
241
242
243
244
245
  #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
246
  #endif /* DUMP_PACKETS >= 1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247

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

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

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

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

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

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

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

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

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

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

4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
563
564
565
566
  #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...
567
  {
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
568
569
  	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...
570
  }
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
571

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1245
  		vcc->pop = vpriv->old_pop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246
1247
1248
1249
  		if (vpriv->xoff)
  			netif_wake_queue(dev);
  		kfree(vpriv);
  		vcc->user_back = NULL;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1250
  		vcc->push = entry->old_push;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
  		vcc_release_async(vcc, -EPIPE);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1252
  		entry->vcc = NULL;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1253
1254
1255
  	}
  	if (entry->recv_vcc) {
  		entry->recv_vcc->push = entry->old_recv_push;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1256
  		vcc_release_async(entry->recv_vcc, -EPIPE);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1257
1258
  		entry->recv_vcc = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259
1260
1261
1262
1263
1264
  }
  
  /*
   * 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...
1265
  static inline void
d0732f649   Chas Williams   [ATM]: [lec] conv...
1266
  lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1268
  	struct hlist_head *tmp;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1269

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

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

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

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1336
  static void dump_arp_table(struct lec_priv *priv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1338
  	struct lec_arp_table *rulla;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1339
1340
  	char buf[256];
  	int i, j, offset;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1341

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
  }
d0732f649   Chas Williams   [ATM]: [lec] conv...
1457
1458
1459
  #else
  #define dump_arp_table(priv) do { } while (0)
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1460
1461
1462
1463
  
  /*
   * Destruction of arp-cache
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1464
  static void lec_arp_destroy(struct lec_priv *priv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465
1466
  {
  	unsigned long flags;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1467
  	struct hlist_node *next;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1468
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1469
  	int i;
afe2c511f   Tejun Heo   workqueue: conver...
1470
  	cancel_delayed_work_sync(&priv->lec_arp_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1472
1473
1474
  	/*
  	 * Remove all entries
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1475
1476
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1477
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1478
  		hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1479
  					  &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1480
  			lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1481
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1482
  		}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1483
  		INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1484
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1485

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

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

d0732f649   Chas Williams   [ATM]: [lec] conv...
1524
  	head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])];
b67bfe0d4   Sasha Levin   hlist: drop the n...
1525
  	hlist_for_each_entry(entry, head, next) {
150238ebb   Joe Perches   atm: Convert comp...
1526
  		if (ether_addr_equal(mac_addr, entry->mac_addr))
d0732f649   Chas Williams   [ATM]: [lec] conv...
1527
  			return entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1528
1529
  	}
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1530
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1531
  static struct lec_arp_table *make_entry(struct lec_priv *priv,
61c33e012   Mitchell Blank Jr   atm: use const wh...
1532
  					const unsigned char *mac_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1533
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1534
1535
1536
1537
  	struct lec_arp_table *to_return;
  
  	to_return = kzalloc(sizeof(struct lec_arp_table), GFP_ATOMIC);
  	if (!to_return) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
1538
1539
  		pr_info("LEC: Arp entry kmalloc failed
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1540
1541
  		return NULL;
  	}
116e853f7   Joe Perches   atm: Use ether_ad...
1542
  	ether_addr_copy(to_return->mac_addr, mac_addr);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1543
  	INIT_HLIST_NODE(&to_return->next);
ba4217935   Kees Cook   net: atm: Convert...
1544
  	timer_setup(&to_return->timer, lec_arp_expire_arp, 0);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1545
1546
1547
  	to_return->last_used = jiffies;
  	to_return->priv = priv;
  	skb_queue_head_init(&to_return->tx_wait);
788936641   Reshetova, Elena   net, atm: convert...
1548
  	refcount_set(&to_return->usage, 1);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1549
  	return to_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1550
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1551
  /* Arp sent timer expired */
ba4217935   Kees Cook   net: atm: Convert...
1552
  static void lec_arp_expire_arp(struct timer_list *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1554
  	struct lec_arp_table *entry;
ba4217935   Kees Cook   net: atm: Convert...
1555
  	entry = from_timer(entry, t, timer);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1556

99824461e   Joe Perches   net/atm: Convert ...
1557
1558
  	pr_debug("
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
  	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
1571
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1572
  /* Unknown/unused vcc expire, remove associated entry */
ba4217935   Kees Cook   net: atm: Convert...
1573
  static void lec_arp_expire_vcc(struct timer_list *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1574
1575
  {
  	unsigned long flags;
ba4217935   Kees Cook   net: atm: Convert...
1576
  	struct lec_arp_table *to_remove = from_timer(to_remove, t, timer);
e3192690a   Joe Perches   net: Remove casts...
1577
  	struct lec_priv *priv = to_remove->priv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1578

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

99824461e   Joe Perches   net/atm: Convert ...
1581
1582
1583
1584
1585
  	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
1586
1587
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1588
  	hlist_del(&to_remove->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1590
  	lec_arp_clear_vccs(to_remove);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1591
  	lec_arp_put(to_remove);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1592
  }
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
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
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
  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
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
  /*
   * 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 ...
1655
  static void lec_arp_check_expire(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1656
1657
  {
  	unsigned long flags;
c4028958b   David Howells   WorkStruct: make ...
1658
1659
  	struct lec_priv *priv =
  		container_of(work, struct lec_priv, lec_arp_work.work);
b67bfe0d4   Sasha Levin   hlist: drop the n...
1660
  	struct hlist_node *next;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1661
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1662
  	unsigned long now;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1663
  	int i;
99824461e   Joe Perches   net/atm: Convert ...
1664
1665
  	pr_debug("%p
  ", priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1666
  	now = jiffies;
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
1667
  restart:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1668
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1669
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1670
  		hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1671
  					  &priv->lec_arp_tables[i], next) {
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
  			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 ...
1682
  				lec_arp_put(entry);
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
1683
1684
  
  				goto restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1685
1686
1687
1688
  			}
  		}
  	}
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
987e46bdf   Chas Williams   [ATM]: [lec] use ...
1689
  	schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1690
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1691

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

99824461e   Joe Perches   net/atm: Convert ...
1802
1803
  	pr_debug("
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1804
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1805
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1806
  		hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1807
1808
1809
1810
  					  &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
1811
  				lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1812
  				lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1813
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1814
  			spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1815
1816
1817
  			return 0;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1818
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1819
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1820
1821
1822
  }
  
  /*
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1823
   * Notifies:  Response to arp_request (atm_addr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1824
1825
   */
  static void
61c33e012   Mitchell Blank Jr   atm: use const wh...
1826
1827
  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...
1828
  	       unsigned int targetless_le_arp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1829
1830
  {
  	unsigned long flags;
b67bfe0d4   Sasha Levin   hlist: drop the n...
1831
  	struct hlist_node *next;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1832
1833
  	struct lec_arp_table *entry, *tmp;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1834

99824461e   Joe Perches   net/atm: Convert ...
1835
1836
1837
  	pr_debug("%smac:%pM
  ",
  		 (targetless_le_arp) ? "targetless " : "", mac_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838
1839
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1840
1841
1842
1843
1844
1845
  	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...
1846
  	if (!hlist_empty(&priv->lec_arp_empty_ones)) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
1847
  		hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1848
  					  &priv->lec_arp_empty_ones, next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1849
1850
  			if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) {
  				hlist_del(&entry->next);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1851
  				del_timer(&entry->timer);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1852
1853
1854
1855
1856
1857
1858
1859
1860
  				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 ...
1861
  					lec_arp_put(entry);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1862
1863
1864
  					entry = tmp;
  				} else {
  					entry->status = ESI_FORWARD_DIRECT;
116e853f7   Joe Perches   atm: Use ether_ad...
1865
1866
  					ether_addr_copy(entry->mac_addr,
  							mac_addr);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1867
1868
1869
1870
1871
1872
1873
  					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...
1874
1875
  				pr_debug("After update
  ");
d0732f649   Chas Williams   [ATM]: [lec] conv...
1876
1877
  				dump_arp_table(priv);
  				goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1878
  			}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1879
1880
  		}
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1881

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

99824461e   Joe Perches   net/atm: Convert ...
2092
2093
  	pr_debug("%lx
  ", tran_id);
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2094
  restart:
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2095
2096
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
2097
  		hlist_for_each_entry(entry,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2098
2099
2100
  				     &priv->lec_arp_tables[i], next) {
  			if (entry->flush_tran_id == tran_id &&
  			    entry->status == ESI_FLUSH_PENDING) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2101
  				struct sk_buff *skb;
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2102
  				struct atm_vcc *vcc = entry->vcc;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2103

6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2104
  				lec_arp_hold(entry);
c48192a70   Joe Perches   net/atm/lec.c: ch...
2105
2106
  				spin_unlock_irqrestore(&priv->lec_arp_lock,
  						       flags);
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
2107
  				while ((skb = skb_dequeue(&entry->tx_wait)))
162619e59   Stephen Hemminger   lec: convert to i...
2108
  					lec_send(vcc, skb);
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2109
  				entry->last_used = jiffies;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2110
  				entry->status = ESI_FORWARD_DIRECT;
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2111
  				lec_arp_put(entry);
522400623   Stephen Hemminger   [ATM]: Replace DP...
2112
2113
  				pr_debug("LEC_ARP: Flushed
  ");
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2114
  				goto restart;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2115
2116
2117
  			}
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2118
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2119
  	dump_arp_table(priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2120
2121
2122
2123
  }
  
  static void
  lec_set_flush_tran_id(struct lec_priv *priv,
61c33e012   Mitchell Blank Jr   atm: use const wh...
2124
  		      const unsigned char *atm_addr, unsigned long tran_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2125
2126
  {
  	unsigned long flags;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2127
2128
  	struct lec_arp_table *entry;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2129
2130
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2131
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
b67bfe0d4   Sasha Levin   hlist: drop the n...
2132
  		hlist_for_each_entry(entry,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2133
  				     &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2134
2135
  			if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
  				entry->flush_tran_id = tran_id;
522400623   Stephen Hemminger   [ATM]: Replace DP...
2136
2137
  				pr_debug("Set flush transaction id to %lx for %p
  ",
99824461e   Joe Perches   net/atm: Convert ...
2138
  					 tran_id, entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2139
  			}
d0732f649   Chas Williams   [ATM]: [lec] conv...
2140
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2141
2142
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2143
  static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2144
2145
  {
  	unsigned long flags;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2146
2147
2148
2149
  	unsigned char mac_addr[] = {
  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  	};
  	struct lec_arp_table *to_add;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2150
2151
  	struct lec_vcc_priv *vpriv;
  	int err = 0;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2152

c48192a70   Joe Perches   net/atm/lec.c: ch...
2153
2154
  	vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
  	if (!vpriv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2155
2156
2157
2158
  		return -ENOMEM;
  	vpriv->xoff = 0;
  	vpriv->old_pop = vcc->pop;
  	vcc->user_back = vpriv;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2159
  	vcc->pop = lec_pop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2160
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2161
2162
  	to_add = make_entry(priv, mac_addr);
  	if (!to_add) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2163
2164
  		vcc->pop = vpriv->old_pop;
  		kfree(vpriv);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2165
  		err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
  		goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2167
2168
2169
2170
2171
2172
2173
2174
2175
  	}
  	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
2176
2177
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2178
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2179
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2180
  static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2181
2182
  {
  	unsigned long flags;
b67bfe0d4   Sasha Levin   hlist: drop the n...
2183
  	struct hlist_node *next;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2184
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2185
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2186

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

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

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2193
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
b67bfe0d4   Sasha Levin   hlist: drop the n...
2194
  		hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2195
  					  &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2196
2197
  			if (vcc == entry->vcc) {
  				lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2198
  				lec_arp_put(entry);
c48192a70   Joe Perches   net/atm/lec.c: ch...
2199
  				if (priv->mcast_vcc == vcc)
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2200
  					priv->mcast_vcc = NULL;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2201
2202
2203
  			}
  		}
  	}
b67bfe0d4   Sasha Levin   hlist: drop the n...
2204
  	hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2205
  				  &priv->lec_arp_empty_ones, next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
2206
  		if (entry->vcc == vcc) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2207
2208
  			lec_arp_clear_vccs(entry);
  			del_timer(&entry->timer);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2209
  			hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2210
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2211
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2212
  	}
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_no_forward, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2215
2216
2217
  		if (entry->recv_vcc == vcc) {
  			lec_arp_clear_vccs(entry);
  			del_timer(&entry->timer);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2218
  			hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2219
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2220
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2221
  	}
b67bfe0d4   Sasha Levin   hlist: drop the n...
2222
  	hlist_for_each_entry_safe(entry, next, &priv->mcast_fwds, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2223
2224
2225
  		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...
2226
  			hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2227
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2228
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2229
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2230
2231
2232
2233
2234
2235
2236
  
  	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...
2237
  		      struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2238
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2239
  	unsigned long flags;
b67bfe0d4   Sasha Levin   hlist: drop the n...
2240
  	struct hlist_node *next;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2241
  	struct lec_arp_table *entry, *tmp;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2242
  	struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
60eea6cf2   Paul Gortmaker   atm: remove the c...
2243
  	unsigned char *src = hdr->h_source;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2244
2245
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
b67bfe0d4   Sasha Levin   hlist: drop the n...
2246
  	hlist_for_each_entry_safe(entry, next,
c48192a70   Joe Perches   net/atm/lec.c: ch...
2247
  				  &priv->lec_arp_empty_ones, next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
2248
2249
  		if (vcc == entry->vcc) {
  			del_timer(&entry->timer);
116e853f7   Joe Perches   atm: Use ether_ad...
2250
  			ether_addr_copy(entry->mac_addr, src);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2251
2252
2253
  			entry->status = ESI_FORWARD_DIRECT;
  			entry->last_used = jiffies;
  			/* We might have got an entry */
c48192a70   Joe Perches   net/atm/lec.c: ch...
2254
2255
  			tmp = lec_arp_find(priv, src);
  			if (tmp) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
2256
  				lec_arp_remove(priv, tmp);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2257
  				lec_arp_put(tmp);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2258
2259
2260
2261
  			}
  			hlist_del(&entry->next);
  			lec_arp_add(priv, entry);
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2262
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2263
  	}
522400623   Stephen Hemminger   [ATM]: Replace DP...
2264
2265
  	pr_debug("LEC_ARP: Arp_check_empties: entry not found!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2266
2267
2268
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2269

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