Blame view

net/802/tr.c 15.1 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
  #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>
36f0bebd9   Pavel Emelyanov   [TR]: Use ctl pat...
38
  #include <linux/sysctl.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
39
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  #include <net/arp.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
41
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
  
  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...
51

c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
52
  struct rif_cache {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
  	unsigned char addr[TR_ALEN];
  	int iface;
c6b336539   Alexey Dobriyan   [TOKENRING]: be'i...
55
56
  	__be16 rcf;
  	__be16 rseg[8];
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
57
  	struct rif_cache *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
63
64
65
66
67
  	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...
68

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  static struct timer_list rif_timer;
81a21eb4e   Adrian Bunk   [TR] net/802/tr.c...
79
  static int sysctl_tr_rif_timeout = 60*10*HZ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  
  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...
101

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
  static int tr_header(struct sk_buff *skb, struct net_device *dev,
  		     unsigned short type,
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
104
  		     const void *daddr, const void *saddr, unsigned len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
  {
  	struct trh_hdr *trh;
  	int hdr_len;
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
108
109
  	/*
  	 * Add the 802.2 SNAP header if IP as the IPv4/IPv6 code calls
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  	 * 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...
127
  		trh = (struct trh_hdr *)skb_push(skb, hdr_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
132
133
134
135
136
137
138
139
140
  	}
  
  	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...
141
142
  
  	if(daddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
  	{
  		memcpy(trh->daddr,daddr,dev->addr_len);
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
145
  		tr_source_route(skb, trh, dev);
a02cec215   Eric Dumazet   net: return opera...
146
  		return hdr_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
  	}
  
  	return -hdr_len;
  }
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
151

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
  /*
   *	A neighbour discovery of some species (eg arp) has completed. We
   *	can now send the packet.
   */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
156
157
  
  static int tr_rebuild_header(struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
161
162
163
164
165
  {
  	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...
166

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
188
189
  /*
   *	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...
190

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

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

001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
258
  	spin_lock_irqsave(&rif_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
  
  	/*
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
261
  	 *	Broadcasts are single route as stated in RFC 1042
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
  	 */
  	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...
266
  		trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
  			       | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
  		trh->saddr[0]|=TR_RII;
  	}
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
270
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
277
278
279
280
  	{
  		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...
281
  		if(entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
  		{
  #if TR_SR_DEBUG
e174961ca   Johannes Berg   net: convert prin...
284
285
  printk("source routing for %pM
  ", trh->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
  #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...
291
  				trh->rcf^=htons(TR_RCF_DIR_BIT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
  				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...
307
  		else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
311
312
313
  		{
  			/*
  			 *	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...
314
  			trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
318
319
320
321
322
323
324
325
326
  				       | 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...
327
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
  		slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8);
  	olddata = skb->data;
001dd250c   Jay Vosburgh   [TOKENRING]: Use ...
330
  	spin_unlock_irqrestore(&rif_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
335
336
337
338
339
  
  	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...
340

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
  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 ...
344
  	unsigned long flags;
c8b35d2a2   Alexey Dobriyan   [TOKENRING]: net/...
345
  	struct rif_cache *entry;
5ac660ee1   Jochen Friedrich   [TR]: Preserve RI...
346
  	unsigned char saddr0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
353
  	/*
  	 *	Firstly see if the entry exists
  	 */
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
354
  	if(trh->saddr[0] & TR_RII)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
359
  	{
  		trh->saddr[0]&=0x7f;
  		if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2)
  		{
  			rii_p = 1;
9afa0949e   YOSHIFUJI Hideaki   [NET] 802: Fix wh...
360
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
364
  	}
  
  	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...
365
  	if(entry==NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
  	{
  #if TR_SR_DEBUG
e174961ca   Johannes Berg   net: convert prin...
368
369
370
  		printk("adding rif_entry: addr:%pM rcf:%04X
  ",
  		       trh->saddr, ntohs(trh->rcf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
375
376
377
378
  #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/...
379
  		entry=kmalloc(sizeof(struct rif_cache),GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380

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

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  		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...
458

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

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

3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
598
  	dev->header_ops	= &tr_header_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
602
603
604
  
  	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...
605

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
  	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);
  }
36f0bebd9   Pavel Emelyanov   [TR]: Use ctl pat...
627
628
629
  #ifdef CONFIG_SYSCTL
  static struct ctl_table tr_table[] = {
  	{
36f0bebd9   Pavel Emelyanov   [TR]: Use ctl pat...
630
631
632
633
  		.procname	= "rif_timeout",
  		.data		= &sysctl_tr_rif_timeout,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
634
  		.proc_handler	= proc_dointvec
36f0bebd9   Pavel Emelyanov   [TR]: Use ctl pat...
635
  	},
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
636
  	{ },
36f0bebd9   Pavel Emelyanov   [TR]: Use ctl pat...
637
638
639
  };
  
  static __initdata struct ctl_path tr_path[] = {
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
640
641
  	{ .procname = "net", },
  	{ .procname = "token-ring", },
36f0bebd9   Pavel Emelyanov   [TR]: Use ctl pat...
642
643
644
  	{ }
  };
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
649
650
651
  /*
   *	Called during bootup.  We don't actually have to initialise
   *	too much for this.
   */
  
  static int __init rif_init(void)
  {
1b310fca3   Eric Dumazet   [TOKENRING]: rif_...
652
  	rif_timer.expires  = jiffies + sysctl_tr_rif_timeout;
b24b8a247   Pavel Emelyanov   [NET]: Convert in...
653
  	setup_timer(&rif_timer, rif_check_expire, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  	add_timer(&rif_timer);
36f0bebd9   Pavel Emelyanov   [TR]: Use ctl pat...
655
656
657
  #ifdef CONFIG_SYSCTL
  	register_sysctl_paths(tr_path, tr_table);
  #endif
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
658
  	proc_net_fops_create(&init_net, "tr_rif", S_IRUGO, &rif_seq_fops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
  	return 0;
  }
  
  module_init(rif_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
  EXPORT_SYMBOL(tr_type_trans);
  EXPORT_SYMBOL(alloc_trdev);
422247451   Meelis Roos   net: fix tokenrin...
665
666
  
  MODULE_LICENSE("GPL");