"Das U-Boot" Source Tree
at master 359 lines 7.7 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copied from Linux Monitor (LiMon) - Networking. 4 * 5 * Copyright 1994 - 2000 Neil Russell. 6 * (See License) 7 * Copyright 2000 Roland Borde 8 * Copyright 2000 Paolo Scaffardi 9 * Copyright 2000-2002 Wolfgang Denk, wd@denx.de 10 */ 11 12#include <net.h> 13 14#include "cdp.h" 15 16/* Ethernet bcast address */ 17const u8 net_cdp_ethaddr[6] = { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc }; 18 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 32 33#define CDP_TIMEOUT 250UL /* one packet every 250ms */ 34 35static int cdp_seq; 36static int cdp_ok; 37 38ushort cdp_native_vlan; 39ushort cdp_appliance_vlan; 40 41static const uchar cdp_snap_hdr[8] = { 42 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 }; 43 44static ushort cdp_compute_csum(const uchar *buff, ushort len) 45{ 46 ushort csum; 47 int odd; 48 ulong result = 0; 49 ushort leftover; 50 ushort *p; 51 52 if (len > 0) { 53 odd = 1 & (ulong)buff; 54 if (odd) { 55 result = *buff << 8; 56 len--; 57 buff++; 58 } 59 while (len > 1) { 60 p = (ushort *)buff; 61 result += *p++; 62 buff = (uchar *)p; 63 if (result & 0x80000000) 64 result = (result & 0xFFFF) + (result >> 16); 65 len -= 2; 66 } 67 if (len) { 68 leftover = (signed short)(*(const signed char *)buff); 69 /* 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. 73 */ 74 result = (result & 0xffff0000) | 75 ((result + leftover) & 0x0000ffff); 76 } 77 while (result >> 16) 78 result = (result & 0xFFFF) + (result >> 16); 79 80 if (odd) 81 result = ((result >> 8) & 0xff) | 82 ((result & 0xff) << 8); 83 } 84 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); 89 /* add up carry.. */ 90 result = (result & 0xffff) + (result >> 16); 91 92 /* negate */ 93 csum = ~(ushort)result; 94 95 /* run time endian detection */ 96 if (csum != htons(csum)) /* little endian */ 97 csum = htons(csum); 98 99 return csum; 100} 101 102static int cdp_send_trigger(void) 103{ 104 uchar *pkt; 105 ushort *s; 106 ushort *cp; 107 struct ethernet_hdr *et; 108 int len; 109 ushort chksum; 110#if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID) || \ 111 defined(CONFIG_CDP_VERSION) || defined(CONFIG_CDP_PLATFORM) 112 char buf[32]; 113#endif 114 115 pkt = net_tx_packet; 116 et = (struct ethernet_hdr *)pkt; 117 118 /* NOTE: trigger sent not on any VLAN */ 119 120 /* form ethernet header */ 121 memcpy(et->et_dest, net_cdp_ethaddr, 6); 122 memcpy(et->et_src, net_ethaddr, 6); 123 124 pkt += ETHER_HDR_SIZE; 125 126 /* SNAP header */ 127 memcpy((uchar *)pkt, cdp_snap_hdr, sizeof(cdp_snap_hdr)); 128 pkt += sizeof(cdp_snap_hdr); 129 130 /* CDP header */ 131 *pkt++ = 0x02; /* CDP version 2 */ 132 *pkt++ = 180; /* TTL */ 133 s = (ushort *)pkt; 134 cp = s; 135 /* checksum (0 for later calculation) */ 136 *s++ = htons(0); 137 138 /* CDP fields */ 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); 144 s += 16 / 2; 145#endif 146 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()); 151 len = strlen(buf); 152 if (len & 1) /* make it even */ 153 len++; 154 *s++ = htons(len + 4); 155 memcpy((uchar *)s, buf, len); 156 s += len / 2; 157#endif 158 159#ifdef CONFIG_CDP_CAPABILITIES 160 *s++ = htons(CDP_CAPABILITIES_TLV); 161 *s++ = htons(8); 162 *(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES); 163 s += 2; 164#endif 165 166#ifdef CONFIG_CDP_VERSION 167 *s++ = htons(CDP_VERSION_TLV); 168 memset(buf, 0, sizeof(buf)); 169 strcpy(buf, CONFIG_CDP_VERSION); 170 len = strlen(buf); 171 if (len & 1) /* make it even */ 172 len++; 173 *s++ = htons(len + 4); 174 memcpy((uchar *)s, buf, len); 175 s += len / 2; 176#endif 177 178#ifdef CONFIG_CDP_PLATFORM 179 *s++ = htons(CDP_PLATFORM_TLV); 180 memset(buf, 0, sizeof(buf)); 181 strcpy(buf, CONFIG_CDP_PLATFORM); 182 len = strlen(buf); 183 if (len & 1) /* make it even */ 184 len++; 185 *s++ = htons(len + 4); 186 memcpy((uchar *)s, buf, len); 187 s += len / 2; 188#endif 189 190#ifdef CONFIG_CDP_TRIGGER 191 *s++ = htons(CDP_TRIGGER_TLV); 192 *s++ = htons(8); 193 *(ulong *)s = htonl(CONFIG_CDP_TRIGGER); 194 s += 2; 195#endif 196 197#ifdef CONFIG_CDP_POWER_CONSUMPTION 198 *s++ = htons(CDP_POWER_CONSUMPTION_TLV); 199 *s++ = htons(6); 200 *s++ = htons(CONFIG_CDP_POWER_CONSUMPTION); 201#endif 202 203 /* length of ethernet packet */ 204 len = (uchar *)s - ((uchar *)net_tx_packet + ETHER_HDR_SIZE); 205 et->et_protlen = htons(len); 206 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)); 210 if (chksum == 0) 211 chksum = 0xFFFF; 212 *cp = htons(chksum); 213 214 net_send_packet(net_tx_packet, (uchar *)s - net_tx_packet); 215 return 0; 216} 217 218static void cdp_timeout_handler(void) 219{ 220 cdp_seq++; 221 222 if (cdp_seq < 3) { 223 net_set_timeout_handler(CDP_TIMEOUT, cdp_timeout_handler); 224 cdp_send_trigger(); 225 return; 226 } 227 228 /* if not OK try again */ 229 if (!cdp_ok) 230 net_start_again(); 231 else 232 net_set_state(NETLOOP_SUCCESS); 233} 234 235void cdp_receive(const uchar *pkt, unsigned len) 236{ 237 const uchar *t; 238 const ushort *ss; 239 ushort type, tlen; 240 ushort vlan, nvlan; 241 242 /* minimum size? */ 243 if (len < sizeof(cdp_snap_hdr) + 4) 244 goto pkt_short; 245 246 /* check for valid CDP SNAP header */ 247 if (memcmp(pkt, cdp_snap_hdr, sizeof(cdp_snap_hdr)) != 0) 248 return; 249 250 pkt += sizeof(cdp_snap_hdr); 251 len -= sizeof(cdp_snap_hdr); 252 253 /* Version of CDP protocol must be >= 2 and TTL != 0 */ 254 if (pkt[0] < 0x02 || pkt[1] == 0) 255 return; 256 257 /* 258 * if version is greater than 0x02 maybe we'll have a problem; 259 * output a warning 260 */ 261 if (pkt[0] != 0x02) 262 printf("**WARNING: CDP packet received with a protocol version " 263 "%d > 2\n", pkt[0] & 0xff); 264 265 if (cdp_compute_csum(pkt, len) != 0) 266 return; 267 268 pkt += 4; 269 len -= 4; 270 271 vlan = htons(-1); 272 nvlan = htons(-1); 273 while (len > 0) { 274 if (len < 4) 275 goto pkt_short; 276 277 ss = (const ushort *)pkt; 278 type = ntohs(ss[0]); 279 tlen = ntohs(ss[1]); 280 if (tlen > len) 281 goto pkt_short; 282 283 pkt += tlen; 284 len -= tlen; 285 286 ss += 2; /* point ss to the data of the TLV */ 287 tlen -= 4; 288 289 switch (type) { 290 case CDP_DEVICE_ID_TLV: 291 break; 292 case CDP_ADDRESS_TLV: 293 break; 294 case CDP_PORT_ID_TLV: 295 break; 296 case CDP_CAPABILITIES_TLV: 297 break; 298 case CDP_VERSION_TLV: 299 break; 300 case CDP_PLATFORM_TLV: 301 break; 302 case CDP_NATIVE_VLAN_TLV: 303 nvlan = *ss; 304 break; 305 case CDP_APPLIANCE_VLAN_TLV: 306 t = (const uchar *)ss; 307 while (tlen > 0) { 308 if (tlen < 3) 309 goto pkt_short; 310 311 ss = (const ushort *)(t + 1); 312 313#ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE 314 if (t[0] == CONFIG_CDP_APPLIANCE_VLAN_TYPE) 315 vlan = *ss; 316#else 317 /* XXX will this work; dunno */ 318 vlan = ntohs(*ss); 319#endif 320 t += 3; tlen -= 3; 321 } 322 break; 323 case CDP_TRIGGER_TLV: 324 break; 325 case CDP_POWER_CONSUMPTION_TLV: 326 break; 327 case CDP_SYSNAME_TLV: 328 break; 329 case CDP_SYSOBJECT_TLV: 330 break; 331 case CDP_MANAGEMENT_ADDRESS_TLV: 332 break; 333 } 334 } 335 336 cdp_appliance_vlan = vlan; 337 cdp_native_vlan = nvlan; 338 339 cdp_ok = 1; 340 return; 341 342pkt_short: 343 printf("** CDP packet is too short\n"); 344 return; 345} 346 347void cdp_start(void) 348{ 349 printf("Using %s device\n", eth_get_name()); 350 cdp_seq = 0; 351 cdp_ok = 0; 352 353 cdp_native_vlan = htons(-1); 354 cdp_appliance_vlan = htons(-1); 355 356 net_set_timeout_handler(CDP_TIMEOUT, cdp_timeout_handler); 357 358 cdp_send_trigger(); 359}