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
17 /* Ethernet bcast address */
18 const u8 net_cdp_ethaddr
[6] = { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
20 #define CDP_DEVICE_ID_TLV 0x0001
21 #define CDP_ADDRESS_TLV 0x0002
22 #define CDP_PORT_ID_TLV 0x0003
23 #define CDP_CAPABILITIES_TLV 0x0004
24 #define CDP_VERSION_TLV 0x0005
25 #define CDP_PLATFORM_TLV 0x0006
26 #define CDP_NATIVE_VLAN_TLV 0x000a
27 #define CDP_APPLIANCE_VLAN_TLV 0x000e
28 #define CDP_TRIGGER_TLV 0x000f
29 #define CDP_POWER_CONSUMPTION_TLV 0x0010
30 #define CDP_SYSNAME_TLV 0x0014
31 #define CDP_SYSOBJECT_TLV 0x0015
32 #define CDP_MANAGEMENT_ADDRESS_TLV 0x0016
34 #define CDP_TIMEOUT 250UL /* one packet every 250ms */
39 ushort cdp_native_vlan
;
40 ushort cdp_appliance_vlan
;
42 static const uchar cdp_snap_hdr
[8] = {
43 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
45 static ushort
cdp_compute_csum(const uchar
*buff
, ushort len
)
54 odd
= 1 & (ulong
)buff
;
64 if (result
& 0x80000000)
65 result
= (result
& 0xFFFF) + (result
>> 16);
69 leftover
= (signed short)(*(const signed char *)buff
);
71 * CISCO SUCKS big time! (and blows too):
72 * CDP uses the IP checksum algorithm with a twist;
73 * for the last byte it *sign* extends and sums.
75 result
= (result
& 0xffff0000) |
76 ((result
+ leftover
) & 0x0000ffff);
79 result
= (result
& 0xFFFF) + (result
>> 16);
82 result
= ((result
>> 8) & 0xff) |
83 ((result
& 0xff) << 8);
86 /* add up 16-bit and 17-bit words for 17+c bits */
87 result
= (result
& 0xffff) + (result
>> 16);
88 /* add up 16-bit and 2-bit for 16+c bit */
89 result
= (result
& 0xffff) + (result
>> 16);
91 result
= (result
& 0xffff) + (result
>> 16);
94 csum
= ~(ushort
)result
;
96 /* run time endian detection */
97 if (csum
!= htons(csum
)) /* little endian */
103 static int cdp_send_trigger(void)
108 struct ethernet_hdr
*et
;
111 #if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID) || \
112 defined(CONFIG_CDP_VERSION) || defined(CONFIG_CDP_PLATFORM)
117 et
= (struct ethernet_hdr
*)pkt
;
119 /* NOTE: trigger sent not on any VLAN */
121 /* form ethernet header */
122 memcpy(et
->et_dest
, net_cdp_ethaddr
, 6);
123 memcpy(et
->et_src
, net_ethaddr
, 6);
125 pkt
+= ETHER_HDR_SIZE
;
128 memcpy((uchar
*)pkt
, cdp_snap_hdr
, sizeof(cdp_snap_hdr
));
129 pkt
+= sizeof(cdp_snap_hdr
);
132 *pkt
++ = 0x02; /* CDP version 2 */
133 *pkt
++ = 180; /* TTL */
136 /* checksum (0 for later calculation) */
140 #ifdef CONFIG_CDP_DEVICE_ID
141 *s
++ = htons(CDP_DEVICE_ID_TLV
);
142 *s
++ = htons(CONFIG_CDP_DEVICE_ID
);
143 sprintf(buf
, CONFIG_CDP_DEVICE_ID_PREFIX
"%pm", net_ethaddr
);
144 memcpy((uchar
*)s
, buf
, 16);
148 #ifdef CONFIG_CDP_PORT_ID
149 *s
++ = htons(CDP_PORT_ID_TLV
);
150 memset(buf
, 0, sizeof(buf
));
151 sprintf(buf
, CONFIG_CDP_PORT_ID
, eth_get_dev_index());
153 if (len
& 1) /* make it even */
155 *s
++ = htons(len
+ 4);
156 memcpy((uchar
*)s
, buf
, len
);
160 #ifdef CONFIG_CDP_CAPABILITIES
161 *s
++ = htons(CDP_CAPABILITIES_TLV
);
163 *(ulong
*)s
= htonl(CONFIG_CDP_CAPABILITIES
);
167 #ifdef CONFIG_CDP_VERSION
168 *s
++ = htons(CDP_VERSION_TLV
);
169 memset(buf
, 0, sizeof(buf
));
170 strcpy(buf
, CONFIG_CDP_VERSION
);
172 if (len
& 1) /* make it even */
174 *s
++ = htons(len
+ 4);
175 memcpy((uchar
*)s
, buf
, len
);
179 #ifdef CONFIG_CDP_PLATFORM
180 *s
++ = htons(CDP_PLATFORM_TLV
);
181 memset(buf
, 0, sizeof(buf
));
182 strcpy(buf
, CONFIG_CDP_PLATFORM
);
184 if (len
& 1) /* make it even */
186 *s
++ = htons(len
+ 4);
187 memcpy((uchar
*)s
, buf
, len
);
191 #ifdef CONFIG_CDP_TRIGGER
192 *s
++ = htons(CDP_TRIGGER_TLV
);
194 *(ulong
*)s
= htonl(CONFIG_CDP_TRIGGER
);
198 #ifdef CONFIG_CDP_POWER_CONSUMPTION
199 *s
++ = htons(CDP_POWER_CONSUMPTION_TLV
);
201 *s
++ = htons(CONFIG_CDP_POWER_CONSUMPTION
);
204 /* length of ethernet packet */
205 len
= (uchar
*)s
- ((uchar
*)net_tx_packet
+ ETHER_HDR_SIZE
);
206 et
->et_protlen
= htons(len
);
208 len
= ETHER_HDR_SIZE
+ sizeof(cdp_snap_hdr
);
209 chksum
= cdp_compute_csum((uchar
*)net_tx_packet
+ len
,
210 (uchar
*)s
- (net_tx_packet
+ len
));
215 net_send_packet(net_tx_packet
, (uchar
*)s
- net_tx_packet
);
219 static void cdp_timeout_handler(void)
224 net_set_timeout_handler(CDP_TIMEOUT
, cdp_timeout_handler
);
229 /* if not OK try again */
233 net_set_state(NETLOOP_SUCCESS
);
236 void cdp_receive(const uchar
*pkt
, unsigned len
)
244 if (len
< sizeof(cdp_snap_hdr
) + 4)
247 /* check for valid CDP SNAP header */
248 if (memcmp(pkt
, cdp_snap_hdr
, sizeof(cdp_snap_hdr
)) != 0)
251 pkt
+= sizeof(cdp_snap_hdr
);
252 len
-= sizeof(cdp_snap_hdr
);
254 /* Version of CDP protocol must be >= 2 and TTL != 0 */
255 if (pkt
[0] < 0x02 || pkt
[1] == 0)
259 * if version is greater than 0x02 maybe we'll have a problem;
263 printf("**WARNING: CDP packet received with a protocol version "
264 "%d > 2\n", pkt
[0] & 0xff);
266 if (cdp_compute_csum(pkt
, len
) != 0)
278 ss
= (const ushort
*)pkt
;
287 ss
+= 2; /* point ss to the data of the TLV */
291 case CDP_DEVICE_ID_TLV
:
293 case CDP_ADDRESS_TLV
:
295 case CDP_PORT_ID_TLV
:
297 case CDP_CAPABILITIES_TLV
:
299 case CDP_VERSION_TLV
:
301 case CDP_PLATFORM_TLV
:
303 case CDP_NATIVE_VLAN_TLV
:
306 case CDP_APPLIANCE_VLAN_TLV
:
307 t
= (const uchar
*)ss
;
312 ss
= (const ushort
*)(t
+ 1);
314 #ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
315 if (t
[0] == CONFIG_CDP_APPLIANCE_VLAN_TYPE
)
318 /* XXX will this work; dunno */
324 case CDP_TRIGGER_TLV
:
326 case CDP_POWER_CONSUMPTION_TLV
:
328 case CDP_SYSNAME_TLV
:
330 case CDP_SYSOBJECT_TLV
:
332 case CDP_MANAGEMENT_ADDRESS_TLV
:
337 cdp_appliance_vlan
= vlan
;
338 cdp_native_vlan
= nvlan
;
344 printf("** CDP packet is too short\n");
350 printf("Using %s device\n", eth_get_name());
354 cdp_native_vlan
= htons(-1);
355 cdp_appliance_vlan
= htons(-1);
357 net_set_timeout_handler(CDP_TIMEOUT
, cdp_timeout_handler
);