cdp.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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. (void) eth_send(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. NetState = NETLOOP_SUCCESS;
  204. }
  205. static void
  206. CDPDummyHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
  207. unsigned len)
  208. {
  209. /* nothing */
  210. }
  211. void cdp_receive(const uchar *pkt, unsigned len)
  212. {
  213. const uchar *t;
  214. const ushort *ss;
  215. ushort type, tlen;
  216. ushort vlan, nvlan;
  217. /* minimum size? */
  218. if (len < sizeof(CDP_SNAP_hdr) + 4)
  219. goto pkt_short;
  220. /* check for valid CDP SNAP header */
  221. if (memcmp(pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr)) != 0)
  222. return;
  223. pkt += sizeof(CDP_SNAP_hdr);
  224. len -= sizeof(CDP_SNAP_hdr);
  225. /* Version of CDP protocol must be >= 2 and TTL != 0 */
  226. if (pkt[0] < 0x02 || pkt[1] == 0)
  227. return;
  228. /*
  229. * if version is greater than 0x02 maybe we'll have a problem;
  230. * output a warning
  231. */
  232. if (pkt[0] != 0x02)
  233. printf("**WARNING: CDP packet received with a protocol version "
  234. "%d > 2\n", pkt[0] & 0xff);
  235. if (CDP_compute_csum(pkt, len) != 0)
  236. return;
  237. pkt += 4;
  238. len -= 4;
  239. vlan = htons(-1);
  240. nvlan = htons(-1);
  241. while (len > 0) {
  242. if (len < 4)
  243. goto pkt_short;
  244. ss = (const ushort *)pkt;
  245. type = ntohs(ss[0]);
  246. tlen = ntohs(ss[1]);
  247. if (tlen > len)
  248. goto pkt_short;
  249. pkt += tlen;
  250. len -= tlen;
  251. ss += 2; /* point ss to the data of the TLV */
  252. tlen -= 4;
  253. switch (type) {
  254. case CDP_DEVICE_ID_TLV:
  255. break;
  256. case CDP_ADDRESS_TLV:
  257. break;
  258. case CDP_PORT_ID_TLV:
  259. break;
  260. case CDP_CAPABILITIES_TLV:
  261. break;
  262. case CDP_VERSION_TLV:
  263. break;
  264. case CDP_PLATFORM_TLV:
  265. break;
  266. case CDP_NATIVE_VLAN_TLV:
  267. nvlan = *ss;
  268. break;
  269. case CDP_APPLIANCE_VLAN_TLV:
  270. t = (const uchar *)ss;
  271. while (tlen > 0) {
  272. if (tlen < 3)
  273. goto pkt_short;
  274. ss = (const ushort *)(t + 1);
  275. #ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
  276. if (t[0] == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
  277. vlan = *ss;
  278. #else
  279. /* XXX will this work; dunno */
  280. vlan = ntohs(*ss);
  281. #endif
  282. t += 3; tlen -= 3;
  283. }
  284. break;
  285. case CDP_TRIGGER_TLV:
  286. break;
  287. case CDP_POWER_CONSUMPTION_TLV:
  288. break;
  289. case CDP_SYSNAME_TLV:
  290. break;
  291. case CDP_SYSOBJECT_TLV:
  292. break;
  293. case CDP_MANAGEMENT_ADDRESS_TLV:
  294. break;
  295. }
  296. }
  297. CDPApplianceVLAN = vlan;
  298. CDPNativeVLAN = nvlan;
  299. CDPOK = 1;
  300. return;
  301. pkt_short:
  302. printf("** CDP packet is too short\n");
  303. return;
  304. }
  305. void
  306. CDPStart(void)
  307. {
  308. printf("Using %s device\n", eth_get_name());
  309. CDPSeq = 0;
  310. CDPOK = 0;
  311. CDPNativeVLAN = htons(-1);
  312. CDPApplianceVLAN = htons(-1);
  313. NetSetTimeout(CDP_TIMEOUT, CDPTimeout);
  314. NetSetHandler(CDPDummyHandler);
  315. CDPSendTrigger();
  316. }