1 /*******************************************************************
2 *
3 * OpenLLDP TLV
4 *
5 * See LICENSE file for more info.
6 *
7 * File: lldp_tlv.c
8 *
9 * Authors: Terry Simons (terry.simons@gmail.com)
10 *
11 *******************************************************************/
12
13 #ifndef WIN32
14 #include <arpa/inet.h>
15 #include <stdint.h>
16 #else
17 #define strdup _strdup
18 #include "stdintwin.h"
19 #include "Winsock2.h"
20 #endif
21 #include <sys/types.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <netinet/in.h>
26 #include "lldp_port.h"
27 #include "lldp_debug.h"
28 #include "tlv.h"
29 #include "tlv_common.h"
30 #include "lldp_neighbor.h"
31
32 // The LLDP-MED location configuration data.
33 extern struct lci_s lci;
34
35 /* There are a max of 128 TLV validators (types 0 through 127), so we'll stick them in a static array indexed by their tlv type */
36 uint8_t (*validate_tlv[128])(struct lldp_tlv *tlv) = {
37 validate_end_of_lldpdu_tlv, /* 0 End of LLDPU TLV */
38 validate_chassis_id_tlv, /* 1 Chassis ID TLV */
39 validate_port_id_tlv, /* 2 Port ID TLV */
40 validate_ttl_tlv, /* 3 Time To Live TLV */
41 validate_port_description_tlv, /* 4 Port Description TLV */
42 validate_system_name_tlv, /* 5 System Name TLV */
43 validate_system_description_tlv, /* 6 System Description TLV */
44 validate_system_capabilities_tlv, /* 7 System Capabilities TLV */
45 validate_management_address_tlv, /* 8 Management Address TLV */
46 /* 9 - 126 are reserved and set to NULL in lldp_tlv_validator_init() */
47 /* 127 is populated for validate_organizationally_specific_tlv in lldp_tlv_validator_init() */
48 };
49
50 #ifndef WIN32
51 #warning Write a test suite that will run all the possible combinations of decode
52 #endif // WIN32
53
decode_tlv_subtype(struct lldp_tlv * tlv)54 char *decode_tlv_subtype(struct lldp_tlv *tlv)
55 {
56 char *result = calloc(1, 2048);
57 char *title = NULL;
58
59 switch(tlv->type)
60 {
61 case CHASSIS_ID_TLV:
62 {
63 uint8_t *chassis_id = &tlv->info_string[1];
64
65 switch(tlv->info_string[0])
66 {
67 case CHASSIS_ID_CHASSIS_COMPONENT:
68 {
69 title = "\tChassis Component - ";
70 strncat(result, title, strlen(title));
71 debug_hex_strcat((uint8_t *)result, chassis_id, (tlv->length - 1));
72 }break;
73 case CHASSIS_ID_INTERFACE_ALIAS:
74 {
75 strncat(result, "\tInterface Alias - ", 19);
76 debug_hex_strcat((uint8_t *)result, chassis_id, (tlv->length - 1));
77 }break;
78 case CHASSIS_ID_PORT_COMPONENT:
79 {
80 strncat(result, "\tPort Component - ", 19);
81 debug_hex_strcat((uint8_t *)result, chassis_id, (tlv->length - 1));
82 }break;
83 case CHASSIS_ID_MAC_ADDRESS:
84 {
85 title = "\tMAC Address - ";
86 strncat(result, title, strlen(title));
87 debug_hex_strcat((uint8_t *)result, chassis_id, (tlv->length - 1));
88 }break;
89 case CHASSIS_ID_NETWORK_ADDRESS:
90 {
91 char *network_address = decode_network_address(chassis_id);
92
93 strncat(result, "\tNetwork Address - ", 2048);
94
95 strncat(result, network_address, 2048);
96
97 free(network_address);
98 }break;
99 case CHASSIS_ID_INTERFACE_NAME:
100 {
101 strncat(result, "\tInterface Name - ", 2048);
102 debug_hex_strcat((uint8_t *)result, chassis_id, (tlv->length - 1));
103 }break;
104 case CHASSIS_ID_LOCALLY_ASSIGNED:
105 {
106 // According to 802.1AB 9.5.3.2, this is an alphanumeric
107 char *tmp = calloc(1, tlv->length + 1);
108
109 memcpy(tmp, tlv->info_string, tlv->length);
110
111 strncat(result, "\tLocally Assigned - ", 2048);
112
113 strncat(result, tmp, 255);
114
115 free(tmp);
116 }break;
117 default:
118 {
119 char *tmp = calloc(1, 2048);
120
121 sprintf(tmp, "\tReserved (%c)\n", tlv->info_string[0]);
122
123 strncat(result, tmp, 2048);
124
125 free(tmp);
126 }
127 };
128 }break;
129 case PORT_ID_TLV:
130 {
131 uint8_t *port_id = &tlv->info_string[1];
132
133 // strncat(result, "Port ID: ", 2048);
134
135 switch(tlv->info_string[0])
136 {
137 case PORT_ID_INTERFACE_ALIAS:
138 {
139 strncat(result, "\tInterface Alias - ", 2048);
140 debug_hex_strcat((uint8_t *)result, port_id, tlv->length -1);
141 }break;
142 case PORT_ID_PORT_COMPONENT:
143 {
144 strncat(result, "\tPort Component - ", 2048);
145 debug_hex_strcat((uint8_t *)result, port_id, tlv->length -1);
146 }break;
147 case PORT_ID_MAC_ADDRESS:
148 {
149 strncat(result, "\tMAC Address - ", 2048);
150 debug_hex_strcat((uint8_t *)result, port_id, tlv->length -1);
151 }break;
152 case PORT_ID_NETWORK_ADDRESS:
153 {
154 char *network_address = decode_network_address(port_id);
155 strncat(result, "\tNetwork Address - ", 2048);
156
157 strncat(result, network_address, 2048);
158
159 free(network_address);
160 }break;
161 case PORT_ID_INTERFACE_NAME:
162 {
163 char *tmp = calloc(1, 18 + tlv->length + 1);
164
165 //char *cstr = tlv_info_string_to_cstr(tlv);
166 // The port interface name is 1 less than the lenght.
167 char *cstr = calloc(1, tlv->length);
168 memcpy(cstr, &tlv->info_string[1], tlv->length - 1);
169
170 if(cstr != NULL)
171 {
172 sprintf(tmp, "\tInterface Name - %s", cstr);
173
174 free(cstr);
175
176 strncat(result, tmp, 2048);
177 }
178
179 free(tmp);
180
181 }break;
182 case PORT_ID_LOCALLY_ASSIGNED:
183 {
184 // According to 802.1AB 9.5.3.2, this is an alphanumeric
185 char *tmp = calloc(1, tlv->length);
186
187 memcpy(tmp, tlv->info_string, tlv->length);
188 strncat(result, "\tLocally Assigned - ", 2048);
189
190 //debug_hex_strcat(result, tlv->info_string, tlv->length - 1);
191
192 strncat(result, tmp, 2048);
193
194 free(tmp);;
195 }break;
196 default:
197 {
198 char *tmp = calloc(1, 2048);
199
200 sprintf(tmp, "\tReserved (%c)", tlv->info_string[0]);
201
202 strncat(result, tmp, 2048);
203
204 free(tmp);
205 }
206 };
207 }break;
208 case TIME_TO_LIVE_TLV:
209 {
210 uint16_t *ttl = (uint16_t *)&tlv->info_string[0];
211
212 char *tmp = calloc(1, 255);
213
214 sprintf(tmp, "\t%d seconds", htons(*ttl));
215
216 strncat(result, tmp, 2048);
217
218 free(tmp);
219
220 //debug_printf(DEBUG_TLV, "Time To Live: %d seconds", htons(*ttl));
221 }break;
222 case PORT_DESCRIPTION_TLV:
223 {
224 char *port_description = calloc(1, tlv->length + 1);
225
226 memcpy(port_description, tlv->info_string, tlv->length);
227
228 //sprintf(tmp, "Port Description:\t%s\n", port_description);
229
230 strncat(result, port_description, 2048);
231
232 //strncat(result, tmp, 2048);
233
234 //free(tmp);
235
236 //debug_printf(DEBUG_TLV, "Port Description: %s\n", port_description);
237
238 free(port_description);
239 }break;
240 case SYSTEM_NAME_TLV:
241 {
242 char *tmp = calloc(1, tlv->length + 2);
243 char *cstr = tlv_info_string_to_cstr(tlv);
244
245 if(cstr != NULL)
246 {
247 snprintf(tmp, tlv->length + 2, "\t%s", cstr);
248
249 free(cstr);
250
251 strncat(result, tmp, strlen(tmp));
252 }
253
254
255
256 free(tmp);
257 }break;
258 case SYSTEM_DESCRIPTION_TLV:
259 {
260 char *cstr = tlv_info_string_to_cstr(tlv);
261
262 if(cstr != NULL)
263 {
264 strncat(result, cstr, strlen(cstr));
265 free(cstr);
266 }
267 }break;
268 case SYSTEM_CAPABILITIES_TLV:
269 {
270 char *capabilities = NULL;
271
272 uint16_t *system_capabilities = (uint16_t *)&tlv->info_string[0];
273 uint16_t *enabled_capabilities = (uint16_t *)&tlv->info_string[2];
274
275 capabilities = decode_tlv_system_capabilities(htons(*system_capabilities), htons(*enabled_capabilities));
276
277 strncat(result, capabilities, 2048);
278
279 free(capabilities);
280
281 }break;
282 case MANAGEMENT_ADDRESS_TLV:
283 {
284 //char *management_address = NULL;
285 char *management_address = decode_management_address(tlv);
286
287 if(management_address != NULL) {
288
289 strncat(result, management_address, 2048);
290
291 free(management_address);
292 } else {
293 debug_hex_strcat((uint8_t *)result, tlv->info_string, tlv->length - 1);
294 }
295
296 }break;
297 case ORG_SPECIFIC_TLV:
298 {
299 char *org_specific = decode_organizationally_specific_tlv(tlv);
300
301 debug_hex_strcat((uint8_t *)result, tlv->info_string, tlv->length - 1);
302
303 free(org_specific);
304 }break;
305 case END_OF_LLDPDU_TLV:
306 {
307 ; // Don't do anything here
308 }break;
309 default:
310 debug_printf(DEBUG_NORMAL, "Hit default case\n");
311
312 debug_printf(DEBUG_NORMAL, "Got unrecognized type '%d'\n", tlv->type);
313 debug_hex_strcat((uint8_t *)result, tlv->info_string, tlv->length - 1);
314 };
315
316 // strncat(result, "\n", 2048);
317
318 return result;
319 }
320
decode_organizationally_specific_tlv(struct lldp_tlv * tlv)321 char *decode_organizationally_specific_tlv(struct lldp_tlv *tlv) {
322 #ifndef WIN32
323 #warning Not implemented
324 #endif // WIN32
325
326 return NULL;
327 }
328
interface_subtype_name(uint8_t subtype)329 char *interface_subtype_name(uint8_t subtype) {
330
331 switch(subtype) {
332 case 1:
333 return strdup("Unknown");
334 break;
335 case 2:
336 return strdup("ifIndex");
337 break;
338 case 3:
339 return strdup("System Port Number");
340 break;
341 default:
342 return strdup("Invalid Subtype");
343 }
344 }
345
346 // http://www.iana.org/assignments/address-family-numbers
decode_iana_address_family(uint8_t family)347 char *decode_iana_address_family(uint8_t family) {
348 switch(family)
349 {
350 case IANA_RESERVED_LOW:
351 #warning - IANA_RESERVED_HIGH is defined as 65536, which is too big for uint8_t, so am I using the wrong type, or should it be 255?
352 case IANA_RESERVED_HIGH:
353 return strdup("Reserved");
354 case IANA_IP:
355 return strdup("IPv4");
356 case IANA_IP6:
357 return strdup("IPv6");
358 case IANA_NSAP:
359 return strdup("NSAP");
360 case IANA_HDLC:
361 return strdup("HDLC (8-bit multidrop)");
362 case IANA_BBN_1822:
363 return strdup("BBN 1822");
364 case IANA_E_163:
365 return strdup("E.163");
366 case IANA_E_164_ATM:
367 return strdup("E.164 (SMDS, Frame Relay, ATM)");
368 case IANA_F_69:
369 return strdup("F.69 (Telex)");
370 case IANA_X_121:
371 return strdup("X.121 (X.25, Frame Relay)");
372 case IANA_IPX:
373 return strdup("IPX");
374 case IANA_APPLETALK:
375 return strdup("Appletalk");
376 case IANA_DECNET_IV:
377 return strdup("Decnet IV");
378 case IANA_BANYAN_VINES:
379 return strdup("Banyan Vines");
380 case IANA_E_164_NSAP:
381 return strdup("E.164 with NSAP format subaddress");
382 case IANA_DNS:
383 return strdup("DNS (Domain Name System)");
384 case IANA_DISTINGUISHED:
385 return strdup("Distinguished Name");
386 case IANA_AS_NUMBER:
387 return strdup("AS Number");
388 case IANA_XTP_IPV4:
389 return strdup("XTP over IP version 4");
390 case IANA_XTP_IPV6:
391 return strdup("XTP over IP version 6");
392 case IANA_FIBRE_PORT_NAME:
393 return strdup("Fibre Channel World-Wide Port Name");
394 case IANA_FIBRE_NODE_NAME:
395 return strdup("Fibre Channel World-Wide Node name");
396 case IANA_GWID:
397 return strdup("GWID");
398 case IANA_AFI_L2VPN:
399 return strdup("AFI for L2VPN information");
400 default:
401 return strdup("Unassigned");
402 }
403 }
404
decode_network_address(uint8_t * network_address)405 char *decode_network_address(uint8_t *network_address) {
406 char *result = NULL;
407 uint8_t addr_len = 0;
408 uint8_t subtype = 0;
409 char *addr_family = NULL;
410 uint8_t *addr = NULL;
411 uint8_t *tmp = NULL;
412
413 if(network_address == NULL)
414 return NULL;
415
416 addr_len = network_address[0];
417 subtype = network_address[1];
418 addr = &network_address[2];
419 addr_family = decode_iana_address_family(subtype);
420
421 if(addr_family == NULL) {
422 debug_printf(DEBUG_NORMAL, "NULL Address Family in %s\n", __FUNCTION__);
423 return NULL;
424 }
425
426 result = calloc(1, 2048);
427
428 sprintf(result, "%s - ", addr_family);
429
430 free(addr_family);
431
432 switch(subtype)
433 {
434 case IANA_IP:
435 {
436 if(addr_len == 5) {
437 tmp = calloc(1, 16);
438
439 sprintf((char *)tmp, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
440
441 strncat(result, (char *)tmp, 2048);
442
443 free(tmp);
444 } else {
445 debug_printf(DEBUG_NORMAL, "Invalid IPv4 address length: %d\n", addr_len);
446 debug_hex_strcat((uint8_t *)result, addr, addr_len - 1);
447 }
448 }break;
449 default:
450 debug_hex_strcat((uint8_t *)result, addr, addr_len - 1);
451 }
452
453 return result;
454 }
455
decode_management_address(struct lldp_tlv * tlv)456 char *decode_management_address(struct lldp_tlv *tlv){
457 uint8_t addr_len = tlv->info_string[0];
458 //uint8_t subtype = tlv->info_string[1];
459 //uint8_t *addr = &tlv->info_string[2];
460 uint8_t interface_subtype = tlv->info_string[addr_len + 1];
461 char *if_subtype_name = NULL;
462 uint32_t *interface_number = (uint32_t *)&tlv->info_string[addr_len + 2];
463 uint8_t oid_length = tlv->info_string[addr_len + 6];
464 char *oid_string = NULL;
465 char *addr_buf = NULL;
466 char *result = calloc(1, 2048);
467
468 if(oid_length == 0) {
469 oid_string = strdup("Standard LLDP MIB");
470 } else {
471 oid_string = strdup("Proprietary MIB");
472 }
473
474 if_subtype_name = interface_subtype_name(interface_subtype);
475
476 addr_buf = decode_network_address(&tlv->info_string[0]);
477
478 sprintf(result, "%s (%s - %d) (OID: %s)",
479 addr_buf,
480 if_subtype_name,
481 (*interface_number),
482 oid_string
483 );
484
485 free(addr_buf);
486 free(oid_string);
487 free(if_subtype_name);
488
489 return result;
490 }
491
492
decode_tlv_system_capabilities(uint16_t system_capabilities,uint16_t enabled_capabilities)493 char *decode_tlv_system_capabilities( uint16_t system_capabilities, uint16_t enabled_capabilities)
494 {
495 int capability = 0;
496 char *result = calloc(1, 2048);
497 char *capability_string = calloc(1, 2048);
498
499 // sprintf(result, "System Capabilities: %02X, Enabled Capabilities: %02X\n", system_capabilities, enabled_capabilities);
500 //sprintf(result, "System Capabilities: \n");
501
502 //debug_printf(DEBUG_TLV, "System Capabilities: %02X, Enabled Capabilities: %02X\n", system_capabilities, enabled_capabilities);
503
504 //strncat(result, "\t\tCapabilities:", 2048);
505
506 //debug_printf(DEBUG_TLV, "Capabilities:\n");
507
508 for(capability = 1; capability <= 65535; capability *= 2)
509 {
510 memset(capability_string, 0x0, 2048);
511
512 if((system_capabilities & capability))
513 {
514 if(enabled_capabilities & capability)
515 {
516 //debug_printf(DEBUG_TLV, "%s (enabled)\n", capability_name(capability));
517 sprintf(capability_string, "\n\t\t\t\t%s (enabled)", capability_name(capability));
518 strncat(result, capability_string, 2048);
519 }
520 else
521 {
522 //debug_printf(DEBUG_TLV, "%s (disabled)\n", capability_name(capability));
523 sprintf(capability_string, "\n\t\t\t\t%s (disabled)", capability_name(capability));
524 strncat(result, capability_string, 2048);
525 }
526 }
527 }
528
529 free(capability_string);
530
531 return result;
532 }
533
capability_name(uint16_t capability)534 char *capability_name(uint16_t capability)
535 {
536 switch(capability)
537 {
538 case SYSTEM_CAPABILITY_OTHER:
539 return "Other";
540 case SYSTEM_CAPABILITY_REPEATER:
541 return "Repeater/Hub";
542 case SYSTEM_CAPABILITY_BRIDGE:
543 return "Bridge/Switch";
544 case SYSTEM_CAPABILITY_WLAN:
545 return "Wireless LAN";
546 case SYSTEM_CAPABILITY_ROUTER:
547 return "Router";
548 case SYSTEM_CAPABILITY_TELEPHONE:
549 return "Telephone";
550 case SYSTEM_CAPABILITY_DOCSIS:
551 return "DOCSIS/Cable Modem";
552 case SYSTEM_CAPABILITY_STATION:
553 return "Station";
554 default:
555 return "Unknown";
556 };
557 }
558
559
tlv_typetoname(uint8_t tlv_type)560 char *tlv_typetoname(uint8_t tlv_type)
561 {
562 switch(tlv_type)
563 {
564 case CHASSIS_ID_TLV:
565 return "Chassis ID";
566 break;
567 case PORT_ID_TLV:
568 return "Port ID";
569 break;
570 case TIME_TO_LIVE_TLV:
571 return "Time To Live";
572 break;
573 case PORT_DESCRIPTION_TLV:
574 return "Port Description";
575 break;
576 case SYSTEM_NAME_TLV:
577 return "System Name";
578 break;
579 case SYSTEM_DESCRIPTION_TLV:
580 return "System Description";
581 break;
582 case SYSTEM_CAPABILITIES_TLV:
583 return "System Capabiltiies";
584 break;
585 case MANAGEMENT_ADDRESS_TLV:
586 return "Management Address";
587 break;
588 case ORG_SPECIFIC_TLV:
589 return "Organizationally Specific";
590 break;
591 case END_OF_LLDPDU_TLV:
592 return "End Of LLDPDU";
593 break;
594 default:
595 return "Unknown";
596 };
597 }
598
tlvInitializeLLDP(struct lldp_port * lldp_port)599 uint8_t tlvInitializeLLDP(struct lldp_port *lldp_port)
600 {
601 return 0;
602 }
603
tlvCleanupLLDP()604 void tlvCleanupLLDP()
605 {
606
607 }
608
609
initializeTLVFunctionValidators()610 uint8_t initializeTLVFunctionValidators()
611 {
612 int index = 0;
613
614 /* Set all of the reserved TLVs to NULL validator functions */
615 /* so they're forced to go through the generic validator */
616 for(index = LLDP_BEGIN_RESERVED_TLV; index < LLDP_END_RESERVED_TLV; index++)
617 {
618 //debug_printf(DEBUG_EXCESSIVE, "Setting TLV Validator '%d' to NULL - it's reserved\n", index);
619
620 validate_tlv[index] = NULL;
621 }
622
623 debug_printf(DEBUG_EXCESSIVE, "Setting TLV Validator '%d' - it's the organizational specific TLV validator...\n", ORG_SPECIFIC_TLV);
624
625 validate_tlv[ORG_SPECIFIC_TLV] = validate_organizationally_specific_tlv;
626
627 return 0;
628 }
629
initialize_tlv()630 struct lldp_tlv *initialize_tlv() {
631 struct lldp_tlv *tlv = (struct lldp_tlv *)calloc(1, sizeof(struct lldp_tlv));
632
633 return tlv;
634 }
635
636
637
create_end_of_lldpdu_tlv(struct lldp_port * lldp_port)638 struct lldp_tlv *create_end_of_lldpdu_tlv(struct lldp_port *lldp_port) {
639
640 struct lldp_tlv* tlv = initialize_tlv();
641
642 tlv->type = END_OF_LLDPDU_TLV; // Constant defined in lldp_tlv.h
643 tlv->length = 0; // The End of LLDPDU TLV is length 0.
644
645 tlv->info_string = NULL;
646
647 return tlv;
648 }
649
validate_end_of_lldpdu_tlv(struct lldp_tlv * tlv)650 uint8_t validate_end_of_lldpdu_tlv(struct lldp_tlv *tlv)
651 {
652 if(tlv->length != 0)
653 {
654 debug_printf(DEBUG_NORMAL, "[ERROR] TLV type is 'End of LLDPDU' (0), but TLV length is %d when it should be 0!\n", tlv->length);
655
656 return XEINVALIDTLV;
657 }
658
659 return XVALIDTLV;
660 }
661
validate_length_max_255(struct lldp_tlv * tlv)662 uint8_t validate_length_max_255(struct lldp_tlv *tlv)
663 {
664 //Length will never be below 0 because the variable used is unsigned...
665 if(tlv->length > 255)
666 {
667 debug_printf(DEBUG_NORMAL, "[ERROR] TLV has invalid length '%d'.\n\tIt should be between 0 and 255 inclusive!\n", tlv->length);
668
669 return XEINVALIDTLV;
670 }
671
672 return XVALIDTLV;
673 }
674
validate_length_max_256(struct lldp_tlv * tlv)675 uint8_t validate_length_max_256(struct lldp_tlv *tlv)
676 {
677 if(tlv->length < 2 || tlv->length > 256)
678 {
679 debug_printf(DEBUG_NORMAL, "[ERROR] TLV has invalid length '%d'.\n\tIt should be between 2 and 256 inclusive!\n", tlv->length);
680
681 return XEINVALIDTLV;
682 }
683
684 return XVALIDTLV;
685 }
686
create_chassis_id_tlv_invalid_length(struct lldp_port * lldp_port)687 struct lldp_tlv *create_chassis_id_tlv_invalid_length(struct lldp_port *lldp_port) {
688
689 struct lldp_tlv* tlv = initialize_tlv();
690
691 tlv->type = CHASSIS_ID_TLV; // Constant defined in lldp_tlv.h
692 tlv->length = 7; //The size of a MAC + the size of the subtype (1 byte)
693
694 tlv->info_string = calloc(1, tlv->length);
695
696 // CHASSIS_ID_MAC_ADDRESS is a 1-byte value - 4 in this case. Defined in lldp_tlv.h
697 tlv->info_string[0] = CHASSIS_ID_MAC_ADDRESS;
698
699 // We need to start copying at the 2nd byte, so we use [1] here...
700 // This reads "memory copy to the destination at the address of tlv->info_string[1] with the source my_mac for 6 bytes" (the size of a MAC address)
701 memcpy(&tlv->info_string[1], &lldp_port->source_mac[0], 6);
702
703 return tlv;
704 }
705
create_chassis_id_tlv(struct lldp_port * lldp_port)706 struct lldp_tlv *create_chassis_id_tlv(struct lldp_port *lldp_port) {
707
708 struct lldp_tlv* tlv = initialize_tlv();
709
710 tlv->type = CHASSIS_ID_TLV; // Constant defined in lldp_tlv.h
711 tlv->length = 7; //The size of a MAC + the size of the subtype (1 byte)
712
713 tlv->info_string = calloc(1, tlv->length);
714
715 // CHASSIS_ID_MAC_ADDRESS is a 1-byte value - 4 in this case. Defined in lldp_tlv.h
716 tlv->info_string[0] = CHASSIS_ID_MAC_ADDRESS;
717
718 // We need to start copying at the 2nd byte, so we use [1] here...
719 // This reads "memory copy to the destination at the address of tlv->info_string[1] with the source my_mac for 6 bytes" (the size of a MAC address)
720 memcpy(&tlv->info_string[1], &lldp_port->source_mac[0], 6);
721
722 return tlv;
723 }
724
validate_chassis_id_tlv(struct lldp_tlv * tlv)725 uint8_t validate_chassis_id_tlv(struct lldp_tlv *tlv)
726 {
727 // Several TLVs have this requirement.
728 return validate_length_max_256(tlv);
729 }
730
create_port_id_tlv(struct lldp_port * lldp_port)731 struct lldp_tlv *create_port_id_tlv(struct lldp_port *lldp_port) {
732
733 struct lldp_tlv* tlv = initialize_tlv();
734
735 tlv->type = PORT_ID_TLV; // Constant defined in lldp_tlv.h
736 tlv->length = 1 + strlen(lldp_port->if_name); //The length of the interface name + the size of the subtype (1 byte)
737
738 tlv->info_string = calloc(1, tlv->length);
739
740 // PORT_ID_INTERFACE_NAME is a 1-byte value - 5 in this case. Defined in lldp_tlv.h
741 tlv->info_string[0] = PORT_ID_INTERFACE_NAME;
742
743
744 // We need to start copying at the 2nd byte, so we use [1] here...
745 // This reads "memory copy to the destination at the address of tlv->info_string[1] with the source lldp_port->if_name for strlen(lldp_port->if_name) bytes"
746 memcpy(&tlv->info_string[1], lldp_port->if_name, strlen(lldp_port->if_name));
747
748 return tlv;
749 }
750
validate_port_id_tlv(struct lldp_tlv * tlv)751 uint8_t validate_port_id_tlv(struct lldp_tlv *tlv)
752 {
753 // Several TLVs have this requirement.
754 return validate_length_max_256(tlv);
755 }
756
create_ttl_tlv(struct lldp_port * lldp_port)757 struct lldp_tlv *create_ttl_tlv(struct lldp_port *lldp_port) {
758
759 struct lldp_tlv* tlv = initialize_tlv();
760 uint16_t ttl = htons(lldp_port->tx.txTTL);
761
762 tlv->type = TIME_TO_LIVE_TLV; // Constant defined in lldp_tlv.h
763 tlv->length = 2; // Static length defined by IEEE 802.1AB section 9.5.4
764
765 tlv->info_string = calloc(1, tlv->length);
766
767 memcpy(tlv->info_string, &ttl, tlv->length);
768
769 return tlv;
770 }
771
validate_ttl_tlv(struct lldp_tlv * tlv)772 uint8_t validate_ttl_tlv(struct lldp_tlv *tlv)
773 {
774 if(tlv->length != 2)
775 {
776 debug_printf(DEBUG_NORMAL, "[ERROR] TLV has invalid length '%d'.\n\tLength should be '2'.\n", tlv->length);
777
778 return XEINVALIDTLV;
779 }
780
781 return XVALIDTLV;
782 }
783
create_port_description_tlv(struct lldp_port * lldp_port)784 struct lldp_tlv *create_port_description_tlv(struct lldp_port *lldp_port) {
785
786 struct lldp_tlv* tlv = initialize_tlv();
787
788 tlv->type = PORT_DESCRIPTION_TLV; // onstant defined in lldp_tlv.h
789 tlv->length = strlen(lldp_port->if_name);
790
791 tlv->info_string = calloc(1, tlv->length);
792
793 memcpy(&tlv->info_string[0], lldp_port->if_name, strlen(lldp_port->if_name));
794
795 return tlv;
796
797 }
798
799
validate_port_description_tlv(struct lldp_tlv * tlv)800 uint8_t validate_port_description_tlv(struct lldp_tlv *tlv)
801 {
802 // Several TLVs have this requirement.
803 return validate_length_max_255(tlv);
804 }
805
create_system_name_tlv(struct lldp_port * lldp_port)806 struct lldp_tlv *create_system_name_tlv(struct lldp_port *lldp_port)
807 {
808
809 struct lldp_tlv* tlv = initialize_tlv();
810
811 tlv->type = SYSTEM_NAME_TLV; // Constant defined in lldp_tlv.h
812 tlv->length = strlen(lldp_systemname);
813
814 tlv->info_string = calloc(1, tlv->length);
815
816 memcpy(tlv->info_string, lldp_systemname, tlv->length);
817
818 return tlv;
819 }
820
validate_system_name_tlv(struct lldp_tlv * tlv)821 uint8_t validate_system_name_tlv(struct lldp_tlv *tlv)
822 {
823 // Several TLVs have this requirement.
824 return validate_length_max_255(tlv);
825 }
826
create_system_description_tlv(struct lldp_port * lldp_port)827 struct lldp_tlv *create_system_description_tlv(struct lldp_port *lldp_port)
828 {
829
830 struct lldp_tlv* tlv = initialize_tlv();
831
832 tlv->type = SYSTEM_DESCRIPTION_TLV; // Constant defined in lldp_tlv.h
833
834 tlv->length = strlen(lldp_systemdesc);
835
836 tlv->info_string = calloc(1, tlv->length);
837
838 memcpy(tlv->info_string, lldp_systemdesc, tlv->length);
839
840 return tlv;
841
842 }
843
validate_system_description_tlv(struct lldp_tlv * tlv)844 uint8_t validate_system_description_tlv(struct lldp_tlv *tlv)
845 {
846 // Several TLVs have this requirement.
847 return validate_length_max_255(tlv);
848 }
849
create_system_capabilities_tlv(struct lldp_port * lldp_port)850 struct lldp_tlv *create_system_capabilities_tlv(struct lldp_port *lldp_port) {
851 struct lldp_tlv* tlv = initialize_tlv();
852 // Tell it we're a station for now... bit 7
853 uint16_t capabilities = htons(128);
854
855 tlv->type = SYSTEM_CAPABILITIES_TLV; // Constant defined in lldp_tlv.h
856
857 tlv->length = 4;
858
859 tlv->info_string = calloc(1, tlv->length);
860
861 memcpy(&tlv->info_string[0], &capabilities, sizeof(uint16_t));
862 memcpy(&tlv->info_string[2], &capabilities, sizeof(uint16_t));
863
864 return tlv;
865 }
866
validate_system_capabilities_tlv(struct lldp_tlv * tlv)867 uint8_t validate_system_capabilities_tlv(struct lldp_tlv *tlv)
868 {
869 if(tlv->length != 4)
870 {
871 debug_printf(DEBUG_NORMAL, "[ERROR] TLV has invalid length '%d'.\n\tLength should be '4'.\n", tlv->length);
872
873 return XEINVALIDTLV;
874 }
875
876 return XVALIDTLV;
877 }
878
879 // NB: Initial deployment will do IPv4 only...
880 //
create_management_address_tlv(struct lldp_port * lldp_port)881 struct lldp_tlv *create_management_address_tlv(struct lldp_port *lldp_port) {
882 struct lldp_tlv *tlv = initialize_tlv();
883 uint32_t if_index = lldp_port->if_index;
884
885 tlv->type = MANAGEMENT_ADDRESS_TLV; // Constant defined in lldp_tlv.h
886
887 #define MGMT_ADDR_STR_LEN 1
888 #define MGMT_ADDR_SUBTYPE 1
889 #define IPV4_LEN 4
890 #define IF_NUM_SUBTYPE 1
891 #define IF_NUM 4
892 #define OID 1
893 #define OBJ_IDENTIFIER 0
894
895 // management address string length (1 octet)
896 // management address subtype (1 octet)
897 // management address (4 bytes for IPv4)
898 // interface numbering subtype (1 octet)
899 // interface number (4 bytes)
900 // OID string length (1 byte)
901 // object identifier (0 to 128 octets)
902 tlv->length = MGMT_ADDR_STR_LEN + MGMT_ADDR_SUBTYPE + IPV4_LEN + IF_NUM_SUBTYPE + IF_NUM + OID + OBJ_IDENTIFIER ;
903
904 //uint64_t tlv_offset = 0;
905
906 tlv->info_string = calloc(1, tlv->length);
907
908 // Management address string length
909 // subtype of 1 byte + management address length, so 5 for IPv4
910 tlv->info_string[0] = 5;
911
912 // 1 for IPv4 as per http://www.iana.org/assignments/address-family-numbers
913 tlv->info_string[1] = 1;
914
915 // Copy in our IP
916 memcpy(&tlv->info_string[2], lldp_port->source_ipaddr, 4);
917
918 // Interface numbering subtype... system port number in our case.
919 tlv->info_string[6] = 3;
920
921 // Interface number... 4 bytes long, or uint32_t
922 memcpy(&tlv->info_string[7], &lldp_port->if_index, sizeof(uint32_t));
923
924 debug_printf(DEBUG_NORMAL, "Would stuff interface #: %d\n", if_index);
925
926 // OID - 0 for us
927 tlv->info_string[11] = 0;
928
929 // object identifier... doesn't exist for us because it's not required, and we don't have an OID.
930
931 return tlv;
932 }
933
validate_management_address_tlv(struct lldp_tlv * tlv)934 uint8_t validate_management_address_tlv(struct lldp_tlv *tlv)
935 {
936 if(tlv->length < 9 || tlv->length > 167)
937 {
938 debug_printf(DEBUG_NORMAL, "[ERROR] TLV has invalid length '%d'.\n\tIt should be between 9 and 167 inclusive!\n", tlv->length);
939
940 return XEINVALIDTLV;
941 }
942
943 return XVALIDTLV;
944 }
945
946
947
948
949 //***********************************
950 //*LLDP-MED Location Indentification*
951 //***********************************
952
create_lldpmed_location_identification_tlv(struct lldp_port * lldp_port)953 struct lldp_tlv *create_lldpmed_location_identification_tlv (struct lldp_port *lldp_port)
954 {
955 int j;
956 int len = 0;
957 int pos = 0;
958 struct lldp_tlv *tlv = initialize_tlv();
959
960
961 //just 1, 2 or 3 is allowed for location data format, 0 is invalid, 4-255 is reserved for future use
962 if ((lci.location_data_format < 1) || (lci.location_data_format > 3))
963 {
964 debug_printf (DEBUG_NORMAL, "[ERROR] in config file: invalid location_data_format '%d' \n", lci.location_data_format);
965
966 free(tlv);
967
968 return NULL;
969 }
970
971 //set CATypes with no content "" to NULL, otherwise CAType with length 0 is created
972 for (j = 0; j < 33; j++)
973 {
974 if ((lci.civic_ca[j] != NULL) && (strcmp (lci.civic_ca[j], "") == 0))
975 lci.civic_ca[j] = NULL;
976 }
977
978 //calculate LCI Length for Civic Location
979 if (lci.location_data_format == LCI_CIVIC)
980 {
981 for (j = 0; j < 33; j++)
982 {
983 //printf ("%i\n", j);
984 //(strlen(civic_ca[j]) > 0) &&
985 if ((lci.civic_ca[j] != NULL))
986 len += strlen (lci.civic_ca[j]) + 1 + 1;//length of CAvalue + CAtype + CAlength
987 }
988 len += 1 + 2;//add len for What and Countrycode
989 tlv->length = 1 + len + 4 + 1;//1 for the LCI length field, LCI length plus 4 for the MED Header and 1 for Location Data Format
990 }
991
992 //length for coordinate based
993 if (lci.location_data_format == LCI_COORDINATE)
994 {
995 int tmp = strlen (lci.coordinate_based_lci) / 2;
996 if (tmp == 23)
997 debug_printf (DEBUG_NORMAL, "Coordinate based LCI contains colons\n");
998
999 if ((tmp != 16) && (tmp != 23))
1000 debug_printf (DEBUG_NORMAL, "coordinate_based_lci has wrong length '%d' \n", tmp);
1001
1002 tlv->length = 16 + 5;//MED Header (5) + geo location is always 16
1003 //printf ("geo loc data length calculated = %i \n", tlv->length);
1004 }
1005
1006 //length for ELIN
1007 if (lci.location_data_format == LCI_ELIN)
1008 tlv->length = strlen (lci.elin) + 5;
1009
1010 tlv->type = ORG_SPECIFIC_TLV;
1011
1012 tlv->info_string = calloc(1, tlv->length);
1013
1014 //MED-Header
1015 tlv->info_string[0] = 0x00;
1016 tlv->info_string[1] = 0x12;
1017 tlv->info_string[2] = 0xBB;
1018 tlv->info_string[3] = 3;
1019
1020 //set Location Data Format
1021 tlv->info_string[4] = lci.location_data_format;
1022
1023
1024 //--------------------
1025 // create Location ID
1026 //--------------------
1027
1028 //handle civic location LCI
1029 if (lci.location_data_format == 2)
1030 {
1031 tlv->info_string[5] = len;//LCI Length
1032 tlv->info_string[6] = lci.civic_what;
1033 tlv->info_string[7] = lci.civic_countrycode[0];
1034 tlv->info_string[8] = lci.civic_countrycode[1];
1035 pos = 9;
1036
1037 debug_printf (DEBUG_NORMAL, "create civic location identification TLV\n");
1038 //for(j = 0; j < 33; j++)
1039 //printf("CA typ %i len(%i) = %s \n", j, strlen(civic_ca[j]), civic_ca[j]);
1040 //printf("nr 12 %s",civic_ca[12]);
1041
1042 for (j = 0; j < 33; j++)
1043 {
1044 //(strlen(civic_ca[j]) > 1) &&
1045 if ((lci.civic_ca[j] != NULL))
1046 {
1047 int calength = strlen (lci.civic_ca[j]);
1048 debug_printf (DEBUG_NORMAL, "CA Type %i with len %i contains %s \n", j,
1049 calength, lci.civic_ca[j]);
1050 tlv->info_string[pos] = j;
1051 pos++;
1052 tlv->info_string[pos] = calength;
1053 pos++;
1054 memcpy(&tlv->info_string[pos], lci.civic_ca[j], calength);
1055 pos += calength;
1056 }
1057 }
1058 }
1059
1060 //handle ECS ELIN data format
1061 if (lci.location_data_format == 3)
1062 memcpy(&tlv->info_string[5], lci.elin, strlen(lci.elin));
1063
1064 //handling coordinate-based LCI
1065 if (lci.location_data_format == 1)
1066 {
1067 char temp[3];
1068 char out[17]; // binary location + string terminator
1069 char *in = calloc (1, strlen(lci.coordinate_based_lci) + 1);
1070 int i, u;
1071 int counter = 0;
1072 //remove colons from string
1073 for (u = 0; u < strlen (lci.coordinate_based_lci); u++)
1074 {
1075 if (lci.coordinate_based_lci[u] != ':')
1076 {
1077 in[counter] = lci.coordinate_based_lci[u];
1078 counter++;
1079 }
1080 }
1081
1082 in[32] = '\0'; // initialize string terminators
1083 out[16] = '\0';
1084 temp[2] = '\0';
1085
1086 debug_printf (DEBUG_NORMAL, "coordinate_based_lci: %s\n", lci.coordinate_based_lci);
1087 debug_printf (DEBUG_NORMAL, "coordinate_based without colons: %s \n", in);
1088
1089 //convert string to hex
1090 for (i = 0; i < 16; i++)
1091 {
1092 temp[0] = in[i * 2];
1093 temp[1] = in[i * 2 + 1];
1094 out[i] = (char) strtol (temp, NULL, 16);
1095 }
1096
1097 free (in);
1098
1099 debug_printf (DEBUG_NORMAL, "out: ");
1100 for (i = 0; i < 16; i++)
1101 {
1102 //proper output requires unsigned char cast
1103 debug_printf (DEBUG_NORMAL, "%02x", (unsigned char)out[i]);
1104 }
1105 debug_printf (DEBUG_NORMAL, "\n");
1106
1107 memcpy(&tlv->info_string[5], out, 16);
1108 }
1109
1110 return tlv;
1111 }
1112 //****************************LLDP-MED location identification end **************************
1113
1114
validate_organizationally_specific_tlv(struct lldp_tlv * tlv)1115 uint8_t validate_organizationally_specific_tlv(struct lldp_tlv *tlv)
1116 {
1117 if(tlv->length < 4 || tlv->length > 511)
1118 {
1119 debug_printf(DEBUG_NORMAL, "[ERROR] TLV has invalid length '%d'.\n\tIt should be between 4 and 511 inclusive!\n", tlv->length);
1120
1121 return XEINVALIDTLV;
1122 }
1123
1124 return XVALIDTLV;
1125 }
1126
validate_generic_tlv(struct lldp_tlv * tlv)1127 uint8_t validate_generic_tlv(struct lldp_tlv *tlv)
1128 {
1129 debug_printf(DEBUG_TLV, "Generic TLV Validation for TLV type: %d.\n", tlv->type);
1130 debug_printf(DEBUG_TLV, "TLV Info String Length: %d\n", tlv->length);
1131 debug_printf(DEBUG_TLV, "TLV Info String: ");
1132 debug_hex_dump(DEBUG_TLV, tlv->info_string, tlv->length);
1133
1134 // Length will never fall below 0 because it's an unsigned variable
1135 if(tlv->length > 511)
1136 {
1137 debug_printf(DEBUG_NORMAL, "[ERROR] TLV has invalid length '%d'.\n\tIt should be between 0 and 511 inclusive!\n", tlv->length);
1138
1139 return XEINVALIDTLV;
1140 }
1141
1142 return XVALIDTLV;
1143 }
1144
1145
1146
1147 // A helper function to explode a flattened TLV.
explode_tlv(struct lldp_flat_tlv * flat_tlv)1148 struct lldp_tlv *explode_tlv(struct lldp_flat_tlv *flat_tlv) {
1149
1150 uint16_t type_and_length = 0;
1151 struct lldp_tlv *tlv = NULL;
1152
1153 tlv = calloc(1, sizeof(struct lldp_tlv));
1154
1155 if(tlv) {
1156
1157 // Suck the type and length out...
1158 type_and_length = *(uint16_t *)&tlv[0];
1159
1160 tlv->length = type_and_length & 511;
1161 type_and_length = type_and_length >> 9;
1162 tlv->type = (uint8_t)type_and_length;
1163
1164 tlv->info_string = calloc(1, tlv->length);
1165
1166 if(tlv->info_string) {
1167 // Copy the info string into our TLV...
1168 memcpy(&tlv->info_string[0], &flat_tlv->tlv[sizeof(type_and_length)], tlv->length);
1169 } else { // tlv->info_string == NULL
1170 debug_printf(DEBUG_NORMAL, "[ERROR] Unable to malloc buffer in %s() at line: %d!\n", __FUNCTION__, __LINE__);
1171 }
1172 } else { // tlv == NULL
1173 debug_printf(DEBUG_NORMAL, "[ERROR] Unable to malloc buffer in %s() at line: %d!\n", __FUNCTION__, __LINE__);
1174 }
1175
1176 return tlv;
1177 }
1178
tlvcpy(struct lldp_tlv * dst,struct lldp_tlv * src)1179 uint8_t tlvcpy(struct lldp_tlv *dst, struct lldp_tlv *src)
1180 {
1181 if(src == NULL)
1182 return -1;
1183
1184 if(dst == NULL)
1185 return -1;
1186
1187 dst->type = src->type;
1188 dst->length = src->length;
1189 dst->info_string = calloc(1, dst->length);
1190
1191 if(((dst->info_string != NULL) && (src->info_string != NULL)))
1192 {
1193 memcpy(dst->info_string, src->info_string, dst->length);
1194 }
1195 else
1196 {
1197 debug_printf(DEBUG_NORMAL, "[ERROR] Couldn't allocate memory!!\n");
1198
1199 return -1;
1200 }
1201
1202 return 0;
1203 }
1204
tlvpop(uint8_t * buffer)1205 struct lldp_tlv *tlvpop(uint8_t *buffer)
1206 {
1207 return NULL;
1208 }
1209
tlvpush(uint8_t * buffer,struct lldp_tlv * tlv)1210 uint8_t tlvpush(uint8_t *buffer, struct lldp_tlv *tlv)
1211 {
1212 return -1;
1213 }
1214
lldp_cache_tlv(struct lldp_tlv * tlv)1215 uint8_t lldp_cache_tlv(struct lldp_tlv *tlv)
1216 {
1217 return -1;
1218 }
1219
tlv_info_string_to_cstr(struct lldp_tlv * tlv)1220 char *tlv_info_string_to_cstr(struct lldp_tlv *tlv)
1221 {
1222 char *cstr = NULL;
1223
1224 if(tlv == NULL)
1225 return NULL;
1226
1227 if(tlv->length <= 0)
1228 return NULL;
1229
1230 if(tlv->info_string == NULL)
1231 return NULL;
1232
1233 cstr = calloc(1, tlv->length + 1);
1234
1235 memcpy(cstr, tlv->info_string, tlv->length);
1236
1237 return cstr;
1238 }
1239