cdp.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * Copied from Linux Monitor (LiMon) - Networking.
  3. *
  4. * Copyright 1994 - 2000 Neil Russell.
  5. * (See License)
  6. * Copyright 2000 Roland Borde
  7. * Copyright 2000 Paolo Scaffardi
  8. * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
  9. * SPDX-License-Identifier: GPL-2.0
  10. */
  11. #include <common.h>
  12. #include <net.h>
  13. #if defined(CONFIG_CDP_VERSION)
  14. #include <timestamp.h>
  15. #endif
  16. #include "cdp.h"
  17. /* Ethernet bcast address */
  18. const uchar NetCDPAddr[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
  32. #define CDP_TIMEOUT 250UL /* one packet every 250ms */
  33. static int CDPSeq;
  34. static int CDPOK;
  35. ushort CDPNativeVLAN;
  36. ushort CDPApplianceVLAN;
  37. static const uchar CDP_SNAP_hdr[8] = {
  38. 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
  39. static ushort
  40. CDP_compute_csum(const uchar *buff, ushort len)
  41. {
  42. ushort csum;
  43. int odd;
  44. ulong result = 0;
  45. ushort leftover;
  46. ushort *p;
  47. if (len > 0) {
  48. odd = 1 & (ulong)buff;
  49. if (odd) {
  50. result = *buff << 8;
  51. len--;
  52. buff++;
  53. }
  54. while (len > 1) {
  55. p = (ushort *)buff;
  56. result += *p++;
  57. buff = (uchar *)p;
  58. if (result & 0x80000000)
  59. result = (result & 0xFFFF) + (result >> 16);
  60. len -= 2;
  61. }
  62. if (len) {
  63. leftover = (signed short)(*(const signed char *)buff);
  64. /*
  65. * CISCO SUCKS big time! (and blows too):
  66. * CDP uses the IP checksum algorithm with a twist;
  67. * for the last byte it *sign* extends and sums.
  68. */
  69. result = (result & 0xffff0000) |
  70. ((result + leftover) & 0x0000ffff);
  71. }
  72. while (result >> 16)
  73. result = (result & 0xFFFF) + (result >> 16);
  74. if (odd)
  75. result = ((result >> 8) & 0xff) |
  76. ((result & 0xff) << 8);
  77. }
  78. /* add up 16-bit and 17-bit words for 17+c bits */
  79. result = (result & 0xffff) + (result >> 16);
  80. /* add up 16-bit and 2-bit for 16+c bit */
  81. result = (result & 0xffff) + (result >> 16);
  82. /* add up carry.. */
  83. result = (result & 0xffff) + (result >> 16);
  84. /* negate */
  85. csum = ~(ushort)result;
  86. /* run time endian detection */
  87. if (csum != htons(csum)) /* little endian */
  88. csum = htons(csum);
  89. return csum;
  90. }
  91. static int
  92. CDPSendTrigger(void)
  93. {
  94. uchar *pkt;
  95. ushort *s;
  96. ushort *cp;
  97. struct ethernet_hdr *et;
  98. int len;
  99. ushort chksum;
  100. #if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID) || \
  101. defined(CONFIG_CDP_VERSION) || defined(CONFIG_CDP_PLATFORM)
  102. char buf[32];
  103. #endif
  104. pkt = NetTxPacket;
  105. et = (struct ethernet_hdr *)pkt;
  106. /* NOTE: trigger sent not on any VLAN */
  107. /* form ethernet header */
  108. memcpy(et->et_dest, NetCDPAddr, 6);
  109. memcpy(et->et_src, NetOurEther, 6);
  110. pkt += ETHER_HDR_SIZE;
  111. /* SNAP header */
  112. memcpy((uchar *)pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr));
  113. pkt += sizeof(CDP_SNAP_hdr);
  114. /* CDP header */
  115. *pkt++ = 0x02; /* CDP version 2 */
  116. *pkt++ = 180; /* TTL */
  117. s = (ushort *)pkt;
  118. cp = s;
  119. /* checksum (0 for later calculation) */
  120. *s++ = htons(0);
  121. /* CDP fields */
  122. #ifdef CONFIG_CDP_DEVICE_ID
  123. *s++ = htons(CDP_DEVICE_ID_TLV);
  124. *s++ = htons(CONFIG_CDP_DEVICE_ID);
  125. sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", NetOurEther);
  126. memcpy((uchar *)s, buf, 16);
  127. s += 16 / 2;
  128. #endif
  129. #ifdef CONFIG_CDP_PORT_ID
  130. *s++ = htons(CDP_PORT_ID_TLV);
  131. memset(buf, 0, sizeof(buf));
  132. sprintf(buf, CONFIG_CDP_PORT_ID, eth_get_dev_index());
  133. len = strlen(buf);
  134. if (len & 1) /* make it even */
  135. len++;
  136. *s++ = htons(len + 4);
  137. memcpy((uchar *)s, buf, len);
  138. s += len / 2;
  139. #endif
  140. #ifdef CONFIG_CDP_CAPABILITIES
  141. *s++ = htons(CDP_CAPABILITIES_TLV);
  142. *s++ = htons(8);
  143. *(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES);
  144. s += 2;
  145. #endif
  146. #ifdef CONFIG_CDP_VERSION
  147. *s++ = htons(CDP_VERSION_TLV);
  148. memset(buf, 0, sizeof(buf));
  149. strcpy(buf, CONFIG_CDP_VERSION);
  150. len = strlen(buf);
  151. if (len & 1) /* make it even */
  152. len++;
  153. *s++ = htons(len + 4);
  154. memcpy((uchar *)s, buf, len);
  155. s += len / 2;
  156. #endif
  157. #ifdef CONFIG_CDP_PLATFORM
  158. *s++ = htons(CDP_PLATFORM_TLV);
  159. memset(buf, 0, sizeof(buf));
  160. strcpy(buf, CONFIG_CDP_PLATFORM);
  161. len = strlen(buf);
  162. if (len & 1) /* make it even */
  163. len++;
  164. *s++ = htons(len + 4);
  165. memcpy((uchar *)s, buf, len);
  166. s += len / 2;
  167. #endif
  168. #ifdef CONFIG_CDP_TRIGGER
  169. *s++ = htons(CDP_TRIGGER_TLV);
  170. *s++ = htons(8);
  171. *(ulong *)s = htonl(CONFIG_CDP_TRIGGER);
  172. s += 2;
  173. #endif
  174. #ifdef CONFIG_CDP_POWER_CONSUMPTION
  175. *s++ = htons(CDP_POWER_CONSUMPTION_TLV);
  176. *s++ = htons(6);
  177. *s++ = htons(CONFIG_CDP_POWER_CONSUMPTION);
  178. #endif
  179. /* length of ethernet packet */
  180. len = (uchar *)s - ((uchar *)NetTxPacket + ETHER_HDR_SIZE);
  181. et->et_protlen = htons(len);
  182. len = ETHER_HDR_SIZE + sizeof(CDP_SNAP_hdr);
  183. chksum = CDP_compute_csum((uchar *)NetTxPacket + len,
  184. (uchar *)s - (NetTxPacket + len));
  185. if (chksum == 0)
  186. chksum = 0xFFFF;
  187. *cp = htons(chksum);
  188. NetSendPacket(NetTxPacket, (uchar *)s - NetTxPacket);
  189. return 0;
  190. }
  191. static void
  192. CDPTimeout(void)
  193. {
  194. CDPSeq++;
  195. if (CDPSeq < 3) {
  196. NetSetTimeout(CDP_TIMEOUT, CDPTimeout);
  197. CDPSendTrigger();
  198. return;
  199. }
  200. /* if not OK try again */
  201. if (!CDPOK)
  202. NetStartAgain();
  203. else
  204. net_set_state(NETLOOP_SUCCESS);
  205. }
  206. void cdp_receive(const uchar *pkt, unsigned len)
  207. {
  208. const uchar *t;
  209. const ushort *ss;
  210. ushort type, tlen;
  211. ushort vlan, nvlan;
  212. /* minimum size? */
  213. if (len < sizeof(CDP_SNAP_hdr) + 4)
  214. goto pkt_short;
  215. /* check for valid CDP SNAP header */
  216. if (memcmp(pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr)) != 0)
  217. return;
  218. pkt += sizeof(CDP_SNAP_hdr);
  219. len -= sizeof(CDP_SNAP_hdr);
  220. /* Version of CDP protocol must be >= 2 and TTL != 0 */
  221. if (pkt[0] < 0x02 || pkt[1] == 0)
  222. return;
  223. /*
  224. * if version is greater than 0x02 maybe we'll have a problem;
  225. * output a warning
  226. */
  227. if (pkt[0] != 0x02)
  228. printf("**WARNING: CDP packet received with a protocol version "
  229. "%d > 2\n", pkt[0] & 0xff);
  230. if (CDP_compute_csum(pkt, len) != 0)
  231. return;
  232. pkt += 4;
  233. len -= 4;
  234. vlan = htons(-1);
  235. nvlan = htons(-1);
  236. while (len > 0) {
  237. if (len < 4)
  238. goto pkt_short;
  239. ss = (const ushort *)pkt;
  240. type = ntohs(ss[0]);
  241. tlen = ntohs(ss[1]);
  242. if (tlen > len)
  243. goto pkt_short;
  244. pkt += tlen;
  245. len -= tlen;
  246. ss += 2; /* point ss to the data of the TLV */
  247. tlen -= 4;
  248. switch (type) {
  249. case CDP_DEVICE_ID_TLV:
  250. break;
  251. case CDP_ADDRESS_TLV:
  252. break;
  253. case CDP_PORT_ID_TLV:
  254. break;
  255. case CDP_CAPABILITIES_TLV:
  256. break;
  257. case CDP_VERSION_TLV:
  258. break;
  259. case CDP_PLATFORM_TLV:
  260. break;
  261. case CDP_NATIVE_VLAN_TLV:
  262. nvlan = *ss;
  263. break;
  264. case CDP_APPLIANCE_VLAN_TLV:
  265. t = (const uchar *)ss;
  266. while (tlen > 0) {
  267. if (tlen < 3)
  268. goto pkt_short;
  269. ss = (const ushort *)(t + 1);
  270. #ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
  271. if (t[0] == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
  272. vlan = *ss;
  273. #else
  274. /* XXX will this work; dunno */
  275. vlan = ntohs(*ss);
  276. #endif
  277. t += 3; tlen -= 3;
  278. }
  279. break;
  280. case CDP_TRIGGER_TLV:
  281. break;
  282. case CDP_POWER_CONSUMPTION_TLV:
  283. break;
  284. case CDP_SYSNAME_TLV:
  285. break;
  286. case CDP_SYSOBJECT_TLV:
  287. break;
  288. case CDP_MANAGEMENT_ADDRESS_TLV:
  289. break;
  290. }
  291. }
  292. CDPApplianceVLAN = vlan;
  293. CDPNativeVLAN = nvlan;
  294. CDPOK = 1;
  295. return;
  296. pkt_short:
  297. printf("** CDP packet is too short\n");
  298. return;
  299. }
  300. void
  301. CDPStart(void)
  302. {
  303. printf("Using %s device\n", eth_get_name());
  304. CDPSeq = 0;
  305. CDPOK = 0;
  306. CDPNativeVLAN = htons(-1);
  307. CDPApplianceVLAN = htons(-1);
  308. NetSetTimeout(CDP_TIMEOUT, CDPTimeout);
  309. CDPSendTrigger();
  310. }