1 // SPDX-License-Identifier: GPL-2.0
3 * Copied from Linux Monitor (LiMon) - Networking.
5 * Copyright 1994 - 2000 Neil Russell.
7 * Copyright 2000 Roland Borde
8 * Copyright 2000 Paolo Scaffardi
9 * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
16 /* Ethernet bcast address */
17 const u8 net_cdp_ethaddr[6] = { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
19 #define CDP_DEVICE_ID_TLV 0x0001
20 #define CDP_ADDRESS_TLV 0x0002
21 #define CDP_PORT_ID_TLV 0x0003
22 #define CDP_CAPABILITIES_TLV 0x0004
23 #define CDP_VERSION_TLV 0x0005
24 #define CDP_PLATFORM_TLV 0x0006
25 #define CDP_NATIVE_VLAN_TLV 0x000a
26 #define CDP_APPLIANCE_VLAN_TLV 0x000e
27 #define CDP_TRIGGER_TLV 0x000f
28 #define CDP_POWER_CONSUMPTION_TLV 0x0010
29 #define CDP_SYSNAME_TLV 0x0014
30 #define CDP_SYSOBJECT_TLV 0x0015
31 #define CDP_MANAGEMENT_ADDRESS_TLV 0x0016
33 #define CDP_TIMEOUT 250UL /* one packet every 250ms */
38 ushort cdp_native_vlan;
39 ushort cdp_appliance_vlan;
41 static const uchar cdp_snap_hdr[8] = {
42 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
44 static ushort cdp_compute_csum(const uchar *buff, ushort len)
53 odd = 1 & (ulong)buff;
63 if (result & 0x80000000)
64 result = (result & 0xFFFF) + (result >> 16);
68 leftover = (signed short)(*(const signed char *)buff);
70 * CISCO SUCKS big time! (and blows too):
71 * CDP uses the IP checksum algorithm with a twist;
72 * for the last byte it *sign* extends and sums.
74 result = (result & 0xffff0000) |
75 ((result + leftover) & 0x0000ffff);
78 result = (result & 0xFFFF) + (result >> 16);
81 result = ((result >> 8) & 0xff) |
82 ((result & 0xff) << 8);
85 /* add up 16-bit and 17-bit words for 17+c bits */
86 result = (result & 0xffff) + (result >> 16);
87 /* add up 16-bit and 2-bit for 16+c bit */
88 result = (result & 0xffff) + (result >> 16);
90 result = (result & 0xffff) + (result >> 16);
93 csum = ~(ushort)result;
95 /* run time endian detection */
96 if (csum != htons(csum)) /* little endian */
102 static int cdp_send_trigger(void)
107 struct ethernet_hdr *et;
110 #if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID) || \
111 defined(CONFIG_CDP_VERSION) || defined(CONFIG_CDP_PLATFORM)
116 et = (struct ethernet_hdr *)pkt;
118 /* NOTE: trigger sent not on any VLAN */
120 /* form ethernet header */
121 memcpy(et->et_dest, net_cdp_ethaddr, 6);
122 memcpy(et->et_src, net_ethaddr, 6);
124 pkt += ETHER_HDR_SIZE;
127 memcpy((uchar *)pkt, cdp_snap_hdr, sizeof(cdp_snap_hdr));
128 pkt += sizeof(cdp_snap_hdr);
131 *pkt++ = 0x02; /* CDP version 2 */
132 *pkt++ = 180; /* TTL */
135 /* checksum (0 for later calculation) */
139 #ifdef CONFIG_CDP_DEVICE_ID
140 *s++ = htons(CDP_DEVICE_ID_TLV);
141 *s++ = htons(CONFIG_CDP_DEVICE_ID);
142 sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", net_ethaddr);
143 memcpy((uchar *)s, buf, 16);
147 #ifdef CONFIG_CDP_PORT_ID
148 *s++ = htons(CDP_PORT_ID_TLV);
149 memset(buf, 0, sizeof(buf));
150 sprintf(buf, CONFIG_CDP_PORT_ID, eth_get_dev_index());
152 if (len & 1) /* make it even */
154 *s++ = htons(len + 4);
155 memcpy((uchar *)s, buf, len);
159 #ifdef CONFIG_CDP_CAPABILITIES
160 *s++ = htons(CDP_CAPABILITIES_TLV);
162 *(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES);
166 #ifdef CONFIG_CDP_VERSION
167 *s++ = htons(CDP_VERSION_TLV);
168 memset(buf, 0, sizeof(buf));
169 strcpy(buf, CONFIG_CDP_VERSION);
171 if (len & 1) /* make it even */
173 *s++ = htons(len + 4);
174 memcpy((uchar *)s, buf, len);
178 #ifdef CONFIG_CDP_PLATFORM
179 *s++ = htons(CDP_PLATFORM_TLV);
180 memset(buf, 0, sizeof(buf));
181 strcpy(buf, CONFIG_CDP_PLATFORM);
183 if (len & 1) /* make it even */
185 *s++ = htons(len + 4);
186 memcpy((uchar *)s, buf, len);
190 #ifdef CONFIG_CDP_TRIGGER
191 *s++ = htons(CDP_TRIGGER_TLV);
193 *(ulong *)s = htonl(CONFIG_CDP_TRIGGER);
197 #ifdef CONFIG_CDP_POWER_CONSUMPTION
198 *s++ = htons(CDP_POWER_CONSUMPTION_TLV);
200 *s++ = htons(CONFIG_CDP_POWER_CONSUMPTION);
203 /* length of ethernet packet */
204 len = (uchar *)s - ((uchar *)net_tx_packet + ETHER_HDR_SIZE);
205 et->et_protlen = htons(len);
207 len = ETHER_HDR_SIZE + sizeof(cdp_snap_hdr);
208 chksum = cdp_compute_csum((uchar *)net_tx_packet + len,
209 (uchar *)s - (net_tx_packet + len));
214 net_send_packet(net_tx_packet, (uchar *)s - net_tx_packet);
218 static void cdp_timeout_handler(void)
223 net_set_timeout_handler(CDP_TIMEOUT, cdp_timeout_handler);
228 /* if not OK try again */
232 net_set_state(NETLOOP_SUCCESS);
235 void cdp_receive(const uchar *pkt, unsigned len)
243 if (len < sizeof(cdp_snap_hdr) + 4)
246 /* check for valid CDP SNAP header */
247 if (memcmp(pkt, cdp_snap_hdr, sizeof(cdp_snap_hdr)) != 0)
250 pkt += sizeof(cdp_snap_hdr);
251 len -= sizeof(cdp_snap_hdr);
253 /* Version of CDP protocol must be >= 2 and TTL != 0 */
254 if (pkt[0] < 0x02 || pkt[1] == 0)
258 * if version is greater than 0x02 maybe we'll have a problem;
262 printf("**WARNING: CDP packet received with a protocol version "
263 "%d > 2\n", pkt[0] & 0xff);
265 if (cdp_compute_csum(pkt, len) != 0)
277 ss = (const ushort *)pkt;
286 ss += 2; /* point ss to the data of the TLV */
290 case CDP_DEVICE_ID_TLV:
292 case CDP_ADDRESS_TLV:
294 case CDP_PORT_ID_TLV:
296 case CDP_CAPABILITIES_TLV:
298 case CDP_VERSION_TLV:
300 case CDP_PLATFORM_TLV:
302 case CDP_NATIVE_VLAN_TLV:
305 case CDP_APPLIANCE_VLAN_TLV:
306 t = (const uchar *)ss;
311 ss = (const ushort *)(t + 1);
313 #ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
314 if (t[0] == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
317 /* XXX will this work; dunno */
323 case CDP_TRIGGER_TLV:
325 case CDP_POWER_CONSUMPTION_TLV:
327 case CDP_SYSNAME_TLV:
329 case CDP_SYSOBJECT_TLV:
331 case CDP_MANAGEMENT_ADDRESS_TLV:
336 cdp_appliance_vlan = vlan;
337 cdp_native_vlan = nvlan;
343 printf("** CDP packet is too short\n");
349 printf("Using %s device\n", eth_get_name());
353 cdp_native_vlan = htons(-1);
354 cdp_appliance_vlan = htons(-1);
356 net_set_timeout_handler(CDP_TIMEOUT, cdp_timeout_handler);