Blame view

net/cdp.c 7.58 KB
f739fcd83   Tom Rini   SPDX: Convert a f...
1
  // SPDX-License-Identifier: GPL-2.0
f575ae1f7   Joe Hershberger   net: Move CDP out...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /*
   *	Copied from Linux Monitor (LiMon) - Networking.
   *
   *	Copyright 1994 - 2000 Neil Russell.
   *	(See License)
   *	Copyright 2000 Roland Borde
   *	Copyright 2000 Paolo Scaffardi
   *	Copyright 2000-2002 Wolfgang Denk, wd@denx.de
   */
  
  #include <common.h>
  #include <net.h>
  #if defined(CONFIG_CDP_VERSION)
  #include <timestamp.h>
  #endif
  
  #include "cdp.h"
  
  /* Ethernet bcast address */
0adb5b761   Joe Hershberger   net: cosmetic: Na...
21
  const u8 net_cdp_ethaddr[6] = { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
f575ae1f7   Joe Hershberger   net: Move CDP out...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  
  #define CDP_DEVICE_ID_TLV		0x0001
  #define CDP_ADDRESS_TLV			0x0002
  #define CDP_PORT_ID_TLV			0x0003
  #define CDP_CAPABILITIES_TLV		0x0004
  #define CDP_VERSION_TLV			0x0005
  #define CDP_PLATFORM_TLV		0x0006
  #define CDP_NATIVE_VLAN_TLV		0x000a
  #define CDP_APPLIANCE_VLAN_TLV		0x000e
  #define CDP_TRIGGER_TLV			0x000f
  #define CDP_POWER_CONSUMPTION_TLV	0x0010
  #define CDP_SYSNAME_TLV			0x0014
  #define CDP_SYSOBJECT_TLV		0x0015
  #define CDP_MANAGEMENT_ADDRESS_TLV	0x0016
  
  #define CDP_TIMEOUT			250UL	/* one packet every 250ms */
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
38
39
  static int cdp_seq;
  static int cdp_ok;
f575ae1f7   Joe Hershberger   net: Move CDP out...
40

6aede5b75   Joe Hershberger   net: cosmetic: Cl...
41
42
  ushort cdp_native_vlan;
  ushort cdp_appliance_vlan;
f575ae1f7   Joe Hershberger   net: Move CDP out...
43

6aede5b75   Joe Hershberger   net: cosmetic: Cl...
44
  static const uchar cdp_snap_hdr[8] = {
f575ae1f7   Joe Hershberger   net: Move CDP out...
45
  	0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
46
  static ushort cdp_compute_csum(const uchar *buff, ushort len)
f575ae1f7   Joe Hershberger   net: Move CDP out...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  {
  	ushort csum;
  	int     odd;
  	ulong   result = 0;
  	ushort  leftover;
  	ushort *p;
  
  	if (len > 0) {
  		odd = 1 & (ulong)buff;
  		if (odd) {
  			result = *buff << 8;
  			len--;
  			buff++;
  		}
  		while (len > 1) {
  			p = (ushort *)buff;
  			result += *p++;
  			buff = (uchar *)p;
  			if (result & 0x80000000)
  				result = (result & 0xFFFF) + (result >> 16);
  			len -= 2;
  		}
  		if (len) {
  			leftover = (signed short)(*(const signed char *)buff);
  			/*
  			 * CISCO SUCKS big time! (and blows too):
  			 * CDP uses the IP checksum algorithm with a twist;
  			 * for the last byte it *sign* extends and sums.
  			 */
  			result = (result & 0xffff0000) |
  				 ((result + leftover) & 0x0000ffff);
  		}
  		while (result >> 16)
  			result = (result & 0xFFFF) + (result >> 16);
  
  		if (odd)
  			result = ((result >> 8) & 0xff) |
  				 ((result & 0xff) << 8);
  	}
  
  	/* add up 16-bit and 17-bit words for 17+c bits */
  	result = (result & 0xffff) + (result >> 16);
  	/* add up 16-bit and 2-bit for 16+c bit */
  	result = (result & 0xffff) + (result >> 16);
  	/* add up carry.. */
  	result = (result & 0xffff) + (result >> 16);
  
  	/* negate */
  	csum = ~(ushort)result;
  
  	/* run time endian detection */
  	if (csum != htons(csum))	/* little endian */
  		csum = htons(csum);
  
  	return csum;
  }
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
103
  static int cdp_send_trigger(void)
f575ae1f7   Joe Hershberger   net: Move CDP out...
104
105
106
107
  {
  	uchar *pkt;
  	ushort *s;
  	ushort *cp;
cb487f566   Joe Hershberger   net: cosmetic: Un...
108
  	struct ethernet_hdr *et;
f575ae1f7   Joe Hershberger   net: Move CDP out...
109
110
111
112
113
114
  	int len;
  	ushort chksum;
  #if	defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID)   || \
  	defined(CONFIG_CDP_VERSION)   || defined(CONFIG_CDP_PLATFORM)
  	char buf[32];
  #endif
1203fccee   Joe Hershberger   net: cosmetic: Cl...
115
  	pkt = net_tx_packet;
cb487f566   Joe Hershberger   net: cosmetic: Un...
116
  	et = (struct ethernet_hdr *)pkt;
f575ae1f7   Joe Hershberger   net: Move CDP out...
117
118
119
120
  
  	/* NOTE: trigger sent not on any VLAN */
  
  	/* form ethernet header */
0adb5b761   Joe Hershberger   net: cosmetic: Na...
121
122
  	memcpy(et->et_dest, net_cdp_ethaddr, 6);
  	memcpy(et->et_src, net_ethaddr, 6);
f575ae1f7   Joe Hershberger   net: Move CDP out...
123
124
125
126
  
  	pkt += ETHER_HDR_SIZE;
  
  	/* SNAP header */
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
127
128
  	memcpy((uchar *)pkt, cdp_snap_hdr, sizeof(cdp_snap_hdr));
  	pkt += sizeof(cdp_snap_hdr);
f575ae1f7   Joe Hershberger   net: Move CDP out...
129
130
131
132
133
134
135
136
137
138
139
140
141
  
  	/* CDP header */
  	*pkt++ = 0x02;				/* CDP version 2 */
  	*pkt++ = 180;				/* TTL */
  	s = (ushort *)pkt;
  	cp = s;
  	/* checksum (0 for later calculation) */
  	*s++ = htons(0);
  
  	/* CDP fields */
  #ifdef CONFIG_CDP_DEVICE_ID
  	*s++ = htons(CDP_DEVICE_ID_TLV);
  	*s++ = htons(CONFIG_CDP_DEVICE_ID);
0adb5b761   Joe Hershberger   net: cosmetic: Na...
142
  	sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", net_ethaddr);
f575ae1f7   Joe Hershberger   net: Move CDP out...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  	memcpy((uchar *)s, buf, 16);
  	s += 16 / 2;
  #endif
  
  #ifdef CONFIG_CDP_PORT_ID
  	*s++ = htons(CDP_PORT_ID_TLV);
  	memset(buf, 0, sizeof(buf));
  	sprintf(buf, CONFIG_CDP_PORT_ID, eth_get_dev_index());
  	len = strlen(buf);
  	if (len & 1)	/* make it even */
  		len++;
  	*s++ = htons(len + 4);
  	memcpy((uchar *)s, buf, len);
  	s += len / 2;
  #endif
  
  #ifdef CONFIG_CDP_CAPABILITIES
  	*s++ = htons(CDP_CAPABILITIES_TLV);
  	*s++ = htons(8);
  	*(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES);
  	s += 2;
  #endif
  
  #ifdef CONFIG_CDP_VERSION
  	*s++ = htons(CDP_VERSION_TLV);
  	memset(buf, 0, sizeof(buf));
  	strcpy(buf, CONFIG_CDP_VERSION);
  	len = strlen(buf);
  	if (len & 1)	/* make it even */
  		len++;
  	*s++ = htons(len + 4);
  	memcpy((uchar *)s, buf, len);
  	s += len / 2;
  #endif
  
  #ifdef CONFIG_CDP_PLATFORM
  	*s++ = htons(CDP_PLATFORM_TLV);
  	memset(buf, 0, sizeof(buf));
  	strcpy(buf, CONFIG_CDP_PLATFORM);
  	len = strlen(buf);
  	if (len & 1)	/* make it even */
  		len++;
  	*s++ = htons(len + 4);
  	memcpy((uchar *)s, buf, len);
  	s += len / 2;
  #endif
  
  #ifdef CONFIG_CDP_TRIGGER
  	*s++ = htons(CDP_TRIGGER_TLV);
  	*s++ = htons(8);
  	*(ulong *)s = htonl(CONFIG_CDP_TRIGGER);
  	s += 2;
  #endif
  
  #ifdef CONFIG_CDP_POWER_CONSUMPTION
  	*s++ = htons(CDP_POWER_CONSUMPTION_TLV);
  	*s++ = htons(6);
  	*s++ = htons(CONFIG_CDP_POWER_CONSUMPTION);
  #endif
  
  	/* length of ethernet packet */
1203fccee   Joe Hershberger   net: cosmetic: Cl...
204
  	len = (uchar *)s - ((uchar *)net_tx_packet + ETHER_HDR_SIZE);
f575ae1f7   Joe Hershberger   net: Move CDP out...
205
  	et->et_protlen = htons(len);
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
206
207
  	len = ETHER_HDR_SIZE + sizeof(cdp_snap_hdr);
  	chksum = cdp_compute_csum((uchar *)net_tx_packet + len,
1203fccee   Joe Hershberger   net: cosmetic: Cl...
208
  				  (uchar *)s - (net_tx_packet + len));
f575ae1f7   Joe Hershberger   net: Move CDP out...
209
210
211
  	if (chksum == 0)
  		chksum = 0xFFFF;
  	*cp = htons(chksum);
1203fccee   Joe Hershberger   net: cosmetic: Cl...
212
  	net_send_packet(net_tx_packet, (uchar *)s - net_tx_packet);
f575ae1f7   Joe Hershberger   net: Move CDP out...
213
214
  	return 0;
  }
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
215
  static void cdp_timeout_handler(void)
f575ae1f7   Joe Hershberger   net: Move CDP out...
216
  {
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
217
  	cdp_seq++;
f575ae1f7   Joe Hershberger   net: Move CDP out...
218

6aede5b75   Joe Hershberger   net: cosmetic: Cl...
219
  	if (cdp_seq < 3) {
bc0571fc1   Joe Hershberger   net: cosmetic: Fi...
220
  		net_set_timeout_handler(CDP_TIMEOUT, cdp_timeout_handler);
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
221
  		cdp_send_trigger();
f575ae1f7   Joe Hershberger   net: Move CDP out...
222
223
224
225
  		return;
  	}
  
  	/* if not OK try again */
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
226
  	if (!cdp_ok)
bc0571fc1   Joe Hershberger   net: cosmetic: Fi...
227
  		net_start_again();
f575ae1f7   Joe Hershberger   net: Move CDP out...
228
  	else
22f6e99d5   Joe Hershberger   net: Refactor to ...
229
  		net_set_state(NETLOOP_SUCCESS);
f575ae1f7   Joe Hershberger   net: Move CDP out...
230
  }
0b4c5ff4a   Joe Hershberger   net: cosmetic: Re...
231
  void cdp_receive(const uchar *pkt, unsigned len)
f575ae1f7   Joe Hershberger   net: Move CDP out...
232
233
234
235
236
237
238
  {
  	const uchar *t;
  	const ushort *ss;
  	ushort type, tlen;
  	ushort vlan, nvlan;
  
  	/* minimum size? */
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
239
  	if (len < sizeof(cdp_snap_hdr) + 4)
f575ae1f7   Joe Hershberger   net: Move CDP out...
240
241
242
  		goto pkt_short;
  
  	/* check for valid CDP SNAP header */
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
243
  	if (memcmp(pkt, cdp_snap_hdr, sizeof(cdp_snap_hdr)) != 0)
f575ae1f7   Joe Hershberger   net: Move CDP out...
244
  		return;
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
245
246
  	pkt += sizeof(cdp_snap_hdr);
  	len -= sizeof(cdp_snap_hdr);
f575ae1f7   Joe Hershberger   net: Move CDP out...
247
248
249
250
251
252
253
254
255
256
257
258
259
  
  	/* Version of CDP protocol must be >= 2 and TTL != 0 */
  	if (pkt[0] < 0x02 || pkt[1] == 0)
  		return;
  
  	/*
  	 * if version is greater than 0x02 maybe we'll have a problem;
  	 * output a warning
  	 */
  	if (pkt[0] != 0x02)
  		printf("**WARNING: CDP packet received with a protocol version "
  				"%d > 2
  ", pkt[0] & 0xff);
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
260
  	if (cdp_compute_csum(pkt, len) != 0)
f575ae1f7   Joe Hershberger   net: Move CDP out...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  		return;
  
  	pkt += 4;
  	len -= 4;
  
  	vlan = htons(-1);
  	nvlan = htons(-1);
  	while (len > 0) {
  		if (len < 4)
  			goto pkt_short;
  
  		ss = (const ushort *)pkt;
  		type = ntohs(ss[0]);
  		tlen = ntohs(ss[1]);
  		if (tlen > len)
  			goto pkt_short;
  
  		pkt += tlen;
  		len -= tlen;
  
  		ss += 2;	/* point ss to the data of the TLV */
  		tlen -= 4;
  
  		switch (type) {
  		case CDP_DEVICE_ID_TLV:
  			break;
  		case CDP_ADDRESS_TLV:
  			break;
  		case CDP_PORT_ID_TLV:
  			break;
  		case CDP_CAPABILITIES_TLV:
  			break;
  		case CDP_VERSION_TLV:
  			break;
  		case CDP_PLATFORM_TLV:
  			break;
  		case CDP_NATIVE_VLAN_TLV:
  			nvlan = *ss;
  			break;
  		case CDP_APPLIANCE_VLAN_TLV:
  			t = (const uchar *)ss;
  			while (tlen > 0) {
  				if (tlen < 3)
  					goto pkt_short;
  
  				ss = (const ushort *)(t + 1);
  
  #ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
  				if (t[0] == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
  					vlan = *ss;
  #else
  				/* XXX will this work; dunno */
  				vlan = ntohs(*ss);
  #endif
  				t += 3; tlen -= 3;
  			}
  			break;
  		case CDP_TRIGGER_TLV:
  			break;
  		case CDP_POWER_CONSUMPTION_TLV:
  			break;
  		case CDP_SYSNAME_TLV:
  			break;
  		case CDP_SYSOBJECT_TLV:
  			break;
  		case CDP_MANAGEMENT_ADDRESS_TLV:
  			break;
  		}
  	}
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
330
331
  	cdp_appliance_vlan = vlan;
  	cdp_native_vlan = nvlan;
f575ae1f7   Joe Hershberger   net: Move CDP out...
332

6aede5b75   Joe Hershberger   net: cosmetic: Cl...
333
  	cdp_ok = 1;
f575ae1f7   Joe Hershberger   net: Move CDP out...
334
  	return;
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
335
  pkt_short:
f575ae1f7   Joe Hershberger   net: Move CDP out...
336
337
338
339
  	printf("** CDP packet is too short
  ");
  	return;
  }
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
340
  void cdp_start(void)
f575ae1f7   Joe Hershberger   net: Move CDP out...
341
342
343
  {
  	printf("Using %s device
  ", eth_get_name());
6aede5b75   Joe Hershberger   net: cosmetic: Cl...
344
345
  	cdp_seq = 0;
  	cdp_ok = 0;
f575ae1f7   Joe Hershberger   net: Move CDP out...
346

6aede5b75   Joe Hershberger   net: cosmetic: Cl...
347
348
  	cdp_native_vlan = htons(-1);
  	cdp_appliance_vlan = htons(-1);
f575ae1f7   Joe Hershberger   net: Move CDP out...
349

bc0571fc1   Joe Hershberger   net: cosmetic: Fi...
350
  	net_set_timeout_handler(CDP_TIMEOUT, cdp_timeout_handler);
f575ae1f7   Joe Hershberger   net: Move CDP out...
351

6aede5b75   Joe Hershberger   net: cosmetic: Cl...
352
  	cdp_send_trigger();
f575ae1f7   Joe Hershberger   net: Move CDP out...
353
  }