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