cdp.c 7.5 KB

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