Blame view

net/atm/lec.c 63.3 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
26
27
28
29
30
31
32
33
34
35
36
37
  #include <linux/seq_file.h>
  
  /* TokenRing if needed */
  #ifdef CONFIG_TR
  #include <linux/trdevice.h>
  #endif
  
  /* And atm device */
  #include <linux/atmdev.h>
  #include <linux/atmlec.h>
  
  /* Proxy LEC knows about bridging */
  #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  #include "../bridge/br_private.h"
d44f77466   Chas Williams   [ATM]: [lec] inde...
39
  static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
47
48
  #endif
  
  /* Modular too */
  #include <linux/module.h>
  #include <linux/init.h>
  
  #include "lec.h"
  #include "lec_arpc.h"
  #include "resources.h"
d44f77466   Chas Williams   [ATM]: [lec] inde...
49
50
51
52
53
  #define DUMP_PACKETS 0		/*
  				 * 0 = None,
  				 * 1 = 30 first bytes
  				 * 2 = Whole packet
  				 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

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

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

524ad0a79   Wang Chen   netdevice: safe c...
149
  		priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
150
  		atm_force_charge(priv->lecd, skb2->truesize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  		sk = sk_atm(priv->lecd);
d44f77466   Chas Williams   [ATM]: [lec] inde...
152
153
154
  		skb_queue_tail(&sk->sk_receive_queue, skb2);
  		sk->sk_data_ready(sk, skb2->len);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  }
  #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
  
  /*
   * Modelled after tr_type_trans
   * All multicast and ARE or STE frames go to BUS.
   * Non source routed frames go by destination address.
   * Last hop source routed frames go by destination address.
   * Not last hop source routed frames go by _next_ route descriptor.
   * Returns pointer to destination MAC address or fills in rdesc
   * and returns NULL.
   */
  #ifdef CONFIG_TR
  static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
170
  	struct trh_hdr *trh;
5c17d5f11   Eric Dumazet   [ATM]: Suppress s...
171
  	unsigned int riflen, num_rdsc;
d44f77466   Chas Williams   [ATM]: [lec] inde...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  
  	trh = (struct trh_hdr *)packet;
  	if (trh->daddr[0] & (uint8_t) 0x80)
  		return bus_mac;	/* multicast */
  
  	if (trh->saddr[0] & TR_RII) {
  		riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
  		if ((ntohs(trh->rcf) >> 13) != 0)
  			return bus_mac;	/* ARE or STE */
  	} else
  		return trh->daddr;	/* not source routed */
  
  	if (riflen < 6)
  		return trh->daddr;	/* last hop, source routed */
  
  	/* riflen is 6 or more, packet has more than one route descriptor */
  	num_rdsc = (riflen / 2) - 1;
  	memset(rdesc, 0, ETH_ALEN);
  	/* offset 4 comes from LAN destination field in LE control frames */
  	if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT))
30d492da7   Al Viro   [ATM]: Annotations.
192
  		memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(__be16));
d44f77466   Chas Williams   [ATM]: [lec] inde...
193
  	else {
30d492da7   Al Viro   [ATM]: Annotations.
194
  		memcpy(&rdesc[4], &trh->rseg[1], sizeof(__be16));
d44f77466   Chas Williams   [ATM]: [lec] inde...
195
196
197
198
  		rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
  	}
  
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
201
202
203
204
205
206
207
208
209
  }
  #endif /* CONFIG_TR */
  
  /*
   * 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...
210
  static int lec_open(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  	netif_start_queue(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
213
214
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  }
162619e59   Stephen Hemminger   lec: convert to i...
216
217
  static void
  lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  {
162619e59   Stephen Hemminger   lec: convert to i...
219
  	struct net_device *dev = skb->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
223
224
  	ATM_SKB(skb)->vcc = vcc;
  	ATM_SKB(skb)->atm_options = vcc->atm_options;
  
  	atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
  	if (vcc->send(vcc, skb) < 0) {
162619e59   Stephen Hemminger   lec: convert to i...
225
  		dev->stats.tx_dropped++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
  		return;
  	}
162619e59   Stephen Hemminger   lec: convert to i...
228
229
  	dev->stats.tx_packets++;
  	dev->stats.tx_bytes += skb->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
231
  static void lec_tx_timeout(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  {
99824461e   Joe Perches   net/atm: Convert ...
233
234
  	pr_info("%s
  ", dev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
  	dev->trans_start = jiffies;
  	netif_wake_queue(dev);
  }
3c805a22a   Stephen Hemminger   convert ATM drive...
238
239
  static netdev_tx_t lec_start_xmit(struct sk_buff *skb,
  				  struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
241
  	struct sk_buff *skb2;
524ad0a79   Wang Chen   netdevice: safe c...
242
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
243
244
  	struct lecdatahdr_8023 *lec_h;
  	struct atm_vcc *vcc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  	struct lec_arp_table *entry;
d44f77466   Chas Williams   [ATM]: [lec] inde...
246
  	unsigned char *dst;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
  	int min_frame_size;
  #ifdef CONFIG_TR
d44f77466   Chas Williams   [ATM]: [lec] inde...
249
  	unsigned char rdesc[ETH_ALEN];	/* Token Ring route descriptor */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
251
  	int is_rdesc;
d44f77466   Chas Williams   [ATM]: [lec] inde...
252

99824461e   Joe Perches   net/atm: Convert ...
253
254
  	pr_debug("called
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
255
  	if (!priv->lecd) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
256
257
  		pr_info("%s:No lecd attached
  ", dev->name);
162619e59   Stephen Hemminger   lec: convert to i...
258
  		dev->stats.tx_errors++;
d44f77466   Chas Williams   [ATM]: [lec] inde...
259
  		netif_stop_queue(dev);
81fbbf604   Patrick McHardy   net: fix network ...
260
261
  		kfree_skb(skb);
  		return NETDEV_TX_OK;
d44f77466   Chas Williams   [ATM]: [lec] inde...
262
  	}
522400623   Stephen Hemminger   [ATM]: Replace DP...
263
264
  	pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx
  ",
99824461e   Joe Perches   net/atm: Convert ...
265
266
  		 (long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb),
  		 (long)skb_end_pointer(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
d44f77466   Chas Williams   [ATM]: [lec] inde...
268
269
  	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
270
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
271
272
  	/* Make sure we have room for lec_id */
  	if (skb_headroom(skb) < 2) {
99824461e   Joe Perches   net/atm: Convert ...
273
274
  		pr_debug("reallocating skb
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
275
276
277
  		skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
  		kfree_skb(skb);
  		if (skb2 == NULL)
6ed106549   Patrick McHardy   net: use NETDEV_T...
278
  			return NETDEV_TX_OK;
d44f77466   Chas Williams   [ATM]: [lec] inde...
279
280
281
  		skb = skb2;
  	}
  	skb_push(skb, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282

d44f77466   Chas Williams   [ATM]: [lec] inde...
283
284
285
  	/* Put le header to place, works for TokenRing too */
  	lec_h = (struct lecdatahdr_8023 *)skb->data;
  	lec_h->le_header = htons(priv->lecid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
  
  #ifdef CONFIG_TR
d44f77466   Chas Williams   [ATM]: [lec] inde...
288
289
290
291
292
293
294
295
  	/*
  	 * Ugly. Use this to realign Token Ring packets for
  	 * e.g. PCA-200E driver.
  	 */
  	if (priv->is_trdev) {
  		skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
  		kfree_skb(skb);
  		if (skb2 == NULL)
6ed106549   Patrick McHardy   net: use NETDEV_T...
296
  			return NETDEV_TX_OK;
d44f77466   Chas Williams   [ATM]: [lec] inde...
297
298
  		skb = skb2;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
  #if DUMP_PACKETS >= 2
c48192a70   Joe Perches   net/atm/lec.c: ch...
301
  #define MAX_DUMP_SKB 99
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  #elif DUMP_PACKETS >= 1
c48192a70   Joe Perches   net/atm/lec.c: ch...
303
304
305
306
307
308
309
310
  #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
311
  #endif /* DUMP_PACKETS >= 1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312

d44f77466   Chas Williams   [ATM]: [lec] inde...
313
  	/* Minimum ethernet-frame size */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  #ifdef CONFIG_TR
d44f77466   Chas Williams   [ATM]: [lec] inde...
315
316
  	if (priv->is_trdev)
  		min_frame_size = LEC_MINIMUM_8025_SIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
  	else
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
319
320
321
322
323
324
325
326
  		min_frame_size = LEC_MINIMUM_8023_SIZE;
  	if (skb->len < min_frame_size) {
  		if ((skb->len + skb_tailroom(skb)) < min_frame_size) {
  			skb2 = skb_copy_expand(skb, 0,
  					       min_frame_size - skb->truesize,
  					       GFP_ATOMIC);
  			dev_kfree_skb(skb);
  			if (skb2 == NULL) {
162619e59   Stephen Hemminger   lec: convert to i...
327
  				dev->stats.tx_dropped++;
6ed106549   Patrick McHardy   net: use NETDEV_T...
328
  				return NETDEV_TX_OK;
d44f77466   Chas Williams   [ATM]: [lec] inde...
329
330
331
  			}
  			skb = skb2;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  		skb_put(skb, min_frame_size - skb->len);
d44f77466   Chas Williams   [ATM]: [lec] inde...
333
334
335
336
337
  	}
  
  	/* Send to right vcc */
  	is_rdesc = 0;
  	dst = lec_h->h_dest;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  #ifdef CONFIG_TR
d44f77466   Chas Williams   [ATM]: [lec] inde...
339
340
341
342
343
344
345
  	if (priv->is_trdev) {
  		dst = get_tr_dst(skb->data + 2, rdesc);
  		if (dst == NULL) {
  			dst = rdesc;
  			is_rdesc = 1;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
347
348
  	entry = NULL;
  	vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
99824461e   Joe Perches   net/atm: Convert ...
349
350
351
  	pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p
  ",
  		 dev->name, vcc, vcc ? vcc->flags : 0, entry);
d44f77466   Chas Williams   [ATM]: [lec] inde...
352
353
  	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 ...
354
355
356
  			pr_debug("%s:queuing packet, MAC address %pM
  ",
  				 dev->name, lec_h->h_dest);
d44f77466   Chas Williams   [ATM]: [lec] inde...
357
358
  			skb_queue_tail(&entry->tx_wait, skb);
  		} else {
99824461e   Joe Perches   net/atm: Convert ...
359
360
361
  			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...
362
  			dev->stats.tx_dropped++;
d44f77466   Chas Williams   [ATM]: [lec] inde...
363
364
  			dev_kfree_skb(skb);
  		}
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
365
  		goto out;
d44f77466   Chas Williams   [ATM]: [lec] inde...
366
367
  	}
  #if DUMP_PACKETS > 0
c48192a70   Joe Perches   net/atm/lec.c: ch...
368
369
370
  	printk(KERN_DEBUG "%s:sending to vpi:%d vci:%d
  ",
  	       dev->name, vcc->vpi, vcc->vci);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  #endif /* DUMP_PACKETS > 0 */
d44f77466   Chas Williams   [ATM]: [lec] inde...
372
373
  
  	while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
99824461e   Joe Perches   net/atm: Convert ...
374
375
  		pr_debug("emptying tx queue, MAC address %pM
  ", lec_h->h_dest);
162619e59   Stephen Hemminger   lec: convert to i...
376
  		lec_send(vcc, skb2);
d44f77466   Chas Williams   [ATM]: [lec] inde...
377
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378

162619e59   Stephen Hemminger   lec: convert to i...
379
  	lec_send(vcc, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
  
  	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 ...
396
397
398
  out:
  	if (entry)
  		lec_arp_put(entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
  	dev->trans_start = jiffies;
6ed106549   Patrick McHardy   net: use NETDEV_T...
400
  	return NETDEV_TX_OK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
403
  }
  
  /* The inverse routine to net_open(). */
d44f77466   Chas Williams   [ATM]: [lec] inde...
404
  static int lec_close(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
406
407
  	netif_stop_queue(dev);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
409
  static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
  {
  	unsigned long flags;
d44f77466   Chas Williams   [ATM]: [lec] inde...
412
  	struct net_device *dev = (struct net_device *)vcc->proto_data;
524ad0a79   Wang Chen   netdevice: safe c...
413
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
414
415
416
417
  	struct atmlec_msg *mesg;
  	struct lec_arp_table *entry;
  	int i;
  	char *tmp;		/* FIXME */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
  
  	atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
d44f77466   Chas Williams   [ATM]: [lec] inde...
420
421
422
  	mesg = (struct atmlec_msg *)skb->data;
  	tmp = skb->data;
  	tmp += sizeof(struct atmlec_msg);
522400623   Stephen Hemminger   [ATM]: Replace DP...
423
424
  	pr_debug("%s: msg from zeppelin:%d
  ", dev->name, mesg->type);
d44f77466   Chas Williams   [ATM]: [lec] inde...
425
426
  	switch (mesg->type) {
  	case l_set_mac_addr:
c48192a70   Joe Perches   net/atm/lec.c: ch...
427
  		for (i = 0; i < 6; i++)
d44f77466   Chas Williams   [ATM]: [lec] inde...
428
  			dev->dev_addr[i] = mesg->content.normal.mac_addr[i];
d44f77466   Chas Williams   [ATM]: [lec] inde...
429
430
  		break;
  	case l_del_mac_addr:
c48192a70   Joe Perches   net/atm/lec.c: ch...
431
  		for (i = 0; i < 6; i++)
d44f77466   Chas Williams   [ATM]: [lec] inde...
432
  			dev->dev_addr[i] = 0;
d44f77466   Chas Williams   [ATM]: [lec] inde...
433
434
435
436
437
438
439
440
441
442
443
444
  		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
445
  		spin_lock_irqsave(&priv->lec_arp_lock, flags);
d44f77466   Chas Williams   [ATM]: [lec] inde...
446
447
  		entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
  		lec_arp_remove(priv, entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  		spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
d44f77466   Chas Williams   [ATM]: [lec] inde...
449
450
451
452
453
454
455
456
  		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 ...
457
458
  		pr_debug("in l_arp_update
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
459
  		if (mesg->sizeoftlvs != 0) {	/* LANE2 3.1.5 */
99824461e   Joe Perches   net/atm: Convert ...
460
461
462
  			pr_debug("LANE2 3.1.5, got tlvs, size %d
  ",
  				 mesg->sizeoftlvs);
d44f77466   Chas Williams   [ATM]: [lec] inde...
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  			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...
481
482
  		priv->lane_version = mesg->content.config.lane_version;
  					/* LANE2 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
  		priv->lane2_ops = NULL;
  		if (priv->lane_version > 1)
  			priv->lane2_ops = &lane2_ops;
1f1900f93   Stephen Hemminger   atm: lec use dev_...
486
  		if (dev_set_mtu(dev, mesg->content.config.mtu))
c48192a70   Joe Perches   net/atm/lec.c: ch...
487
488
489
  			pr_info("%s: change_mtu to %d failed
  ",
  				dev->name, mesg->content.config.mtu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
  		priv->is_proxy = mesg->content.config.is_proxy;
d44f77466   Chas Williams   [ATM]: [lec] inde...
491
492
493
494
495
496
497
498
499
500
  		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:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
502
503
504
505
  	{
  		pr_debug("%s: bridge zeppelin asks about %pM
  ",
  			 dev->name, mesg->content.proxy.mac_addr);
d44f77466   Chas Williams   [ATM]: [lec] inde...
506

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

b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
  		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);
  			sk->sk_data_ready(sk, skb2->len);
d44f77466   Chas Williams   [ATM]: [lec] inde...
527
  		}
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
528
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
d44f77466   Chas Williams   [ATM]: [lec] inde...
530
531
  		break;
  	default:
c48192a70   Joe Perches   net/atm/lec.c: ch...
532
533
  		pr_info("%s: Unknown message type %d
  ", dev->name, mesg->type);
d44f77466   Chas Williams   [ATM]: [lec] inde...
534
535
536
537
538
  		dev_kfree_skb(skb);
  		return -EINVAL;
  	}
  	dev_kfree_skb(skb);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
540
  static void lec_atm_close(struct atm_vcc *vcc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
542
543
  	struct sk_buff *skb;
  	struct net_device *dev = (struct net_device *)vcc->proto_data;
524ad0a79   Wang Chen   netdevice: safe c...
544
  	struct lec_priv *priv = netdev_priv(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545

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

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

d44f77466   Chas Williams   [ATM]: [lec] inde...
552
  	if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
c48192a70   Joe Perches   net/atm/lec.c: ch...
553
554
  		pr_info("%s closing with messages pending
  ", dev->name);
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
555
  	while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) {
d44f77466   Chas Williams   [ATM]: [lec] inde...
556
  		atm_return(vcc, skb->truesize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  		dev_kfree_skb(skb);
d44f77466   Chas Williams   [ATM]: [lec] inde...
558
  	}
c48192a70   Joe Perches   net/atm/lec.c: ch...
559
560
  	pr_info("%s: Shut down!
  ", dev->name);
d44f77466   Chas Williams   [ATM]: [lec] inde...
561
  	module_put(THIS_MODULE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
  }
  
  static struct atmdev_ops lecdev_ops = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
565
566
  	.close = lec_atm_close,
  	.send = lec_atm_send
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
569
  };
  
  static struct atm_dev lecatm_dev = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
570
571
572
  	.ops = &lecdev_ops,
  	.type = "lec",
  	.number = 999,		/* dummy device number */
4ef8d0aea   Milind Arun Choudhary   [NET]: SPIN_LOCK_...
573
  	.lock = __SPIN_LOCK_UNLOCKED(lecatm_dev.lock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
577
578
579
  };
  
  /*
   * LANE2: new argument struct sk_buff *data contains
   * the LE_ARP based TLVs introduced in the LANE2 spec
   */
d44f77466   Chas Williams   [ATM]: [lec] inde...
580
581
  static int
  send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
61c33e012   Mitchell Blank Jr   atm: use const wh...
582
  	     const unsigned char *mac_addr, const unsigned char *atm_addr,
d44f77466   Chas Williams   [ATM]: [lec] inde...
583
  	     struct sk_buff *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
586
587
  {
  	struct sock *sk;
  	struct sk_buff *skb;
  	struct atmlec_msg *mesg;
c48192a70   Joe Perches   net/atm/lec.c: ch...
588
  	if (!priv || !priv->lecd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
592
593
594
  	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...
595
  	memset(mesg, 0, sizeof(struct atmlec_msg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
  	mesg->type = type;
d44f77466   Chas Williams   [ATM]: [lec] inde...
597
598
  	if (data != NULL)
  		mesg->sizeoftlvs = data->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
  	if (mac_addr)
  		memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN);
d44f77466   Chas Williams   [ATM]: [lec] inde...
601
602
  	else
  		mesg->content.normal.targetless_le_arp = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
  	if (atm_addr)
  		memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
d44f77466   Chas Williams   [ATM]: [lec] inde...
605
  	atm_force_charge(priv->lecd, skb->truesize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
  	sk = sk_atm(priv->lecd);
  	skb_queue_tail(&sk->sk_receive_queue, skb);
d44f77466   Chas Williams   [ATM]: [lec] inde...
608
  	sk->sk_data_ready(sk, skb->len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609

d44f77466   Chas Williams   [ATM]: [lec] inde...
610
  	if (data != NULL) {
99824461e   Joe Perches   net/atm: Convert ...
611
612
  		pr_debug("about to send %d bytes of data
  ", data->len);
d44f77466   Chas Williams   [ATM]: [lec] inde...
613
614
615
616
  		atm_force_charge(priv->lecd, data->truesize);
  		skb_queue_tail(&sk->sk_receive_queue, data);
  		sk->sk_data_ready(sk, skb->len);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617

d44f77466   Chas Williams   [ATM]: [lec] inde...
618
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
620
621
622
623
  }
  
  /* shamelessly stolen from drivers/net/net_init.c */
  static int lec_change_mtu(struct net_device *dev, int new_mtu)
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
624
625
626
627
  	if ((new_mtu < 68) || (new_mtu > 18190))
  		return -EINVAL;
  	dev->mtu = new_mtu;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
631
  }
  
  static void lec_set_multicast_list(struct net_device *dev)
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
632
633
634
635
  	/*
  	 * by default, all multicast frames arrive over the bus.
  	 * eventually support selective multicast service
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  }
004b3225c   Stephen Hemminger   lec: convert to n...
637
638
639
640
641
642
  static const struct net_device_ops lec_netdev_ops = {
  	.ndo_open		= lec_open,
  	.ndo_stop		= lec_close,
  	.ndo_start_xmit		= lec_start_xmit,
  	.ndo_change_mtu		= lec_change_mtu,
  	.ndo_tx_timeout		= lec_tx_timeout,
afc4b13df   Jiri Pirko   net: remove use o...
643
  	.ndo_set_rx_mode	= lec_set_multicast_list,
004b3225c   Stephen Hemminger   lec: convert to n...
644
  };
61c33e012   Mitchell Blank Jr   atm: use const wh...
645
  static const unsigned char lec_ctrl_magic[] = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
646
647
648
649
650
  	0xff,
  	0x00,
  	0x01,
  	0x01
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651

4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
652
653
654
655
  #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...
656
  {
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
657
658
  	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...
659
  }
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
660

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

c48192a70   Joe Perches   net/atm/lec.c: ch...
667
  #if DUMP_PACKETS > 0
99824461e   Joe Perches   net/atm: Convert ...
668
669
670
  	printk(KERN_DEBUG "%s: vcc vpi:%d vci:%d
  ",
  	       dev->name, vcc->vpi, vcc->vci);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
672
  	if (!skb) {
522400623   Stephen Hemminger   [ATM]: Replace DP...
673
674
  		pr_debug("%s: null skb
  ", dev->name);
d44f77466   Chas Williams   [ATM]: [lec] inde...
675
676
677
  		lec_vcc_close(priv, vcc);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
  #if DUMP_PACKETS >= 2
99824461e   Joe Perches   net/atm: Convert ...
679
  #define MAX_SKB_DUMP 99
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  #elif DUMP_PACKETS >= 1
99824461e   Joe Perches   net/atm: Convert ...
681
682
683
684
685
686
687
688
  #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
689
  #endif /* DUMP_PACKETS > 0 */
99824461e   Joe Perches   net/atm: Convert ...
690
691
  	if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) {
  				/* Control frame, to daemon */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  		struct sock *sk = sk_atm(vcc);
522400623   Stephen Hemminger   [ATM]: Replace DP...
693
694
  		pr_debug("%s: To daemon
  ", dev->name);
d44f77466   Chas Williams   [ATM]: [lec] inde...
695
696
697
  		skb_queue_tail(&sk->sk_receive_queue, skb);
  		sk->sk_data_ready(sk, skb->len);
  	} else {		/* Data frame, queue to protocol handlers */
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
698
  		struct lec_arp_table *entry;
d44f77466   Chas Williams   [ATM]: [lec] inde...
699
700
701
  		unsigned char *src, *dst;
  
  		atm_return(vcc, skb->truesize);
30d492da7   Al Viro   [ATM]: Annotations.
702
  		if (*(__be16 *) skb->data == htons(priv->lecid) ||
d44f77466   Chas Williams   [ATM]: [lec] inde...
703
704
705
706
707
  		    !priv->lecd || !(dev->flags & IFF_UP)) {
  			/*
  			 * Probably looping back, or if lecd is missing,
  			 * lecd has gone down
  			 */
522400623   Stephen Hemminger   [ATM]: Replace DP...
708
709
  			pr_debug("Ignoring frame...
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
710
711
712
  			dev_kfree_skb(skb);
  			return;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
  #ifdef CONFIG_TR
d44f77466   Chas Williams   [ATM]: [lec] inde...
714
715
716
  		if (priv->is_trdev)
  			dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest;
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
718
  			dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
719

d44f77466   Chas Williams   [ATM]: [lec] inde...
720
721
  		/*
  		 * If this is a Data Direct VCC, and the VCC does not match
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
722
723
724
725
726
727
  		 * 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)) {
  #ifdef CONFIG_TR
  			if (priv->is_trdev)
d44f77466   Chas Williams   [ATM]: [lec] inde...
728
729
730
  				src =
  				    ((struct lecdatahdr_8025 *)skb->data)->
  				    h_source;
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
731
732
  			else
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
733
734
735
  				src =
  				    ((struct lecdatahdr_8023 *)skb->data)->
  				    h_source;
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
736
737
738
  			entry = lec_arp_find(priv, src);
  			if (entry && entry->vcc != vcc) {
  				lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
739
  				lec_arp_put(entry);
4a7097fcc   Scott Talbert   [ATM]: [lec] atte...
740
741
742
  			}
  		}
  		spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743

d44f77466   Chas Williams   [ATM]: [lec] inde...
744
745
  		if (!(dst[0] & 0x01) &&	/* Never filter Multi/Broadcast */
  		    !priv->is_proxy &&	/* Proxy wants all the packets */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  		    memcmp(dst, dev->dev_addr, dev->addr_len)) {
d44f77466   Chas Williams   [ATM]: [lec] inde...
747
748
749
  			dev_kfree_skb(skb);
  			return;
  		}
c48192a70   Joe Perches   net/atm/lec.c: ch...
750
  		if (!hlist_empty(&priv->lec_arp_empty_ones))
d44f77466   Chas Williams   [ATM]: [lec] inde...
751
  			lec_arp_check_empties(priv, vcc, skb);
d44f77466   Chas Williams   [ATM]: [lec] inde...
752
  		skb_pull(skb, 2);	/* skip lec_id */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  #ifdef CONFIG_TR
d44f77466   Chas Williams   [ATM]: [lec] inde...
754
755
756
  		if (priv->is_trdev)
  			skb->protocol = tr_type_trans(skb, dev);
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
758
  			skb->protocol = eth_type_trans(skb, dev);
162619e59   Stephen Hemminger   lec: convert to i...
759
760
  		dev->stats.rx_packets++;
  		dev->stats.rx_bytes += skb->len;
d44f77466   Chas Williams   [ATM]: [lec] inde...
761
762
763
  		memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
  		netif_rx(skb);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
765
  static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
768
769
770
  {
  	struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
  	struct net_device *dev = skb->dev;
  
  	if (vpriv == NULL) {
99824461e   Joe Perches   net/atm: Convert ...
771
772
  		pr_info("vpriv = NULL!?!?!?
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
776
777
778
779
780
781
782
783
  		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...
784
  static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
  {
  	struct lec_vcc_priv *vpriv;
d44f77466   Chas Williams   [ATM]: [lec] inde...
787
788
789
790
791
  	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 ...
792
793
794
  	if (bytes_left != 0)
  		pr_info("copy from user failed for %d bytes
  ", bytes_left);
d44f77466   Chas Williams   [ATM]: [lec] inde...
795
796
797
  	if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
  	    !dev_lec[ioc_data.dev_num])
  		return -EINVAL;
c48192a70   Joe Perches   net/atm/lec.c: ch...
798
799
  	vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
  	if (!vpriv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
802
803
804
  		return -ENOMEM;
  	vpriv->xoff = 0;
  	vpriv->old_pop = vcc->pop;
  	vcc->user_back = vpriv;
  	vcc->pop = lec_pop;
524ad0a79   Wang Chen   netdevice: safe c...
805
  	lec_vcc_added(netdev_priv(dev_lec[ioc_data.dev_num]),
d44f77466   Chas Williams   [ATM]: [lec] inde...
806
807
808
809
  		      &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
810
  }
d44f77466   Chas Williams   [ATM]: [lec] inde...
811
  static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
813
814
815
  	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...
816
  	return lec_mcast_make(netdev_priv(dev_lec[arg]), vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
819
  }
  
  /* Initialize device. */
d44f77466   Chas Williams   [ATM]: [lec] inde...
820
821
822
823
824
825
826
827
828
  static int lecd_attach(struct atm_vcc *vcc, int arg)
  {
  	int i;
  	struct lec_priv *priv;
  
  	if (arg < 0)
  		i = 0;
  	else
  		i = arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  #ifdef CONFIG_TR
d44f77466   Chas Williams   [ATM]: [lec] inde...
830
831
832
833
834
  	if (arg >= MAX_LEC_ITF)
  		return -EINVAL;
  #else				/* Reserve the top NUM_TR_DEVS for TR */
  	if (arg >= (MAX_LEC_ITF - NUM_TR_DEVS))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
836
837
  	if (!dev_lec[i]) {
  		int is_trdev, size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838

d44f77466   Chas Williams   [ATM]: [lec] inde...
839
840
841
  		is_trdev = 0;
  		if (i >= (MAX_LEC_ITF - NUM_TR_DEVS))
  			is_trdev = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842

d44f77466   Chas Williams   [ATM]: [lec] inde...
843
  		size = sizeof(struct lec_priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  #ifdef CONFIG_TR
d44f77466   Chas Williams   [ATM]: [lec] inde...
845
846
847
  		if (is_trdev)
  			dev_lec[i] = alloc_trdev(size);
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
849
850
851
  			dev_lec[i] = alloc_etherdev(size);
  		if (!dev_lec[i])
  			return -ENOMEM;
eb0445887   chas williams - CONTRACTOR   atm: [lec] initia...
852
  		dev_lec[i]->netdev_ops = &lec_netdev_ops;
d44f77466   Chas Williams   [ATM]: [lec] inde...
853
854
855
856
857
  		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...
858
  		priv = netdev_priv(dev_lec[i]);
d44f77466   Chas Williams   [ATM]: [lec] inde...
859
  		priv->is_trdev = is_trdev;
d44f77466   Chas Williams   [ATM]: [lec] inde...
860
  	} else {
524ad0a79   Wang Chen   netdevice: safe c...
861
  		priv = netdev_priv(dev_lec[i]);
d44f77466   Chas Williams   [ATM]: [lec] inde...
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
  		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...
886
  	if (dev_lec[i]->flags & IFF_UP)
d44f77466   Chas Williams   [ATM]: [lec] inde...
887
  		netif_start_queue(dev_lec[i]);
d44f77466   Chas Williams   [ATM]: [lec] inde...
888
889
  	__module_get(THIS_MODULE);
  	return i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
891
892
  }
  
  #ifdef CONFIG_PROC_FS
36cbd3dcc   Jan Engelhardt   net: mark read-on...
893
  static const char *lec_arp_get_status_string(unsigned char status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
  {
36cbd3dcc   Jan Engelhardt   net: mark read-on...
895
  	static const char *const lec_arp_status_string[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
  		"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...
923
  		seq_printf(seq, "        ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
926
  	if (entry->recv_vcc) {
  		seq_printf(seq, "     %3d %3d", entry->recv_vcc->vpi,
  			   entry->recv_vcc->vci);
d44f77466   Chas Williams   [ATM]: [lec] inde...
927
928
929
  	}
  	seq_putc(seq, '
  ');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
932
933
  struct lec_state {
  	unsigned long flags;
  	struct lec_priv *locked;
d0732f649   Chas Williams   [ATM]: [lec] conv...
934
  	struct hlist_node *node;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
936
937
938
939
  	struct net_device *dev;
  	int itf;
  	int arp_table;
  	int misc_table;
  };
d0732f649   Chas Williams   [ATM]: [lec] conv...
940
  static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
942
  			  loff_t *l)
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
943
944
  	struct hlist_node *e = state->node;
  	struct lec_arp_table *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
  
  	if (!e)
d0732f649   Chas Williams   [ATM]: [lec] conv...
947
  		e = tbl->first;
2e1e9848a   Joe Perches   [ATM]: Use SEQ_ST...
948
  	if (e == SEQ_START_TOKEN) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
949
  		e = tbl->first;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
  		--*l;
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
952
953
  
  	hlist_for_each_entry_from(tmp, e, next) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
956
  		if (--*l < 0)
  			break;
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
957
  	state->node = e;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
958
959
960
961
  	return (*l < 0) ? state : NULL;
  }
  
  static void *lec_arp_walk(struct lec_state *state, loff_t *l,
d44f77466   Chas Williams   [ATM]: [lec] inde...
962
  			  struct lec_priv *priv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
964
965
966
967
  {
  	void *v = NULL;
  	int p;
  
  	for (p = state->arp_table; p < LEC_ARP_TABLE_SIZE; p++) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
968
  		v = lec_tbl_walk(state, &priv->lec_arp_tables[p], l);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
970
971
972
973
974
975
976
977
978
  		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...
979
980
981
982
  	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
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
  	};
  	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...
1003
  	if (!lec_arp_walk(state, l, priv) && !lec_misc_walk(state, l, priv)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  		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...
1018
1019
  	v = (dev && netdev_priv(dev)) ?
  		lec_priv_walk(state, l, netdev_priv(dev)) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
  	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...
1038
  	return v;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
  }
  
  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...
1050
  	state->node = SEQ_START_TOKEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051

2e1e9848a   Joe Perches   [ATM]: Use SEQ_ST...
1052
  	return *pos ? lec_get_idx(state, *pos) : SEQ_START_TOKEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
  }
  
  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...
1077
1078
  	static const char lec_banner[] =
  	    "Itf  MAC          ATM destination"
d44f77466   Chas Williams   [ATM]: [lec] inde...
1079
1080
1081
  	    "                          Status            Flags "
  	    "VPI/VCI Recv VPI/VCI
  ";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082

2e1e9848a   Joe Perches   [ATM]: Use SEQ_ST...
1083
  	if (v == SEQ_START_TOKEN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
1086
  		seq_puts(seq, lec_banner);
  	else {
  		struct lec_state *state = seq->private;
d44f77466   Chas Williams   [ATM]: [lec] inde...
1087
  		struct net_device *dev = state->dev;
c48192a70   Joe Perches   net/atm/lec.c: ch...
1088
1089
1090
  		struct lec_arp_table *entry = hlist_entry(state->node,
  							  struct lec_arp_table,
  							  next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
1092
  
  		seq_printf(seq, "%s ", dev->name);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1093
  		lec_info(seq, entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1094
1095
1096
  	}
  	return 0;
  }
56b3d975b   Philippe De Muyter   [NET]: Make all i...
1097
  static const struct seq_operations lec_seq_ops = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
1098
1099
1100
1101
  	.start = lec_seq_start,
  	.next = lec_seq_next,
  	.stop = lec_seq_stop,
  	.show = lec_seq_show,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
1103
1104
1105
  };
  
  static int lec_seq_open(struct inode *inode, struct file *file)
  {
9a8c09e73   Pavel Emelyanov   [ATM]: Use seq_op...
1106
  	return seq_open_private(file, &lec_seq_ops, sizeof(struct lec_state));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
1108
  static const struct file_operations lec_seq_fops = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
1109
1110
1111
1112
  	.owner = THIS_MODULE,
  	.open = lec_seq_open,
  	.read = seq_read,
  	.llseek = seq_lseek,
9a8c09e73   Pavel Emelyanov   [ATM]: Use seq_op...
1113
  	.release = seq_release_private,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
1115
1116
1117
1118
1119
1120
  };
  #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...
1121

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
  	switch (cmd) {
d44f77466   Chas Williams   [ATM]: [lec] inde...
1123
1124
1125
1126
1127
1128
1129
1130
  	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
1131
1132
1133
  	}
  
  	switch (cmd) {
d44f77466   Chas Williams   [ATM]: [lec] inde...
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
  	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
1145
1146
1147
1148
1149
1150
  	}
  
  	return err;
  }
  
  static struct atm_ioctl lane_ioctl_ops = {
d44f77466   Chas Williams   [ATM]: [lec] inde...
1151
1152
  	.owner = THIS_MODULE,
  	.ioctl = lane_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
1155
1156
1157
1158
  };
  
  static int __init lane_module_init(void)
  {
  #ifdef CONFIG_PROC_FS
  	struct proc_dir_entry *p;
16e297b35   Wang Chen   [ATM]: Use proc_c...
1159
  	p = proc_create("lec", S_IRUGO, atm_proc_root, &lec_seq_fops);
dbee0d3f4   Wang Chen   [ATM]: When proc_...
1160
  	if (!p) {
99824461e   Joe Perches   net/atm: Convert ...
1161
1162
  		pr_err("Unable to initialize /proc/net/atm/lec
  ");
dbee0d3f4   Wang Chen   [ATM]: When proc_...
1163
1164
  		return -ENOMEM;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
  #endif
  
  	register_atm_ioctl(&lane_ioctl_ops);
36a9f77e5   Michal Marek   atm: Drop __TIME_...
1168
1169
  	pr_info("lec.c: initialized
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
1170
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
1173
1174
  }
  
  static void __exit lane_module_cleanup(void)
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
1175
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176
1177
1178
1179
  
  	remove_proc_entry("lec", atm_proc_root);
  
  	deregister_atm_ioctl(&lane_ioctl_ops);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1180
1181
  	for (i = 0; i < MAX_LEC_ITF; i++) {
  		if (dev_lec[i] != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
  			unregister_netdev(dev_lec[i]);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1183
1184
1185
1186
  			free_netdev(dev_lec[i]);
  			dev_lec[i] = NULL;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
  }
  
  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...
1199
  static int lane2_resolve(struct net_device *dev, const u8 *dst_mac, int force,
d44f77466   Chas Williams   [ATM]: [lec] inde...
1200
  			 u8 **tlvs, u32 *sizeoftlvs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
1202
  {
  	unsigned long flags;
524ad0a79   Wang Chen   netdevice: safe c...
1203
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1204
1205
1206
  	struct lec_arp_table *table;
  	struct sk_buff *skb;
  	int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207

d44f77466   Chas Williams   [ATM]: [lec] inde...
1208
  	if (force == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
  		spin_lock_irqsave(&priv->lec_arp_lock, flags);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1210
  		table = lec_arp_find(priv, dst_mac);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
  		spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1212
1213
  		if (table == NULL)
  			return -1;
2afe37cdf   Arnaldo Carvalho de Melo   [ATM]: Use kmemdu...
1214
  		*tlvs = kmemdup(table->tlvs, table->sizeoftlvs, GFP_ATOMIC);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1215
1216
  		if (*tlvs == NULL)
  			return -1;
d44f77466   Chas Williams   [ATM]: [lec] inde...
1217
1218
1219
1220
  		*sizeoftlvs = table->sizeoftlvs;
  
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
1222
1223
  
  	if (sizeoftlvs == NULL)
  		retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, NULL);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1224

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
1226
1227
1228
1229
  	else {
  		skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC);
  		if (skb == NULL)
  			return -1;
  		skb->len = *sizeoftlvs;
27d7ff46a   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1230
  		skb_copy_to_linear_data(skb, *tlvs, *sizeoftlvs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1231
1232
  		retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb);
  	}
d44f77466   Chas Williams   [ATM]: [lec] inde...
1233
1234
  	return retval;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
1236
1237
1238
1239
1240
1241
1242
  
  /*
   * 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...
1243
1244
  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
1245
  {
d44f77466   Chas Williams   [ATM]: [lec] inde...
1246
1247
  	int retval;
  	struct sk_buff *skb;
524ad0a79   Wang Chen   netdevice: safe c...
1248
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1249
1250
  
  	if (compare_ether_addr(lan_dst, dev->dev_addr))
c48192a70   Joe Perches   net/atm/lec.c: ch...
1251
  		return 0;	/* not our mac address */
d44f77466   Chas Williams   [ATM]: [lec] inde...
1252
1253
  
  	kfree(priv->tlvs);	/* NULL if there was no previous association */
2afe37cdf   Arnaldo Carvalho de Melo   [ATM]: Use kmemdu...
1254
  	priv->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1255
  	if (priv->tlvs == NULL)
c48192a70   Joe Perches   net/atm/lec.c: ch...
1256
  		return 0;
d44f77466   Chas Williams   [ATM]: [lec] inde...
1257
  	priv->sizeoftlvs = sizeoftlvs;
d44f77466   Chas Williams   [ATM]: [lec] inde...
1258
1259
1260
1261
1262
  
  	skb = alloc_skb(sizeoftlvs, GFP_ATOMIC);
  	if (skb == NULL)
  		return 0;
  	skb->len = sizeoftlvs;
27d7ff46a   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1263
  	skb_copy_to_linear_data(skb, tlvs, sizeoftlvs);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1264
1265
  	retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
  	if (retval != 0)
c48192a70   Joe Perches   net/atm/lec.c: ch...
1266
1267
  		pr_info("lec.c: lane2_associate_req() failed
  ");
d44f77466   Chas Williams   [ATM]: [lec] inde...
1268
1269
1270
1271
  	/*
  	 * If the previous association has changed we must
  	 * somehow notify other LANE entities about the change
  	 */
c48192a70   Joe Perches   net/atm/lec.c: ch...
1272
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1273
1274
1275
1276
1277
1278
  }
  
  /*
   * LANE2: 3.1.5, LE_ASSOCIATE.indication
   *
   */
61c33e012   Mitchell Blank Jr   atm: use const wh...
1279
1280
  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
1281
1282
  {
  #if 0
d44f77466   Chas Williams   [ATM]: [lec] inde...
1283
  	int i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
  #endif
524ad0a79   Wang Chen   netdevice: safe c...
1285
  	struct lec_priv *priv = netdev_priv(dev);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1286
1287
1288
1289
1290
1291
1292
  #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
1293

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

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

2afe37cdf   Arnaldo Carvalho de Melo   [ATM]: Use kmemdu...
1299
  	entry->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1300
1301
  	if (entry->tlvs == NULL)
  		return;
d44f77466   Chas Williams   [ATM]: [lec] inde...
1302
  	entry->sizeoftlvs = sizeoftlvs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
  #endif
  #if 0
c48192a70   Joe Perches   net/atm/lec.c: ch...
1305
1306
1307
1308
  	pr_info("
  ");
  	pr_info("dump of tlvs, sizeoftlvs=%d
  ", sizeoftlvs);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1309
  	while (i < sizeoftlvs)
c48192a70   Joe Perches   net/atm/lec.c: ch...
1310
  		pr_cont("%02x ", tlvs[i++]);
d44f77466   Chas Williams   [ATM]: [lec] inde...
1311

c48192a70   Joe Perches   net/atm/lec.c: ch...
1312
1313
  	pr_cont("
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314
  #endif
d44f77466   Chas Williams   [ATM]: [lec] inde...
1315
1316
1317
1318
1319
  	/* 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
1320
1321
1322
1323
1324
1325
1326
  }
  
  /*
   * 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
1327
1328
1329
   */
  
  #include <linux/types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330
  #include <linux/timer.h>
c48192a70   Joe Perches   net/atm/lec.c: ch...
1331
  #include <linux/param.h>
60063497a   Arun Sharma   atomic: use <linu...
1332
  #include <linux/atomic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333
1334
  #include <linux/inetdevice.h>
  #include <net/route.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
  #if 0
c48192a70   Joe Perches   net/atm/lec.c: ch...
1336
  #define pr_debug(format, args...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
  /*
99824461e   Joe Perches   net/atm: Convert ...
1338
    #define pr_debug printk
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
1341
1342
1343
  */
  #endif
  #define DEBUG_ARP_TABLE 0
  
  #define LEC_ARP_REFRESH_INTERVAL (3*HZ)
c4028958b   David Howells   WorkStruct: make ...
1344
  static void lec_arp_check_expire(struct work_struct *work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
  static void lec_arp_expire_arp(unsigned long data);
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1346
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1347
1348
   * Arp table funcs
   */
c48192a70   Joe Perches   net/atm/lec.c: ch...
1349
  #define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE - 1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1350
1351
1352
1353
  
  /*
   * Initialization of arp-cache
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1354
  static void lec_arp_init(struct lec_priv *priv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1356
  	unsigned short i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1357

c48192a70   Joe Perches   net/atm/lec.c: ch...
1358
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
d0732f649   Chas Williams   [ATM]: [lec] conv...
1359
  		INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1360
1361
1362
  	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
1363
  	spin_lock_init(&priv->lec_arp_lock);
c4028958b   David Howells   WorkStruct: make ...
1364
  	INIT_DELAYED_WORK(&priv->lec_arp_work, lec_arp_check_expire);
987e46bdf   Chas Williams   [ATM]: [lec] use ...
1365
  	schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1366
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1367
  static void lec_arp_clear_vccs(struct lec_arp_table *entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1368
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1369
  	if (entry->vcc) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1370
1371
  		struct atm_vcc *vcc = entry->vcc;
  		struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1372
  		struct net_device *dev = (struct net_device *)vcc->proto_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1374
  		vcc->pop = vpriv->old_pop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1375
1376
1377
1378
  		if (vpriv->xoff)
  			netif_wake_queue(dev);
  		kfree(vpriv);
  		vcc->user_back = NULL;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1379
  		vcc->push = entry->old_push;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
  		vcc_release_async(vcc, -EPIPE);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1381
  		entry->vcc = NULL;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1382
1383
1384
  	}
  	if (entry->recv_vcc) {
  		entry->recv_vcc->push = entry->old_recv_push;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
  		vcc_release_async(entry->recv_vcc, -EPIPE);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1386
1387
  		entry->recv_vcc = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1388
1389
1390
1391
1392
1393
  }
  
  /*
   * 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...
1394
  static inline void
d0732f649   Chas Williams   [ATM]: [lec] conv...
1395
  lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1397
  	struct hlist_head *tmp;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1398

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

99824461e   Joe Perches   net/atm: Convert ...
1402
1403
  	pr_debug("Added entry:%pM
  ", entry->mac_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
1405
1406
1407
1408
  }
  
  /*
   * Remove entry from lec_arp_table
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1409
1410
  static int
  lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1411
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1412
1413
1414
  	struct hlist_node *node;
  	struct lec_arp_table *entry;
  	int i, remove_vcc = 1;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1415

c48192a70   Joe Perches   net/atm/lec.c: ch...
1416
  	if (!to_remove)
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1417
  		return -1;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1418
1419
  
  	hlist_del(&to_remove->next);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1420
  	del_timer(&to_remove->timer);
c48192a70   Joe Perches   net/atm/lec.c: ch...
1421
1422
1423
1424
  	/*
  	 * If this is the only MAC connected to this VCC,
  	 * also tear down the VCC
  	 */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1425
1426
1427
1428
  	if (to_remove->status >= ESI_FLUSH_PENDING) {
  		/*
  		 * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
  		 */
d0732f649   Chas Williams   [ATM]: [lec] conv...
1429
  		for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
1430
1431
  			hlist_for_each_entry(entry, node,
  					     &priv->lec_arp_tables[i], next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1432
1433
  				if (memcmp(to_remove->atm_addr,
  					   entry->atm_addr, ATM_ESA_LEN) == 0) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1434
1435
1436
1437
1438
1439
1440
1441
1442
  					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 ...
1443
1444
  	pr_debug("Removed entry:%pM
  ", to_remove->mac_addr);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1445
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
1447
1448
  }
  
  #if DEBUG_ARP_TABLE
36cbd3dcc   Jan Engelhardt   net: mark read-on...
1449
  static const char *get_status_string(unsigned char st)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
  	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...
1462
  	}
c48192a70   Joe Perches   net/atm/lec.c: ch...
1463
  	return "<UNKNOWN>";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1464
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1466
  static void dump_arp_table(struct lec_priv *priv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1467
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1468
  	struct hlist_node *node;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1469
  	struct lec_arp_table *rulla;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1470
1471
  	char buf[256];
  	int i, j, offset;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1472

c48192a70   Joe Perches   net/atm/lec.c: ch...
1473
1474
  	pr_info("Dump %p:
  ", priv);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1475
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
1476
1477
  		hlist_for_each_entry(rulla, node,
  				     &priv->lec_arp_tables[i], next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1478
1479
1480
  			offset = 0;
  			offset += sprintf(buf, "%d: %p
  ", i, rulla);
c48192a70   Joe Perches   net/atm/lec.c: ch...
1481
1482
1483
  			offset += sprintf(buf + offset, "Mac: %pM",
  					  rulla->mac_addr);
  			offset += sprintf(buf + offset, " Atm:");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
  			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...
1503
1504
  			pr_info("%s
  ", buf);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1505
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1506
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1507
1508
  
  	if (!hlist_empty(&priv->lec_no_forward))
c48192a70   Joe Perches   net/atm/lec.c: ch...
1509
1510
  		pr_info("No forward
  ");
d0732f649   Chas Williams   [ATM]: [lec] conv...
1511
  	hlist_for_each_entry(rulla, node, &priv->lec_no_forward, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1512
  		offset = 0;
c48192a70   Joe Perches   net/atm/lec.c: ch...
1513
1514
  		offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr);
  		offset += sprintf(buf + offset, " Atm:");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
  		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...
1531
1532
  		pr_info("%s
  ", buf);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1533
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1534
1535
  
  	if (!hlist_empty(&priv->lec_arp_empty_ones))
c48192a70   Joe Perches   net/atm/lec.c: ch...
1536
1537
  		pr_info("Empty ones
  ");
d0732f649   Chas Williams   [ATM]: [lec] conv...
1538
  	hlist_for_each_entry(rulla, node, &priv->lec_arp_empty_ones, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1539
  		offset = 0;
c48192a70   Joe Perches   net/atm/lec.c: ch...
1540
1541
  		offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr);
  		offset += sprintf(buf + offset, " Atm:");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
  		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...
1558
  		pr_info("%s", buf);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1559
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1560
  	if (!hlist_empty(&priv->mcast_fwds))
c48192a70   Joe Perches   net/atm/lec.c: ch...
1561
1562
  		pr_info("Multicast Forward VCCs
  ");
d0732f649   Chas Williams   [ATM]: [lec] conv...
1563
  	hlist_for_each_entry(rulla, node, &priv->mcast_fwds, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1564
  		offset = 0;
c48192a70   Joe Perches   net/atm/lec.c: ch...
1565
1566
  		offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr);
  		offset += sprintf(buf + offset, " Atm:");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
  		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...
1583
1584
  		pr_info("%s
  ", buf);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1585
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1586

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1587
  }
d0732f649   Chas Williams   [ATM]: [lec] conv...
1588
1589
1590
  #else
  #define dump_arp_table(priv) do { } while (0)
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591
1592
1593
1594
  
  /*
   * Destruction of arp-cache
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1595
  static void lec_arp_destroy(struct lec_priv *priv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1596
1597
  {
  	unsigned long flags;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1598
1599
  	struct hlist_node *node, *next;
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1600
  	int i;
afe2c511f   Tejun Heo   workqueue: conver...
1601
  	cancel_delayed_work_sync(&priv->lec_arp_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1603
1604
1605
  	/*
  	 * Remove all entries
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1606
1607
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1608
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
1609
1610
  		hlist_for_each_entry_safe(entry, node, next,
  					  &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1611
  			lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1612
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1613
  		}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1614
  		INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1615
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1616

c48192a70   Joe Perches   net/atm/lec.c: ch...
1617
1618
  	hlist_for_each_entry_safe(entry, node, next,
  				  &priv->lec_arp_empty_ones, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1619
1620
  		del_timer_sync(&entry->timer);
  		lec_arp_clear_vccs(entry);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1621
  		hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1622
  		lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1623
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1624
  	INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
c48192a70   Joe Perches   net/atm/lec.c: ch...
1625
1626
  	hlist_for_each_entry_safe(entry, node, next,
  				  &priv->lec_no_forward, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1627
1628
  		del_timer_sync(&entry->timer);
  		lec_arp_clear_vccs(entry);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1629
  		hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1630
  		lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1631
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1632
1633
1634
  	INIT_HLIST_HEAD(&priv->lec_no_forward);
  
  	hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1635
1636
  		/* No timer, LANEv2 7.1.20 and 2.3.5.3 */
  		lec_arp_clear_vccs(entry);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1637
  		hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1638
  		lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1639
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
1640
  	INIT_HLIST_HEAD(&priv->mcast_fwds);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1641
  	priv->mcast_vcc = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1642
1643
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1644
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645
1646
   * Find entry by mac_address
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1647
  static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
61c33e012   Mitchell Blank Jr   atm: use const wh...
1648
  					  const unsigned char *mac_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1649
  {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1650
1651
1652
  	struct hlist_node *node;
  	struct hlist_head *head;
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1653

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

d0732f649   Chas Williams   [ATM]: [lec] conv...
1657
1658
  	head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])];
  	hlist_for_each_entry(entry, node, head, next) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
1659
  		if (!compare_ether_addr(mac_addr, entry->mac_addr))
d0732f649   Chas Williams   [ATM]: [lec] conv...
1660
  			return entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1661
1662
  	}
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1663
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1664
  static struct lec_arp_table *make_entry(struct lec_priv *priv,
61c33e012   Mitchell Blank Jr   atm: use const wh...
1665
  					const unsigned char *mac_addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1666
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1667
1668
1669
1670
  	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...
1671
1672
  		pr_info("LEC: Arp entry kmalloc failed
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1673
1674
1675
  		return NULL;
  	}
  	memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1676
  	INIT_HLIST_NODE(&to_return->next);
b24b8a247   Pavel Emelyanov   [NET]: Convert in...
1677
1678
  	setup_timer(&to_return->timer, lec_arp_expire_arp,
  			(unsigned long)to_return);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1679
1680
1681
  	to_return->last_used = jiffies;
  	to_return->priv = priv;
  	skb_queue_head_init(&to_return->tx_wait);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1682
  	atomic_set(&to_return->usage, 1);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1683
  	return to_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1684
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1685
1686
  /* Arp sent timer expired */
  static void lec_arp_expire_arp(unsigned long data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1687
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1688
1689
1690
  	struct lec_arp_table *entry;
  
  	entry = (struct lec_arp_table *)data;
99824461e   Joe Perches   net/atm: Convert ...
1691
1692
  	pr_debug("
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
  	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
1705
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1706
1707
  /* Unknown/unused vcc expire, remove associated entry */
  static void lec_arp_expire_vcc(unsigned long data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1708
1709
  {
  	unsigned long flags;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1710
1711
  	struct lec_arp_table *to_remove = (struct lec_arp_table *)data;
  	struct lec_priv *priv = (struct lec_priv *)to_remove->priv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1712

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

99824461e   Joe Perches   net/atm: Convert ...
1715
1716
1717
1718
1719
  	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
1720
1721
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1722
  	hlist_del(&to_remove->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1723
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1724
  	lec_arp_clear_vccs(to_remove);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1725
  	lec_arp_put(to_remove);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1726
  }
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
  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
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
  /*
   * 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 ...
1789
  static void lec_arp_check_expire(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1790
1791
  {
  	unsigned long flags;
c4028958b   David Howells   WorkStruct: make ...
1792
1793
  	struct lec_priv *priv =
  		container_of(work, struct lec_priv, lec_arp_work.work);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1794
1795
  	struct hlist_node *node, *next;
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1796
  	unsigned long now;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1797
  	int i;
99824461e   Joe Perches   net/atm: Convert ...
1798
1799
  	pr_debug("%p
  ", priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1800
  	now = jiffies;
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
1801
  restart:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1802
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1803
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
1804
1805
  		hlist_for_each_entry_safe(entry, node, next,
  					  &priv->lec_arp_tables[i], next) {
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
  			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 ...
1816
  				lec_arp_put(entry);
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
1817
1818
  
  				goto restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1819
1820
1821
1822
  			}
  		}
  	}
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
987e46bdf   Chas Williams   [ATM]: [lec] use ...
1823
  	schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1824
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1825

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1826
1827
  /*
   * Try to find vcc where mac_address is attached.
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1828
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1829
   */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1830
  static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
c48192a70   Joe Perches   net/atm/lec.c: ch...
1831
1832
  				       const unsigned char *mac_to_find,
  				       int is_rdesc,
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1833
  				       struct lec_arp_table **ret_entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1834
1835
  {
  	unsigned long flags;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1836
  	struct lec_arp_table *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1837
  	struct atm_vcc *found;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1838
1839
1840
1841
  	if (mac_to_find[0] & 0x01) {
  		switch (priv->lane_version) {
  		case 1:
  			return priv->mcast_vcc;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1842
1843
1844
1845
1846
1847
1848
1849
  		case 2:	/* LANE2 wants arp for multicast addresses */
  			if (!compare_ether_addr(mac_to_find, bus_mac))
  				return priv->mcast_vcc;
  			break;
  		default:
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
1851
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1852
1853
1854
1855
1856
1857
  	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 ...
1858
  			lec_arp_hold(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1859
1860
  			*ret_entry = entry;
  			found = entry->vcc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1861
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1862
1863
1864
  		}
  		/*
  		 * If the LE_ARP cache entry is still pending, reset count to 0
75b895c15   Scott Talbert   [ATM]: [lec] rese...
1865
1866
  		 * so another LE_ARP request can be made for this frame.
  		 */
c48192a70   Joe Perches   net/atm/lec.c: ch...
1867
  		if (entry->status == ESI_ARP_PENDING)
75b895c15   Scott Talbert   [ATM]: [lec] rese...
1868
  			entry->no_tries = 0;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
  		/*
  		 * 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 ...
1879
1880
  			pr_debug("Flooding..
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1881
  			found = priv->mcast_vcc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1882
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1883
1884
1885
  		}
  		/*
  		 * We got here because entry->status == ESI_FLUSH_PENDING
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1886
1887
1888
  		 * 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 ...
1889
  		lec_arp_hold(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1890
  		*ret_entry = entry;
99824461e   Joe Perches   net/atm: Convert ...
1891
1892
1893
  		pr_debug("entry->status %d entry->vcc %p
  ", entry->status,
  			 entry->vcc);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1894
1895
1896
1897
  		found = NULL;
  	} else {
  		/* No matching entry was found */
  		entry = make_entry(priv, mac_to_find);
99824461e   Joe Perches   net/atm: Convert ...
1898
1899
  		pr_debug("Making entry
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1900
1901
  		if (!entry) {
  			found = priv->mcast_vcc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1902
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
  		}
  		lec_arp_add(priv, entry);
  		/* We want arp-request(s) to be sent */
  		entry->packets_flooded = 1;
  		entry->status = ESI_ARP_PENDING;
  		entry->no_tries = 1;
  		entry->last_used = entry->timestamp = jiffies;
  		entry->is_rdesc = is_rdesc;
  		if (entry->is_rdesc)
  			send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL,
  				     NULL);
  		else
  			send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL);
  		entry->timer.expires = jiffies + (1 * HZ);
  		entry->timer.function = lec_arp_expire_arp;
  		add_timer(&entry->timer);
  		found = priv->mcast_vcc;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1921
1922
1923
1924
1925
1926
1927
  
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  	return found;
  }
  
  static int
61c33e012   Mitchell Blank Jr   atm: use const wh...
1928
  lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr,
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1929
  		unsigned long permanent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1930
1931
  {
  	unsigned long flags;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1932
1933
  	struct hlist_node *node, *next;
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1934
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1935

99824461e   Joe Perches   net/atm: Convert ...
1936
1937
  	pr_debug("
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1938
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1939
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
1940
1941
1942
1943
1944
  		hlist_for_each_entry_safe(entry, node, next,
  					  &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
1945
  				lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
1946
  				lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1947
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1948
  			spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1949
1950
1951
  			return 0;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1952
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1953
  	return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1954
1955
1956
  }
  
  /*
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
1957
   * Notifies:  Response to arp_request (atm_addr != NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1958
1959
   */
  static void
61c33e012   Mitchell Blank Jr   atm: use const wh...
1960
1961
  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...
1962
  	       unsigned int targetless_le_arp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1963
1964
  {
  	unsigned long flags;
d0732f649   Chas Williams   [ATM]: [lec] conv...
1965
  	struct hlist_node *node, *next;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1966
1967
  	struct lec_arp_table *entry, *tmp;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1968

99824461e   Joe Perches   net/atm: Convert ...
1969
1970
1971
  	pr_debug("%smac:%pM
  ",
  		 (targetless_le_arp) ? "targetless " : "", mac_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1972
1973
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1974
1975
1976
1977
1978
1979
  	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...
1980
  	if (!hlist_empty(&priv->lec_arp_empty_ones)) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
1981
1982
  		hlist_for_each_entry_safe(entry, node, next,
  					  &priv->lec_arp_empty_ones, next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
1983
1984
  			if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) {
  				hlist_del(&entry->next);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
1985
  				del_timer(&entry->timer);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1986
1987
1988
1989
1990
1991
1992
1993
1994
  				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 ...
1995
  					lec_arp_put(entry);
d0732f649   Chas Williams   [ATM]: [lec] conv...
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
  					entry = tmp;
  				} else {
  					entry->status = ESI_FORWARD_DIRECT;
  					memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
  					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...
2007
2008
  				pr_debug("After update
  ");
d0732f649   Chas Williams   [ATM]: [lec] conv...
2009
2010
  				dump_arp_table(priv);
  				goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2011
  			}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2012
2013
  		}
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
2014

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
  	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++) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
2027
2028
  		hlist_for_each_entry(tmp, node,
  				     &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
  			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...
2051
  		send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2052
  	}
522400623   Stephen Hemminger   [ATM]: Replace DP...
2053
2054
  	pr_debug("After update2
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2055
  	dump_arp_table(priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2056
2057
2058
2059
2060
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
  
  /*
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
2061
   * Notifies: Vcc setup ready
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2062
2063
   */
  static void
61c33e012   Mitchell Blank Jr   atm: use const wh...
2064
  lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2065
2066
  	      struct atm_vcc *vcc,
  	      void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2067
2068
  {
  	unsigned long flags;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2069
  	struct hlist_node *node;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2070
2071
  	struct lec_arp_table *entry;
  	int i, found_entry = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2072
2073
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
c48192a70   Joe Perches   net/atm/lec.c: ch...
2074
  	/* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2075
  	if (ioc_data->receive == 2) {
522400623   Stephen Hemminger   [ATM]: Replace DP...
2076
2077
  		pr_debug("LEC_ARP: Attaching mcast forward
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2078
  #if 0
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2079
2080
  		entry = lec_arp_find(priv, bus_mac);
  		if (!entry) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
2081
2082
  			pr_info("LEC_ARP: Multicast entry not found!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2083
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2084
2085
2086
2087
  		}
  		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
2088
  #endif
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2089
2090
  		entry = make_entry(priv, bus_mac);
  		if (entry == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2092
2093
2094
2095
  		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...
2096
  		hlist_add_head(&entry->next, &priv->mcast_fwds);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2097
2098
2099
2100
2101
2102
  		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 ...
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
  		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...
2115
2116
  		entry = make_entry(priv, bus_mac);
  		if (entry == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2117
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2118
2119
2120
2121
2122
2123
2124
  		memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
  		memset(entry->mac_addr, 0, ETH_ALEN);
  		entry->recv_vcc = vcc;
  		entry->old_recv_push = old_push;
  		entry->status = ESI_UNKNOWN;
  		entry->timer.expires = jiffies + priv->vcc_timeout_period;
  		entry->timer.function = lec_arp_expire_vcc;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2125
  		hlist_add_head(&entry->next, &priv->lec_no_forward);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2126
  		add_timer(&entry->timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2127
2128
  		dump_arp_table(priv);
  		goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2129
  	}
99824461e   Joe Perches   net/atm: Convert ...
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
  	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...
2142
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
2143
2144
  		hlist_for_each_entry(entry, node,
  				     &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2145
2146
2147
  			if (memcmp
  			    (ioc_data->atm_addr, entry->atm_addr,
  			     ATM_ESA_LEN) == 0) {
522400623   Stephen Hemminger   [ATM]: Replace DP...
2148
2149
2150
2151
  				pr_debug("LEC_ARP: Attaching data direct
  ");
  				pr_debug("Currently -> Vcc: %d, Rvcc:%d
  ",
99824461e   Joe Perches   net/atm: Convert ...
2152
2153
2154
  					 entry->vcc ? entry->vcc->vci : 0,
  					 entry->recv_vcc ? entry->recv_vcc->
  					 vci : 0);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
  				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
2168
  #if 0
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2169
2170
2171
2172
  						send_to_lecd(priv, l_flush_xmt,
  							     NULL,
  							     entry->atm_addr,
  							     NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173
  #endif
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
  					}
  				} 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...
2193
2194
  		pr_debug("After vcc was added
  ");
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2195
  		dump_arp_table(priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2196
  		goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2197
2198
2199
2200
2201
2202
2203
  	}
  	/*
  	 * 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
2204
  		goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2205
2206
2207
2208
2209
  	entry->vcc = vcc;
  	entry->old_push = old_push;
  	memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
  	memset(entry->mac_addr, 0, ETH_ALEN);
  	entry->status = ESI_UNKNOWN;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2210
  	hlist_add_head(&entry->next, &priv->lec_arp_empty_ones);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2211
2212
2213
  	entry->timer.expires = jiffies + priv->vcc_timeout_period;
  	entry->timer.function = lec_arp_expire_vcc;
  	add_timer(&entry->timer);
522400623   Stephen Hemminger   [ATM]: Replace DP...
2214
2215
  	pr_debug("After vcc was added
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2216
2217
2218
2219
  	dump_arp_table(priv);
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2220
  static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2221
2222
  {
  	unsigned long flags;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2223
  	struct hlist_node *node;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2224
2225
  	struct lec_arp_table *entry;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2226

99824461e   Joe Perches   net/atm: Convert ...
2227
2228
  	pr_debug("%lx
  ", tran_id);
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2229
  restart:
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2230
2231
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
2232
2233
2234
2235
  		hlist_for_each_entry(entry, node,
  				     &priv->lec_arp_tables[i], next) {
  			if (entry->flush_tran_id == tran_id &&
  			    entry->status == ESI_FLUSH_PENDING) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2236
  				struct sk_buff *skb;
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2237
  				struct atm_vcc *vcc = entry->vcc;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2238

6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2239
  				lec_arp_hold(entry);
c48192a70   Joe Perches   net/atm/lec.c: ch...
2240
2241
  				spin_unlock_irqrestore(&priv->lec_arp_lock,
  						       flags);
b4c84ec0f   Joe Perches   net/atm/lec.c: Ad...
2242
  				while ((skb = skb_dequeue(&entry->tx_wait)))
162619e59   Stephen Hemminger   lec: convert to i...
2243
  					lec_send(vcc, skb);
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2244
  				entry->last_used = jiffies;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2245
  				entry->status = ESI_FORWARD_DIRECT;
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2246
  				lec_arp_put(entry);
522400623   Stephen Hemminger   [ATM]: Replace DP...
2247
2248
  				pr_debug("LEC_ARP: Flushed
  ");
6656e3c4c   Chas Williams   [ATM]: [lec] use ...
2249
  				goto restart;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2250
2251
2252
  			}
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2253
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2254
  	dump_arp_table(priv);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2255
2256
2257
2258
  }
  
  static void
  lec_set_flush_tran_id(struct lec_priv *priv,
61c33e012   Mitchell Blank Jr   atm: use const wh...
2259
  		      const unsigned char *atm_addr, unsigned long tran_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2260
2261
  {
  	unsigned long flags;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2262
  	struct hlist_node *node;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2263
2264
  	struct lec_arp_table *entry;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2265
2266
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2267
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
c48192a70   Joe Perches   net/atm/lec.c: ch...
2268
2269
  		hlist_for_each_entry(entry, node,
  				     &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2270
2271
  			if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
  				entry->flush_tran_id = tran_id;
522400623   Stephen Hemminger   [ATM]: Replace DP...
2272
2273
  				pr_debug("Set flush transaction id to %lx for %p
  ",
99824461e   Joe Perches   net/atm: Convert ...
2274
  					 tran_id, entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2275
  			}
d0732f649   Chas Williams   [ATM]: [lec] conv...
2276
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2277
2278
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2279
  static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2280
2281
  {
  	unsigned long flags;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2282
2283
2284
2285
  	unsigned char mac_addr[] = {
  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  	};
  	struct lec_arp_table *to_add;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2286
2287
  	struct lec_vcc_priv *vpriv;
  	int err = 0;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2288

c48192a70   Joe Perches   net/atm/lec.c: ch...
2289
2290
  	vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL);
  	if (!vpriv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2291
2292
2293
2294
  		return -ENOMEM;
  	vpriv->xoff = 0;
  	vpriv->old_pop = vcc->pop;
  	vcc->user_back = vpriv;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2295
  	vcc->pop = lec_pop;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2296
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2297
2298
  	to_add = make_entry(priv, mac_addr);
  	if (!to_add) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2299
2300
  		vcc->pop = vpriv->old_pop;
  		kfree(vpriv);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2301
  		err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2302
  		goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2303
2304
2305
2306
2307
2308
2309
2310
2311
  	}
  	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
2312
2313
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2314
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2315
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2316
  static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2317
2318
  {
  	unsigned long flags;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2319
2320
  	struct hlist_node *node, *next;
  	struct lec_arp_table *entry;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2321
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2322

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

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

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2329
  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
c48192a70   Joe Perches   net/atm/lec.c: ch...
2330
2331
  		hlist_for_each_entry_safe(entry, node, next,
  					  &priv->lec_arp_tables[i], next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2332
2333
  			if (vcc == entry->vcc) {
  				lec_arp_remove(priv, entry);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2334
  				lec_arp_put(entry);
c48192a70   Joe Perches   net/atm/lec.c: ch...
2335
  				if (priv->mcast_vcc == vcc)
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2336
  					priv->mcast_vcc = NULL;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2337
2338
2339
  			}
  		}
  	}
c48192a70   Joe Perches   net/atm/lec.c: ch...
2340
2341
  	hlist_for_each_entry_safe(entry, node, next,
  				  &priv->lec_arp_empty_ones, next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
2342
  		if (entry->vcc == vcc) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2343
2344
  			lec_arp_clear_vccs(entry);
  			del_timer(&entry->timer);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2345
  			hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2346
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2347
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2348
  	}
c48192a70   Joe Perches   net/atm/lec.c: ch...
2349
2350
  	hlist_for_each_entry_safe(entry, node, next,
  				  &priv->lec_no_forward, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2351
2352
2353
  		if (entry->recv_vcc == vcc) {
  			lec_arp_clear_vccs(entry);
  			del_timer(&entry->timer);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2354
  			hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2355
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2356
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2357
  	}
d0732f649   Chas Williams   [ATM]: [lec] conv...
2358
  	hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2359
2360
2361
  		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...
2362
  			hlist_del(&entry->next);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2363
  			lec_arp_put(entry);
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2364
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2365
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2366
2367
2368
2369
2370
2371
2372
  
  	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...
2373
  		      struct atm_vcc *vcc, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2374
  {
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2375
  	unsigned long flags;
d0732f649   Chas Williams   [ATM]: [lec] conv...
2376
2377
  	struct hlist_node *node, *next;
  	struct lec_arp_table *entry, *tmp;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2378
2379
  	struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
  	unsigned char *src;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2380
  #ifdef CONFIG_TR
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2381
  	struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2382

1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2383
2384
2385
  	if (priv->is_trdev)
  		src = tr_hdr->h_source;
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2386
  #endif
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2387
  		src = hdr->h_source;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2388
2389
  
  	spin_lock_irqsave(&priv->lec_arp_lock, flags);
c48192a70   Joe Perches   net/atm/lec.c: ch...
2390
2391
  	hlist_for_each_entry_safe(entry, node, next,
  				  &priv->lec_arp_empty_ones, next) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
2392
2393
2394
2395
2396
2397
  		if (vcc == entry->vcc) {
  			del_timer(&entry->timer);
  			memcpy(entry->mac_addr, src, ETH_ALEN);
  			entry->status = ESI_FORWARD_DIRECT;
  			entry->last_used = jiffies;
  			/* We might have got an entry */
c48192a70   Joe Perches   net/atm/lec.c: ch...
2398
2399
  			tmp = lec_arp_find(priv, src);
  			if (tmp) {
d0732f649   Chas Williams   [ATM]: [lec] conv...
2400
  				lec_arp_remove(priv, tmp);
33a9c2d4b   Chas Williams   [ATM]: [lec] add ...
2401
  				lec_arp_put(tmp);
d0732f649   Chas Williams   [ATM]: [lec] conv...
2402
2403
2404
2405
  			}
  			hlist_del(&entry->next);
  			lec_arp_add(priv, entry);
  			goto out;
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2406
  		}
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2407
  	}
522400623   Stephen Hemminger   [ATM]: Replace DP...
2408
2409
  	pr_debug("LEC_ARP: Arp_check_empties: entry not found!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2410
2411
2412
  out:
  	spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
  }
1fa9961d6   Chas Williams   [ATM]: [lec] inde...
2413

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