Blame view

net/802/tr.c 14.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   * NET3:	Token ring device handling subroutines
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
3
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   *
   * Fixes:       3 Feb 97 Paul Norton <pnorton@cts.com> Minor routing fixes.
   *              Added rif table to /proc/net/tr_rif and rif timeout to
   *              /proc/sys/net/token-ring/rif_timeout.
   *              22 Jun 98 Paul Norton <p.norton@computer.org> Rearranged
   *              tr_header and tr_type_trans to handle passing IPX SNAP and
   *              802.2 through the correct layers. Eliminated tr_reformat.
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
15
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
   */
  
  #include <asm/uaccess.h>
  #include <asm/system.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/jiffies.h>
  #include <linux/string.h>
  #include <linux/mm.h>
  #include <linux/socket.h>
  #include <linux/in.h>
  #include <linux/inet.h>
  #include <linux/netdevice.h>
  #include <linux/trdevice.h>
  #include <linux/skbuff.h>
  #include <linux/errno.h>
  #include <linux/timer.h>
  #include <linux/net.h>
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/init.h>
  #include <net/arp.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
39
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
47
48
  
  static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev);
  static void rif_check_expire(unsigned long dummy);
  
  #define TR_SR_DEBUG 0
  
  /*
   *	Each RIF entry we learn is kept this way
   */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
49

c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
50
  struct rif_cache {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
  	unsigned char addr[TR_ALEN];
  	int iface;
c6b336539   Alexey Dobriyan   [TOKENRING]: be'i...
53
54
  	__be16 rcf;
  	__be16 rseg[8];
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
55
  	struct rif_cache *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
61
62
63
64
65
  	unsigned long last_used;
  	unsigned char local_ring;
  };
  
  #define RIF_TABLE_SIZE 32
  
  /*
   *	We hash the RIF cache 32 ways. We do after all have to look it
   *	up a lot.
   */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
66

c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
67
  static struct rif_cache *rif_table[RIF_TABLE_SIZE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
  
  static DEFINE_SPINLOCK(rif_lock);
  
  
  /*
   *	Garbage disposal timer.
   */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
75

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  static struct timer_list rif_timer;
  
  int sysctl_tr_rif_timeout = 60*10*HZ;
  
  static inline unsigned long rif_hash(const unsigned char *addr)
  {
  	unsigned long x;
  
  	x = addr[0];
  	x = (x << 2) ^ addr[1];
  	x = (x << 2) ^ addr[2];
  	x = (x << 2) ^ addr[3];
  	x = (x << 2) ^ addr[4];
  	x = (x << 2) ^ addr[5];
  
  	x ^= x >> 8;
  
  	return x & (RIF_TABLE_SIZE - 1);
  }
  
  /*
   *	Put the headers on a token ring packet. Token ring source routing
   *	makes this a little more exciting than on ethernet.
   */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
100

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
  static int tr_header(struct sk_buff *skb, struct net_device *dev,
  		     unsigned short type,
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
103
  		     const void *daddr, const void *saddr, unsigned len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
  {
  	struct trh_hdr *trh;
  	int hdr_len;
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
107
108
  	/*
  	 * Add the 802.2 SNAP header if IP as the IPv4/IPv6 code calls
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  	 * dev->hard_header directly.
  	 */
  	if (type == ETH_P_IP || type == ETH_P_IPV6 || type == ETH_P_ARP)
  	{
  		struct trllc *trllc;
  
  		hdr_len = sizeof(struct trh_hdr) + sizeof(struct trllc);
  		trh = (struct trh_hdr *)skb_push(skb, hdr_len);
  		trllc = (struct trllc *)(trh+1);
  		trllc->dsap = trllc->ssap = EXTENDED_SAP;
  		trllc->llc = UI_CMD;
  		trllc->protid[0] = trllc->protid[1] = trllc->protid[2] = 0x00;
  		trllc->ethertype = htons(type);
  	}
  	else
  	{
  		hdr_len = sizeof(struct trh_hdr);
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
126
  		trh = (struct trh_hdr *)skb_push(skb, hdr_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
134
135
136
137
138
139
  	}
  
  	trh->ac=AC;
  	trh->fc=LLC_FRAME;
  
  	if(saddr)
  		memcpy(trh->saddr,saddr,dev->addr_len);
  	else
  		memcpy(trh->saddr,dev->dev_addr,dev->addr_len);
  
  	/*
  	 *	Build the destination and then source route the frame
  	 */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
140
141
  
  	if(daddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
  	{
  		memcpy(trh->daddr,daddr,dev->addr_len);
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
144
  		tr_source_route(skb, trh, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
  		return(hdr_len);
  	}
  
  	return -hdr_len;
  }
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
150

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
  /*
   *	A neighbour discovery of some species (eg arp) has completed. We
   *	can now send the packet.
   */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
155
156
  
  static int tr_rebuild_header(struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
162
163
164
  {
  	struct trh_hdr *trh=(struct trh_hdr *)skb->data;
  	struct trllc *trllc=(struct trllc *)(skb->data+sizeof(struct trh_hdr));
  	struct net_device *dev = skb->dev;
  
  	/*
  	 *	FIXME: We don't yet support IPv6 over token rings
  	 */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
165

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  	if(trllc->ethertype != htons(ETH_P_IP)) {
0ac0760a5   Al Viro   [TR]: endiannness...
167
168
  		printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?
  ", ntohs(trllc->ethertype));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
  		return 0;
  	}
  
  #ifdef CONFIG_INET
  	if(arp_find(trh->daddr, skb)) {
  			return 1;
  	}
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
176
177
178
179
  	else
  #endif
  	{
  		tr_source_route(skb,trh,dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
  		return 0;
  	}
  }
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
183

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
  /*
   *	Some of this is a bit hackish. We intercept RIF information
   *	used for source routing. We also grab IP directly and don't feed
   *	it via SNAP.
   */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
189

0ac0760a5   Al Viro   [TR]: endiannness...
190
  __be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  {
c1a4b86e3   Arnaldo Carvalho de Melo   [TR]: Use tr_hdr(...
192
  	struct trh_hdr *trh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  	struct trllc *trllc;
  	unsigned riflen=0;
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
195

c8fb7948d   Arnaldo Carvalho de Melo   [TR]: Make tr_typ...
196
  	skb->dev = dev;
459a98ed8   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
197
  	skb_reset_mac_header(skb);
c1a4b86e3   Arnaldo Carvalho de Melo   [TR]: Use tr_hdr(...
198
  	trh = tr_hdr(skb);
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
199
200
  
  	if(trh->saddr[0] & TR_RII)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
204
205
  		riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
  
  	trllc = (struct trllc *)(skb->data+sizeof(struct trh_hdr)-TR_MAXRIFLEN+riflen);
  
  	skb_pull(skb,sizeof(struct trh_hdr)-TR_MAXRIFLEN+riflen);
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
206
  	if(*trh->daddr & 0x80)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  	{
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
208
  		if(!memcmp(trh->daddr,dev->broadcast,TR_ALEN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
214
215
216
  			skb->pkt_type=PACKET_BROADCAST;
  		else
  			skb->pkt_type=PACKET_MULTICAST;
  	}
  	else if ( (trh->daddr[0] & 0x01) && (trh->daddr[1] & 0x00) && (trh->daddr[2] & 0x5E))
  	{
  		skb->pkt_type=PACKET_MULTICAST;
  	}
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
217
  	else if(dev->flags & IFF_PROMISC)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
224
  	{
  		if(memcmp(trh->daddr, dev->dev_addr, TR_ALEN))
  			skb->pkt_type=PACKET_OTHERHOST;
  	}
  
  	if ((skb->pkt_type != PACKET_BROADCAST) &&
  	    (skb->pkt_type != PACKET_MULTICAST))
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
225
  		tr_add_rif_info(trh,dev) ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
  
  	/*
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
228
  	 * Strip the SNAP header from ARP packets since we don't
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
  	 * pass them through to the 802.2/SNAP layers.
  	 */
  
  	if (trllc->dsap == EXTENDED_SAP &&
0ac0760a5   Al Viro   [TR]: endiannness...
233
234
235
  	    (trllc->ethertype == htons(ETH_P_IP) ||
  	     trllc->ethertype == htons(ETH_P_IPV6) ||
  	     trllc->ethertype == htons(ETH_P_ARP)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
239
  	{
  		skb_pull(skb, sizeof(struct trllc));
  		return trllc->ethertype;
  	}
0ac0760a5   Al Viro   [TR]: endiannness...
240
  	return htons(ETH_P_TR_802_2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
  }
  
  /*
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
244
   *	We try to do source routing...
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
   */
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
246
247
  void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,
  		     struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
  {
  	int slack;
  	unsigned int hash;
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
251
  	struct rif_cache *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  	unsigned char *olddata;
001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
253
  	unsigned long flags;
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
254
  	static const unsigned char mcast_func_addr[]
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  		= {0xC0,0x00,0x00,0x04,0x00,0x00};
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
256

001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
257
  	spin_lock_irqsave(&rif_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
  
  	/*
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
260
  	 *	Broadcasts are single route as stated in RFC 1042
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
  	 */
  	if( (!memcmp(&(trh->daddr[0]),&(dev->broadcast[0]),TR_ALEN)) ||
  	    (!memcmp(&(trh->daddr[0]),&(mcast_func_addr[0]), TR_ALEN))  )
  	{
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
265
  		trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
  			       | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
  		trh->saddr[0]|=TR_RII;
  	}
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
269
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
274
275
276
277
278
279
  	{
  		hash = rif_hash(trh->daddr);
  		/*
  		 *	Walk the hash table and look for an entry
  		 */
  		for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->daddr[0]),TR_ALEN);entry=entry->next);
  
  		/*
  		 *	If we found an entry we can route the frame.
  		 */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
280
  		if(entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
  		{
  #if TR_SR_DEBUG
0795af572   Joe Perches   [NET]: Introduce ...
283
284
285
286
287
  {
  DECLARE_MAC_BUF(mac);
  printk("source routing for %s
  ",print_mac(mac, trh->daddr));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
  #endif
  			if(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8)
  			{
  				trh->rcf=entry->rcf;
  				memcpy(&trh->rseg[0],&entry->rseg[0],8*sizeof(unsigned short));
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
293
  				trh->rcf^=htons(TR_RCF_DIR_BIT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
  				trh->rcf&=htons(0x1fff);	/* Issam Chehab <ichehab@madge1.demon.co.uk> */
  
  				trh->saddr[0]|=TR_RII;
  #if TR_SR_DEBUG
  				printk("entry found with rcf %04x
  ", entry->rcf);
  			}
  			else
  			{
  				printk("entry found but without rcf length, local=%02x
  ", entry->local_ring);
  #endif
  			}
  			entry->last_used=jiffies;
  		}
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
309
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
314
315
  		{
  			/*
  			 *	Without the information we simply have to shout
  			 *	on the wire. The replies should rapidly clean this
  			 *	situation up.
  			 */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
316
  			trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
320
321
322
323
324
325
326
327
328
  				       | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
  			trh->saddr[0]|=TR_RII;
  #if TR_SR_DEBUG
  			printk("no entry in rif table found - broadcasting frame
  ");
  #endif
  		}
  	}
  
  	/* Compress the RIF here so we don't have to do it in the driver(s) */
  	if (!(trh->saddr[0] & 0x80))
  		slack = 18;
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
329
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
  		slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8);
  	olddata = skb->data;
001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
332
  	spin_unlock_irqrestore(&rif_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
337
338
339
340
341
  
  	skb_pull(skb, slack);
  	memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack);
  }
  
  /*
   *	We have learned some new RIF information for our source
   *	routing.
   */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
342

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
  static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev)
  {
  	unsigned int hash, rii_p = 0;
001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
346
  	unsigned long flags;
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
347
  	struct rif_cache *entry;
5ac660ee1   Jochen Friedrich   [TR]: Preserve RI...
348
  	unsigned char saddr0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349

001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
350
  	spin_lock_irqsave(&rif_lock, flags);
5ac660ee1   Jochen Friedrich   [TR]: Preserve RI...
351
  	saddr0 = trh->saddr[0];
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
352

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
  	/*
  	 *	Firstly see if the entry exists
  	 */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
356
  	if(trh->saddr[0] & TR_RII)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
361
  	{
  		trh->saddr[0]&=0x7f;
  		if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2)
  		{
  			rii_p = 1;
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
362
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
  	}
  
  	hash = rif_hash(trh->saddr);
  	for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);entry=entry->next);
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
367
  	if(entry==NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
  	{
  #if TR_SR_DEBUG
0795af572   Joe Perches   [NET]: Introduce ...
370
371
372
373
  		DECLARE_MAC_BUF(mac);
  		printk("adding rif_entry: addr:%s rcf:%04X
  ",
  		       print_mac(mac, trh->saddr), ntohs(trh->rcf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
378
379
380
381
  #endif
  		/*
  		 *	Allocate our new entry. A failure to allocate loses
  		 *	use the information. This is harmless.
  		 *
  		 *	FIXME: We ought to keep some kind of cache size
  		 *	limiting and adjust the timers to suit.
  		 */
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
382
  		entry=kmalloc(sizeof(struct rif_cache),GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383

9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
384
  		if(!entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
  		{
  			printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !
  ");
001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
388
  			spin_unlock_irqrestore(&rif_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
392
393
394
395
396
397
398
399
400
401
402
  			return;
  		}
  
  		memcpy(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);
  		entry->iface = dev->ifindex;
  		entry->next=rif_table[hash];
  		entry->last_used=jiffies;
  		rif_table[hash]=entry;
  
  		if (rii_p)
  		{
  			entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
  			memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
  			entry->local_ring = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
406
407
  		}
  		else
  		{
  			entry->local_ring = 1;
  		}
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
408
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
  	else	/* Y. Tahara added */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
410
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
  		/*
  		 *	Update existing entries
  		 */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
414
  		if (!entry->local_ring)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
  		    if (entry->rcf != (trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK)) &&
  			 !(trh->rcf & htons(TR_RCF_BROADCAST_MASK)))
  		    {
  #if TR_SR_DEBUG
0795af572   Joe Perches   [NET]: Introduce ...
419
420
421
422
423
424
  {
  DECLARE_MAC_BUF(mac);
  printk("updating rif_entry: addr:%s rcf:%04X
  ",
  		print_mac(mac, trh->saddr), ntohs(trh->rcf));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
  #endif
  			    entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
427
428
429
  			    memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
  		    }
  		entry->last_used=jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  	}
5ac660ee1   Jochen Friedrich   [TR]: Preserve RI...
431
  	trh->saddr[0]=saddr0; /* put the routing indicator back for tcpdump */
001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
432
  	spin_unlock_irqrestore(&rif_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
437
  }
  
  /*
   *	Scan the cache with a timer and see what we need to throw out.
   */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
438
  static void rif_check_expire(unsigned long dummy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  {
  	int i;
001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
441
  	unsigned long flags, next_interval = jiffies + sysctl_tr_rif_timeout/2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442

001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
443
  	spin_lock_irqsave(&rif_lock, flags);
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
444

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  	for(i =0; i < RIF_TABLE_SIZE; i++) {
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
446
  		struct rif_cache *entry, **pentry;
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
447

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
  		pentry = rif_table+i;
  		while((entry=*pentry) != NULL) {
  			unsigned long expires
  				= entry->last_used + sysctl_tr_rif_timeout;
  
  			if (time_before_eq(expires, jiffies)) {
  				*pentry = entry->next;
  				kfree(entry);
  			} else {
  				pentry = &entry->next;
  
  				if (time_before(expires, next_interval))
  					next_interval = expires;
  			}
  		}
  	}
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
464

001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
465
  	spin_unlock_irqrestore(&rif_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
468
469
470
471
472
473
474
  
  	mod_timer(&rif_timer, next_interval);
  
  }
  
  /*
   *	Generate the /proc/net information for the token ring RIF
   *	routing.
   */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
475

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  #ifdef CONFIG_PROC_FS
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
477
  static struct rif_cache *rif_get_idx(loff_t pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
  {
  	int i;
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
480
  	struct rif_cache *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  	loff_t off = 0;
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
482
  	for(i = 0; i < RIF_TABLE_SIZE; i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
486
487
488
489
490
491
492
493
  		for(entry = rif_table[i]; entry; entry = entry->next) {
  			if (off == pos)
  				return entry;
  			++off;
  		}
  
  	return NULL;
  }
  
  static void *rif_seq_start(struct seq_file *seq, loff_t *pos)
  {
001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
494
  	spin_lock_irq(&rif_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
498
499
500
501
  
  	return *pos ? rif_get_idx(*pos - 1) : SEQ_START_TOKEN;
  }
  
  static void *rif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	int i;
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
502
  	struct rif_cache *ent = v;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
505
506
507
508
509
  
  	++*pos;
  
  	if (v == SEQ_START_TOKEN) {
  		i = -1;
  		goto scan;
  	}
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
510
  	if (ent->next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
514
515
516
517
518
519
520
521
522
523
  		return ent->next;
  
  	i = rif_hash(ent->addr);
   scan:
  	while (++i < RIF_TABLE_SIZE) {
  		if ((ent = rif_table[i]) != NULL)
  			return ent;
  	}
  	return NULL;
  }
  
  static void rif_seq_stop(struct seq_file *seq, void *v)
  {
001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
524
  	spin_unlock_irq(&rif_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
528
529
  }
  
  static int rif_seq_show(struct seq_file *seq, void *v)
  {
  	int j, rcf_len, segment, brdgnmb;
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
530
  	struct rif_cache *entry = v;
0795af572   Joe Perches   [NET]: Introduce ...
531
  	DECLARE_MAC_BUF(mac);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
534
535
536
537
  
  	if (v == SEQ_START_TOKEN)
  		seq_puts(seq,
  		     "if     TR address       TTL   rcf   routing segments
  ");
  	else {
881d966b4   Eric W. Biederman   [NET]: Make the d...
538
  		struct net_device *dev = dev_get_by_index(&init_net, entry->iface);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
  		long ttl = (long) (entry->last_used + sysctl_tr_rif_timeout)
  				- (long) jiffies;
0795af572   Joe Perches   [NET]: Introduce ...
541
  		seq_printf(seq, "%s %s %7li ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  			   dev?dev->name:"?",
0795af572   Joe Perches   [NET]: Introduce ...
543
  			   print_mac(mac, entry->addr),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
  			   ttl/HZ);
  
  			if (entry->local_ring)
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
547
548
  				seq_puts(seq, "local
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
551
  			else {
  
  				seq_printf(seq, "%04X", ntohs(entry->rcf));
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
552
  				rcf_len = ((ntohs(entry->rcf) & TR_RCF_LEN_MASK)>>8)-2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  				if (rcf_len)
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
554
  					rcf_len >>= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
558
  				for(j = 1; j < rcf_len; j++) {
  					if(j==1) {
  						segment=ntohs(entry->rseg[j-1])>>4;
  						seq_printf(seq,"  %03X",segment);
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
559
  					}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
562
563
564
565
566
  					segment=ntohs(entry->rseg[j])>>4;
  					brdgnmb=ntohs(entry->rseg[j-1])&0x00f;
  					seq_printf(seq,"-%01X-%03X",brdgnmb,segment);
  				}
  				seq_putc(seq, '
  ');
  			}
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
567
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  	return 0;
  }
56b3d975b   Philippe De Muyter   [NET]: Make all i...
570
  static const struct seq_operations rif_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
576
577
578
579
580
  	.start = rif_seq_start,
  	.next  = rif_seq_next,
  	.stop  = rif_seq_stop,
  	.show  = rif_seq_show,
  };
  
  static int rif_seq_open(struct inode *inode, struct file *file)
  {
  	return seq_open(file, &rif_seq_ops);
  }
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
581
  static const struct file_operations rif_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
586
587
588
589
  	.owner	 = THIS_MODULE,
  	.open    = rif_seq_open,
  	.read    = seq_read,
  	.llseek  = seq_lseek,
  	.release = seq_release,
  };
  
  #endif
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
590
591
592
593
  static const struct header_ops tr_header_ops = {
  	.create = tr_header,
  	.rebuild= tr_rebuild_header,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
597
598
  static void tr_setup(struct net_device *dev)
  {
  	/*
  	 *	Configure and register
  	 */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
599

3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
600
  	dev->header_ops	= &tr_header_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
603
604
605
606
  
  	dev->type		= ARPHRD_IEEE802_TR;
  	dev->hard_header_len	= TR_HLEN;
  	dev->mtu		= 2000;
  	dev->addr_len		= TR_ALEN;
  	dev->tx_queue_len	= 100;	/* Long queues on tr */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
607

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
  	memset(dev->broadcast,0xFF, TR_ALEN);
  
  	/* New-style flags. */
  	dev->flags		= IFF_BROADCAST | IFF_MULTICAST ;
  }
  
  /**
   * alloc_trdev - Register token ring device
   * @sizeof_priv: Size of additional driver-private structure to be allocated
   *	for this token ring device
   *
   * Fill in the fields of the device structure with token ring-generic values.
   *
   * Constructs a new net device, complete with a private data area of
   * size @sizeof_priv.  A 32-byte (not bit) alignment is enforced for
   * this private data area.
   */
  struct net_device *alloc_trdev(int sizeof_priv)
  {
  	return alloc_netdev(sizeof_priv, "tr%d", tr_setup);
  }
  
  /*
   *	Called during bootup.  We don't actually have to initialise
   *	too much for this.
   */
  
  static int __init rif_init(void)
  {
  	init_timer(&rif_timer);
  	rif_timer.expires  = sysctl_tr_rif_timeout;
  	rif_timer.data     = 0L;
  	rif_timer.function = rif_check_expire;
  	add_timer(&rif_timer);
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
642
  	proc_net_fops_create(&init_net, "tr_rif", S_IRUGO, &rif_seq_fops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
646
  	return 0;
  }
  
  module_init(rif_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
  EXPORT_SYMBOL(tr_type_trans);
  EXPORT_SYMBOL(alloc_trdev);