diff --git a/src/1905_tlvs.h b/src/1905_tlvs.h index 616815854e4b6442f1ad3a2dcf74f38db923f3c7..268180ba77746e9f7f7133bf054f9e47afb743d4 100644 --- a/src/1905_tlvs.h +++ b/src/1905_tlvs.h @@ -1,17 +1,44 @@ /* - * 1905_tlvs.h: IEEE-1905 TLV related functions + * 1905_tlvs.h: 1905 tlvs definition in flat format. */ #ifndef _1905_TLVS_H_ #define _1905_TLVS_H_ #include <stdint.h> -#include <stdbool.h> -#include <linux/types.h> - - +/* 1905 CMDU types */ +#define CMDU_TYPE_TOPOLOGY_DISCOVERY 0x0000 +#define CMDU_TYPE_TOPOLOGY_NOTIFICATION 0x0001 +#define CMDU_TYPE_TOPOLOGY_QUERY 0x0002 +#define CMDU_TYPE_TOPOLOGY_RESPONSE 0x0003 +#define CMDU_TYPE_VENDOR_SPECIFIC 0x0004 +#define CMDU_TYPE_LINK_METRIC_QUERY 0x0005 +#define CMDU_TYPE_LINK_METRIC_RESPONSE 0x0006 +#define CMDU_TYPE_AP_AUTOCONFIGURATION_SEARCH 0x0007 +#define CMDU_TYPE_AP_AUTOCONFIGURATION_RESPONSE 0x0008 +#define CMDU_TYPE_AP_AUTOCONFIGURATION_WSC 0x0009 +#define CMDU_TYPE_AP_AUTOCONFIGURATION_RENEW 0x000a +#define CMDU_TYPE_PUSH_BUTTON_EVENT_NOTIFICATION 0x000b +#define CMDU_TYPE_PUSH_BUTTON_JOIN_NOTIFICATION 0x000c +#define CMDU_TYPE_HIGHER_LAYER_QUERY 0x000d +#define CMDU_TYPE_HIGHER_LAYER_RESPONSE 0x000e +#define CMDU_TYPE_INTERFACE_POWER_CHANGE_REQUEST 0x000f +#define CMDU_TYPE_INTERFACE_POWER_CHANGE_RESPONSE 0x0010 +#define CMDU_TYPE_GENERIC_PHY_QUERY 0x0011 +#define CMDU_TYPE_GENERIC_PHY_RESPONSE 0x0012 +#define LAST_1905_CMDU CMDU_TYPE_GENERIC_PHY_RESPONSE + +#define CMDU_TYPE_MAX LAST_1905_CMDU +#define CMDU_TYPE_NONE 0xffff + +/* 1905 CMDU version */ +#define CMDU_MESSAGE_VERSION_1905_1_2013 0x00 + + + +/* 1905 TLV types */ #define TLV_TYPE_END_OF_MESSAGE (0) #define TLV_TYPE_AL_MAC_ADDRESS_TYPE (1) #define TLV_TYPE_MAC_ADDRESS_TYPE (2) @@ -63,7 +90,6 @@ #define MEDIA_TYPE_UNKNOWN (0xFFFF) - /* IEEE802.11 frequency bands */ #define IEEE80211_FREQUENCY_BAND_2_4_GHZ (0x00) #define IEEE80211_FREQUENCY_BAND_5_GHZ (0x01) @@ -86,7 +112,7 @@ typedef uint8_t macaddr_t[6]; /* TLV: End of message */ struct tlv_eom { -}; +} __attribute__((packed)); /* TLV: Vendor specific info */ struct tlv_vendor_specific { @@ -153,10 +179,9 @@ struct tlv_device_bridge_caps { } __attribute__((packed)); - struct non1905_neighbor { uint8_t macaddr[6]; -}; +} __attribute__((packed)); /* TLV: non-1905 neighbor devices */ struct tlv_non1905_neighbor { @@ -192,7 +217,7 @@ struct tlv_linkmetric_query { uint8_t nbr_type; uint8_t nbr_macaddr[6]; uint8_t query_type; -}; +} __attribute__((packed)); struct tx_link_info { uint8_t local_macaddr[6]; @@ -293,401 +318,176 @@ struct tlv_pbc_join_notification { - -//////////////////////////////////////////////////////////////////////////////// -// Generic PHY device information TLV associated structures ("Section 6.4.21") -//////////////////////////////////////////////////////////////////////////////// -// -/* Generic phy common structure used in "Tables 6.29, 6.36 and 6.38" */ -struct _genericPhyCommonData { +/* TLV: generic phy device information */ +struct generic_phy_data { uint8_t oui[3]; uint8_t variant_index; - uint8_t media_specific_bytes_nr; - uint8_t *media_specific_bytes; -}; - -struct _genericPhyDeviceEntries { - uint8_t local_interface_address[6]; - // MAC address of the local interface - - struct _genericPhyCommonData generic_phy_common_data; - // This structure contains the OUI, - // variant index and media specific - // information of the local interface - - uint8_t variant_name[32]; // Variant name UTF-8 string (NULL - // terminated) - - uint8_t generic_phy_description_xml_url_len; - char *generic_phy_description_xml_url; - // URL to the "Generic Phy XML Description - // Document" of the variant. - // The string is - // 'generic_phy_description_xml_url_len' - // bytes long including the final NULL - // character. - -}; -struct genericPhyDeviceInformationTypeTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_GENERIC_PHY_DEVICE_INFORMATION - - uint8_t al_mac_address[6]; // 1905 AL MAC address of the device - - uint8_t local_interfaces_nr; - struct _genericPhyDeviceEntries *local_interfaces; - // List of local interfaces that are - // going to be reported as - // MEDIA_TYPE_UNKNOWN -}; - -//////////////////////////////////////////////////////////////////////////////// -// Device identification type TLV associated structures ("Section 6.4.22") -//////////////////////////////////////////////////////////////////////////////// -struct deviceIdentificationTypeTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_DEVICE_IDENTIFICATION - - char friendly_name[64]; // Friendly name UTF-8 string (NULL - // terminated) - - char manufacturer_name[64]; // Manufacturer name UTF-8 string (NULL - // terminated) - - char manufacturer_model[64]; // Manufacturer modem UTF-8 string (NULL - // terminated) - -}; - -//////////////////////////////////////////////////////////////////////////////// -// Control URL type TLV associated structures ("Section 6.4.23") -//////////////////////////////////////////////////////////////////////////////// -struct controlUrlTypeTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_CONTROL_URL - - char *url; // Pointer to a NULL terminated string - // containing the URL to a control or - // WebUI of the device -}; - -//////////////////////////////////////////////////////////////////////////////// -// IPv4 type TLV associated structures ("Section 6.4.24") -//////////////////////////////////////////////////////////////////////////////// -struct _ipv4Entries { -#define IPV4_TYPE_UNKNOWN (0) -#define IPV4_TYPE_DHCP (1) -#define IPV4_TYPE_STATIC (2) -#define IPV4_TYPE_AUTOIP (3) - uint8_t type; // One of the values from above - - uint8_t ipv4_address[4]; // IPv4 address associated to the interface - - uint8_t ipv4_dhcp_server[4]; // IPv4 address of the DHCP server (if - // known, otherwise set to all zeros) -}; -struct _ipv4InterfaceEntries { - uint8_t mac_address[6]; // MAC address of the interface whose IPv4s - // are going to be reported. - // - // NOTE: The standard says it can also - // be an AL MAC address instead of an - // interface MAC address. - // In that case I guess *all* IPv4s of - // the device (no matter the interface - // they are "binded" to) are reported. - - uint8_t ipv4_nr; - struct _ipv4Entries *ipv4; // List of IPv4s associated to this - // interface -}; -struct ipv4TypeTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_IPV4 - - uint8_t ipv4_interfaces_nr; - struct _ipv4InterfaceEntries *ipv4_interfaces; - // List of interfaces with at least one - // IPv4 assigned -}; - -//////////////////////////////////////////////////////////////////////////////// -// IPv6 type TLV associated structures ("Section 6.4.25") -//////////////////////////////////////////////////////////////////////////////// -struct _ipv6Entries { -#define IPV6_TYPE_UNKNOWN (0) -#define IPV6_TYPE_DHCP (1) -#define IPV6_TYPE_STATIC (2) -#define IPV6_TYPE_SLAAC (3) - uint8_t type; // One of the values from above - - uint8_t ipv6_address[16]; // IPv6 address associated to the interface - - uint8_t ipv6_address_origin[16]; // If type == IPV6_TYPE_DHCP, this field - // contains the IPv6 address of the DHCPv6 - // server. - // If type == IPV6_TYPE_SLAAC, this field - // contains the IPv6 address of the router - // that provided the SLAAC address. - // In any other case this field is set to - // all zeros. -}; -struct _ipv6InterfaceEntries { - uint8_t mac_address[6]; // MAC address of the interface whose IPv4s - // are going to be reported. - // - // NOTE: The standard says it can also - // be an AL MAC address instead of an - // interface MAC address. - // In that case I guess *all* IPv4s of - // the device (no matter the interface - // they are "binded" to) are reported. - - uint8_t ipv6_link_local_address[16]; - // IPv6 link local address corresponding to - // this interface - - uint8_t ipv6_nr; - struct _ipv6Entries *ipv6; // List of IPv4s associated to this - // interface -}; + uint8_t variant_name[32]; + uint8_t sizeof_url; + uint8_t sizeof_mediainfo; + uint8_t url_plus_mediainfo[]; +} __attribute__((packed)); + +struct generic_phy_interface { + uint8_t macaddr[6]; + struct generic_phy_data data; +} __attribute__((packed)); + +struct tlv_generic_phy_devinfo { + uint8_t aladdr[6]; + uint8_t num_interfaces; + struct generic_phy_interface interface[]; +} __attribute__((packed)); + + +/* TLV: device identification */ +struct tlv_device_identification { + uint8_t name[64]; + uint8_t manufacturer[64]; + uint8_t model[64]; +} __attribute__((packed)); + + +/* TLV: control URL */ +struct tlv_control_url { + uint8_t url[0]; +} __attribute__((packed)); + + + +#define IPV4_TYPE_UNKNOWN 0 +#define IPV4_TYPE_DHCP 1 +#define IPV4_TYPE_STATIC 2 +#define IPV4_TYPE_AUTOIP 3 + +struct ipv4_entry { + uint8_t type; + uint8_t address[4]; + uint8_t dhcp_server[4]; +} __attribute__((packed)); + +struct ipv4_interface { + uint8_t macaddr[6]; + uint8_t num_ipv4; + struct ipv4_entry ipv4[]; +} __attribute__((packed)); + +/* TLV: IPv4 TLV */ +struct tlv_ipv4 { + uint8_t num_interfaces; + struct ipv4_interface interface[]; +} __attribute__((packed)); + + + + +#define IPV6_TYPE_UNKNOWN 0 +#define IPV6_TYPE_DHCP 1 +#define IPV6_TYPE_STATIC 2 +#define IPV6_TYPE_SLAAC 3 + +struct ipv6_entry { + uint8_t type; + uint8_t address[16]; + uint8_t origin[16]; +} __attribute__((packed)); + +struct ipv6_interface { + uint8_t macaddr[6]; + uint8_t link_local_address[16]; + uint8_t num_ipv6; + struct ipv6_entry ipv6[]; +} __attribute__((packed)); + +/* TLV: IPv6 TLV */ struct ipv6TypeTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_IPV6 - - uint8_t ipv6_interfaces_nr; - struct _ipv6InterfaceEntries *ipv6_interfaces; - // List of interfaces with at least one - // IPv6 assigned -}; - -//////////////////////////////////////////////////////////////////////////////// -// Push button generic PHY event notification TLV associated structures -// ("Section 6.4.26") -//////////////////////////////////////////////////////////////////////////////// -struct pushButtonGenericPhyEventNotificationTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_GENERIC_PHY_EVENT_NOTIFICATION - - uint8_t local_interfaces_nr; - struct _genericPhyCommonData *local_interfaces; - // List of local interfaces of type - // MEDIA_TYPE_UNKNOWN for which a push button - // configuration method has been activated on - // the device that originates the push button - // event notification -}; - -//////////////////////////////////////////////////////////////////////////////// -// Profile version TLV associated structures ("Section 6.4.27") -//////////////////////////////////////////////////////////////////////////////// -struct x1905ProfileVersionTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_1905_PROFILE_VERSION + uint8_t num_interfaces; + struct ipv6_interface interface[]; +} __attribute__((packed)); + + + +/* TLV: Push button generic PHY event notification */ +struct tlv_pbc_generic_phy_notification { + uint8_t num_genphys; + struct { + uint8_t oui[3]; + uint8_t variant_index; + uint8_t sizeof_mediainfo; + uint8_t mediainfo[]; + } genphy[]; +} __attribute__((packed)); + #define PROFILE_1905_1 (0x00) #define PROFILE_1905_1A (0x01) - uint8_t profile; // One of the values from above -}; - -//////////////////////////////////////////////////////////////////////////////// -// Power off interface TLV associated structures ("Section 6.4.28") -//////////////////////////////////////////////////////////////////////////////// -struct _powerOffInterfaceEntries { - uint8_t interface_address[6]; // MAC address of an interface in the - // "power off" state - - uint16_t media_type; // Underlaying network technology - // One of the MEDIA_TYPE_* values - - struct _genericPhyCommonData generic_phy_common_data; - // If 'media_type' is MEDIA_TYPE_UNKNOWN, - // this structure contains the vendor OUI, - // variant index and media specific - // information of the interface - // Otherwise, it is set to all zeros -}; -struct powerOffInterfaceTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_POWER_OFF_INTERFACE - - uint8_t power_off_interfaces_nr; - struct _powerOffInterfaceEntries *power_off_interfaces; - // List of local interfaces in the "power - // off" state. -}; - -//////////////////////////////////////////////////////////////////////////////// -// Interface power change information TLV associated structures ("Section -// 6.4.29") -//////////////////////////////////////////////////////////////////////////////// -struct _powerChangeInformationEntries { - uint8_t interface_address[6]; // MAC address of an interface in the - // "power off" state - -#define POWER_STATE_REQUEST_OFF (0x00) -#define POWER_STATE_REQUEST_ON (0x01) -#define POWER_STATE_REQUEST_SAVE (0x02) - uint8_t requested_power_state; // One of the values from above -}; -struct interfacePowerChangeInformationTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_INTERFACE_POWER_CHANGE_INFORMATION - - uint8_t power_change_interfaces_nr; - struct _powerChangeInformationEntries *power_change_interfaces; - // List of local interfaces for which a power - // status change is requested -}; - -//////////////////////////////////////////////////////////////////////////////// -// Interface power change status TLV associated structures ("Section 6.4.29") -//////////////////////////////////////////////////////////////////////////////// -struct _powerChangeStatusEntries { - uint8_t interface_address[6]; // MAC address of an interface in the - // "power off" state - -#define POWER_STATE_RESULT_COMPLETED (0x00) -#define POWER_STATE_RESULT_NO_CHANGE (0x01) -#define POWER_STATE_RESULT_ALTERNATIVE_CHANGE (0x02) - uint8_t result; // One of the values from above -}; -struct interfacePowerChangeStatusTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_INTERFACE_POWER_CHANGE_STATUS - - uint8_t power_change_interfaces_nr; - struct _powerChangeStatusEntries *power_change_interfaces; - // List of local interfaces whose power status - // change operation result is being reported -}; - -//////////////////////////////////////////////////////////////////////////////// -// L2 neighbor device TLV associated structures ("Section 6.4.31") -//////////////////////////////////////////////////////////////////////////////// -struct _l2NeighborsEntries { - uint8_t l2_neighbor_mac_address[6]; // MAC address of remote interface - // sharing the same L2 medium - - uint16_t behind_mac_addresses_nr; - uint8_t(*behind_mac_addresses)[6]; // List of MAC addresses the remote - // device (owner of the remote - // interface) "knows" and that are - // not visible on this interface. - // TODO: Define better !!! -}; -struct _l2InterfacesEntries { - uint8_t local_mac_address[6]; // MAC address of the local interface whose - // L2 neighbors are going to be reported - - uint16_t l2_neighbors_nr; - struct _l2NeighborsEntries *l2_neighbors; - // List of neighbors that share the same L2 - // medium as the local interface -}; -struct l2NeighborDeviceTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_L2_NEIGHBOR_DEVICE - - uint8_t local_interfaces_nr; - struct _l2InterfacesEntries *local_interfaces; - // List of interfaces with at least one - // IPv4 assigned -}; - - - -//////////////////////////////////////////////////////////////////////////////// -// Main API functions -//////////////////////////////////////////////////////////////////////////////// - -// This function receives a pointer to a stream of bytes representing a 1905 -// TLV according to "Section 6.4" -// -// It then returns a pointer to a structure whose fields have already been -// filled with the appropiate values extracted from the parsed stream. -// -// The actual type of the returned pointer structure depends on the value of -// the first byte pointed by "packet_stream" (ie. the "Type" field of the TLV): -// -// TLV_TYPE_END_OF_MESSAGE --> struct endOfMessageTLV * -// TLV_TYPE_VENDOR_SPECIFIC --> struct vendorSpecificTLV * -// TLV_TYPE_AL_MAC_ADDRESS_TYPE --> struct alMacAddressTypeTLV * -// TLV_TYPE_MAC_ADDRESS_TYPE --> struct macAddressTypeTLV * -// TLV_TYPE_DEVICE_INFORMATION_TYPE --> struct deviceInformationTypeTLV * -// TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES --> struct deviceBridgingCapabilityTLV * -// TLV_TYPE_NON_1905_NEIGHBOR_DEVICE_LIST --> struct non1905NeighborDeviceListTLV * -// TLV_TYPE_NEIGHBOR_DEVICE_LIST --> struct neighborDeviceListTLV * -// TLV_TYPE_LINK_METRIC_QUERY --> struct linkMetricQueryTLV * -// TLV_TYPE_TRANSMITTER_LINK_METRIC --> struct transmitterLinkMetricTLV * -// TLV_TYPE_RECEIVER_LINK_METRIC --> struct receiverLinkMetricTLV * -// TLV_TYPE_LINK_METRIC_RESULT_CODE --> struct linkMetricResultCodeTLV * -// TLV_TYPE_SEARCHED_ROLE --> struct searchedRoleTLV * -// TLV_TYPE_AUTOCONFIG_FREQ_BAND --> struct autoconfigFreqBandTLV * -// TLV_TYPE_SUPPORTED_ROLE --> struct supportedRoleTLV * -// TLV_TYPE_SUPPORTED_FREQ_BAND --> struct supportedFreqBandTLV * -// TLV_TYPE_WSC --> struct wscTLV * -// TLV_TYPE_PUSH_BUTTON_EVENT_NOTIFICATION --> struct pushButtonEventNotificationTLV * -// TLV_TYPE_PUSH_BUTTON_JOIN_NOTIFICATION --> struct pushButtonJoinNotificationTLV * -// -// If an error was encountered while parsing the stream, a NULL pointer is -// returned instead. -// Otherwise, the returned structure is dynamically allocated, and once it is -// no longer needed, the user must call the "free_1905_TLV_structure()" function -// -uint8_t *parse_1905_TLV_from_packet(uint8_t *packet_stream); - -// This is the opposite of "parse_1905_TLV_from_packet()": it receives a -// pointer to a TLV structure and then returns a pointer to a buffer which: -// - is a packet representation of the TLV -// -// "memory_structure" must point to a structure of one of the types returned by -// "parse_1905_TLV_from_packet()" -// -// If there is a problem this function returns NULL, otherwise the returned -// buffer must be later freed by the caller (it is a regular, non-nested buffer, -// so you just need to call "free()"). -// -// Note that the input structure is *not* freed. You still need to later call -// "free_1905_TLV_structure()" -// -uint8_t *forge_1905_TLV_from_structure(uint8_t *memory_structure); - -//////////////////////////////////////////////////////////////////////////////// -// Utility API functions -//////////////////////////////////////////////////////////////////////////////// - -// This function receives a pointer to a TLV structure and then traverses it -// and all nested structures, calling "free()" on each one of them -// -// "memory_structure" must point to a structure of one of the types returned by -// "parse_1905_TLV_from_packet()" -// -void free_1905_TLV_structure(uint8_t *memory_structure, bool all); - -// 'forge_1905_TLV_from_structure()' returns a regular buffer which can be freed -// using this macro defined to be FREE -// -#define free_1905_TLV_packet FREE - -// This function returns '0' if the two given pointers represent TLV structures -// of the same type and they contain the same data -// -// "memory_structure_1" and "memory_structure_2" must point (each) to a -// structure of one of the types returned by "parse_1905_TLV_from_packet()" -// -uint8_t compare_1905_TLV_structures(uint8_t *memory_structure_1, uint8_t *memory_structure_2); - -// Use this function for debug purposes. It turns a TLV_TYPE_* variable into its -// string representation. -// -// Example: TLV_TYPE_AL_MAC_ADDRESS_TYPE --> "TLV_TYPE_AL_MAC_ADDRESS_TYPE" -// -// Return "Unknown" if the provided type does not exist. -// -char *convert_1905_TLV_type_to_string(uint8_t tlv_type); - -char *convert_band_to_string(uint8_t freq_band); -bool get_freq_band_from_media_type(uint16_t media_type, uint8_t *freq_band); - -#endif + +/* TLV: 1905 profile version */ +struct tlv_1905_profile { + uint8_t version; +} __attribute__((packed)); + + +/* TLV: Power off interface */ +struct tlv_power_off { + uint8_t num_interfaces; + struct { + uint8_t macaddr[6]; + uint16_t media_type; + uint8_t oui[3]; + uint8_t variant_index; + uint8_t sizeof_mediainfo; + uint8_t mediainfo[]; + } interface[]; +} __attribute__((packed)); + + +#define POWER_REQUEST_OFF 0x00 +#define POWER_REQUEST_ON 0x01 +#define POWER_REQUEST_SAVE 0x02 + +/* TLV: interface power change information */ +struct tlv_powerchange_request { + uint8_t num_interfaces; + struct { + uint8_t macaddr[6]; + uint8_t power; + } interface[]; +} __attribute__((packed)); + + + +#define POWER_CHANGE_OK 0x00 +#define POWER_CHANGE_NOK 0x01 +#define POWER_CHANGE_ALT 0x02 + +/* TLV: interface power change status */ +struct tlv_powerchange_status { + uint8_t num_interfaces; + struct { + uint8_t macaddr[6]; + uint8_t status; + } interface[]; +} __attribute__((packed)); + + +/* TLV: L2 neighbor device */ +struct l2_interface_neighbor { + uint8_t macaddr[6]; + uint16_t num_behind_macs; + uint8_t behind_macaddrs[]; +} __attribute__((packed)); + +struct l2_interface { + uint8_t macaddr[6]; + uint16_t num_l2_neighbors; + struct l2_interface_neighbor l2_nbr[]; +} __attribute__((packed)); + +struct tlv_l2_neighbor { + uint8_t num_interfaces; + struct l2_interface interface[]; +} __attribute__((packed)); + + +#endif /* _1905_TLVS_H_ */ diff --git a/src/Makefile b/src/Makefile index 5796dccaaedf26e2605c0e4f57dfeca253c2ef58..6de4480bda7499022849cc71c8c9b5ad53e50a60 100644 --- a/src/Makefile +++ b/src/Makefile @@ -13,6 +13,7 @@ OBJS = cmdu.o \ main.o \ timer.o \ util.o \ + cmdu_ackq.o \ cmduqueue.o \ worker.o diff --git a/src/cmdu.c b/src/cmdu.c index 606d18848a7793aebfb29115c7b542692b6dc38e..9fd851e44f2f51ded0687b7d68fa5be9373fd12a 100644 --- a/src/cmdu.c +++ b/src/cmdu.c @@ -8,7 +8,8 @@ #include "util.h" #include "bufutil.h" -#include "1905_defs.h" +//#include "1905_defs.h" +#include "1905_tlvs.h" #include "cmdu.h" @@ -61,10 +62,20 @@ uint16_t tlv_total_length(struct tlv *t) uint16_t g_mid; +uint16_t cmdu_init_mid(void) +{ + uint8_t b[2]; + + get_random_bytes(2, b); + g_mid = *(uint16_t *)b; + + return (g_mid == 0) ? g_mid = 1 : g_mid; +} + uint16_t cmdu_get_next_mid(void) { - return g_mid++; + return (g_mid % 0xffff == 0) ? g_mid += 2: g_mid++; } int is_cmdu_type_valid(uint16_t type) @@ -73,7 +84,7 @@ int is_cmdu_type_valid(uint16_t type) type <= CMDU_TYPE_MAX); } -static int cmdu_should_relay(uint16_t type) +int cmdu_should_relay(uint16_t type) { return (type == CMDU_TYPE_TOPOLOGY_NOTIFICATION || type == CMDU_TYPE_AP_AUTOCONFIGURATION_SEARCH || @@ -82,6 +93,41 @@ static int cmdu_should_relay(uint16_t type) type == CMDU_TYPE_PUSH_BUTTON_JOIN_NOTIFICATION); } +int is_cmdu_type_response(uint16_t type) +{ + return (type == CMDU_TYPE_TOPOLOGY_RESPONSE || + type == CMDU_TYPE_LINK_METRIC_RESPONSE || + type == CMDU_TYPE_AP_AUTOCONFIGURATION_RESPONSE || + type == CMDU_TYPE_HIGHER_LAYER_RESPONSE || + type == CMDU_TYPE_INTERFACE_POWER_CHANGE_RESPONSE); +} + +uint16_t cmdu_expect_response(uint16_t req_type) +{ + switch (req_type) { + case CMDU_TYPE_TOPOLOGY_QUERY: + return CMDU_TYPE_TOPOLOGY_RESPONSE; + case CMDU_TYPE_LINK_METRIC_QUERY: + return CMDU_TYPE_LINK_METRIC_RESPONSE; + case CMDU_TYPE_AP_AUTOCONFIGURATION_SEARCH: + return CMDU_TYPE_AP_AUTOCONFIGURATION_RESPONSE; + case CMDU_TYPE_AP_AUTOCONFIGURATION_WSC: + return CMDU_TYPE_AP_AUTOCONFIGURATION_WSC; + case CMDU_TYPE_AP_AUTOCONFIGURATION_RENEW: + return CMDU_TYPE_AP_AUTOCONFIGURATION_RESPONSE; + case CMDU_TYPE_HIGHER_LAYER_QUERY: + return CMDU_TYPE_HIGHER_LAYER_RESPONSE; + case CMDU_TYPE_INTERFACE_POWER_CHANGE_REQUEST: + return CMDU_TYPE_INTERFACE_POWER_CHANGE_RESPONSE; + case CMDU_TYPE_GENERIC_PHY_QUERY: + return CMDU_TYPE_GENERIC_PHY_RESPONSE; + default: + break; + } + + return CMDU_TYPE_NONE; +} + struct cmdu_buff *cmdu_alloc(int size) { #define CMDU_RESERVE_HEADSPACE 32 diff --git a/src/cmdu.h b/src/cmdu.h index 5792134fa1bb48feb3d231d07c8686bff7812f52..7d33b4a3505189d86ca2ad57675c04e9efb99f9b 100644 --- a/src/cmdu.h +++ b/src/cmdu.h @@ -24,6 +24,8 @@ struct cmdu_header { #define CMDU_SET_LAST_FRAGMENT(c) (c)->hdr.flag |= 0x80 #define CMDU_SET_RELAY_MCAST(c) (c)->hdr.flag |= 0x40 +#define CMDU_DEFAULT_TIMEOUT 2000 + struct cmdu_linear { struct cmdu_header hdr; @@ -83,6 +85,11 @@ void cmdu_free(struct cmdu_buff *c); int cmdu_size(struct cmdu_buff *c); uint16_t cmdu_get_next_mid(void); +uint16_t cmdu_init_mid(void); +uint16_t cmdu_expect_response(uint16_t req_type); +int cmdu_should_relay(uint16_t type); +int is_cmdu_type_valid(uint16_t type); +int is_cmdu_type_response(uint16_t type); int cmdu_validate(struct cmdu_buff *c, int max_tlvtype, struct tlv_policy *policy); diff --git a/src/cmdu_ackq.c b/src/cmdu_ackq.c new file mode 100644 index 0000000000000000000000000000000000000000..9dd93d54ab8a4389b1eb7617c14a1866a1689703 --- /dev/null +++ b/src/cmdu_ackq.c @@ -0,0 +1,291 @@ +/* + * delm_cmdu_ackq.c + * CMDU response and ack queue management + * + * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: anjan.chanda@iopsys.eu + * + * See LICENSE file for license related information. + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> + +#include <easy/easy.h> + +#include "timer.h" +#include "cmdu_ackq.h" + +static int timeradd_msecs(struct timeval *a, unsigned long msecs, + struct timeval *res) +{ + if (res) { + struct timeval t = { 0 }; + + if (msecs > 1000) { + t.tv_sec += msecs / 1000; + t.tv_usec = (msecs % 1000) * 1000; + } else { + t.tv_usec = msecs * 1000; + } + + timeradd(a, &t, res); + return 0; + } + + return -1; +} + +struct cmdu_ackq_entry *cmdu_ackq_create_msg(uint16_t type, uint16_t mid, + uint8_t *dest, uint32_t timeout) +{ + struct cmdu_ackq_entry *msg; + struct timeval tsp = { 0 }; + + msg = calloc(1, sizeof(*msg)); + if (!msg) { + fprintf(stderr, "calloc failed. err = NOMEM\n"); + return NULL; + } + + msg->type = type; + msg->mid = mid; + gettimeofday(&tsp, NULL); + msg->ageing_time = timeout; + timeradd_msecs(&tsp, msg->ageing_time, &msg->ageing_tmo); + + //msg->ageing_tmo.tv_usec = roundup(msg->ageing_tmo.tv_usec, 1000); + msg->ageing_tmo.tv_usec = (msg->ageing_tmo.tv_usec / 1000) * 1000; + memcpy(msg->origin, dest, 6); + fprintf(stderr, + " CREATE msg: type = 0x%04x mid = %hu origin = " MACFMT " timeout = { %u (%lu:%lu) }\n", + type, mid, MAC2STR(dest), msg->ageing_time, msg->ageing_tmo.tv_sec, msg->ageing_tmo.tv_usec / 1000); + + return msg; +} + +static void cmdu_ackq_delete_msg(struct cmdu_ackq_entry *msg) +{ + if (msg) + free(msg); +} + +static void cmdu_ackq_ageout_entry(struct cmdu_ackq *st, struct hlist_head *head, + struct timeval *min_next_tmo) +{ + struct cmdu_ackq_entry *msg; + struct hlist_node *tmp; + struct timeval now = { 0 }; + + + gettimeofday(&now, NULL); + now.tv_usec = (now.tv_usec / 1000) * 1000; + + + hlist_for_each_entry_safe(msg, tmp, head, hlist) { + fprintf(stderr, "%s(): Entry msg->ageout = (%lu.%lu), now = (%lu.%lu)\n", + __func__, + msg->ageing_tmo.tv_sec, msg->ageing_tmo.tv_usec, + now.tv_sec, now.tv_usec); + + if (timercmp(&msg->ageing_tmo, &now, <=)) { + st->pending_cnt--; + hlist_del(&msg->hlist, head); + fprintf(stderr, "No response from " MACFMT " for CMDU 0x%x with mid = %hu\n", + MAC2STR(msg->origin), msg->mid, msg->type); + cmdu_ackq_delete_msg(msg); + } else { + struct timeval new_next_tmo = { 0 }; + + timersub(&msg->ageing_tmo, &now, &new_next_tmo); + if (!timercmp(min_next_tmo, &new_next_tmo, <)) { + min_next_tmo->tv_sec = new_next_tmo.tv_sec; + min_next_tmo->tv_usec = new_next_tmo.tv_usec; + /* fprintf("next-tmo = (%lu.%lu)\n", + * min_next_tmo->tv_sec, + * min_next_tmo->tv_usec); + */ + } + } + } +} + +static void cmdu_ackq_ageing_timer_run(atimer_t *t) +{ + struct cmdu_ackq *st = container_of(t, struct cmdu_ackq, ageing_timer); + //struct timeval *next_tmo = &st->next_tmo; + struct timeval min_next_tmo = { .tv_sec = 999999 }; + int remain_cnt = 0; + int i; + struct timeval nu; + + gettimeofday(&nu, NULL); + + fprintf(stderr, "\n ----Timer now = %lu.%lu --- cnt = %d---\n", + nu.tv_sec, nu.tv_usec, st->pending_cnt); + + //spin_lock(&st->hash_lock); + for (i = 0; i < CMDU_BACKLOG_MAX; i++) { + if (hlist_empty(&st->table[i])) + continue; + + fprintf(stderr, "i = %d\t", i); + cmdu_ackq_ageout_entry(st, &st->table[i], &min_next_tmo); + } + + remain_cnt = st->pending_cnt; + st->next_tmo.tv_sec = min_next_tmo.tv_sec; + st->next_tmo.tv_usec = min_next_tmo.tv_usec; + + //spin_unlock(&st->hash_lock); + if (remain_cnt) { + uint32_t tmo_msecs = + st->next_tmo.tv_sec * 1000 + st->next_tmo.tv_usec / 1000; + + /* printf("%s(): remain = %d next_tmo = {(%lu s, %lu us) %u}\n", + __func__, remain_cnt, next_tmo->tv_sec, next_tmo->tv_usec, tmo_msecs); */ + + if (tmo_msecs > 0) + timer_set(&st->ageing_timer, tmo_msecs); + } +} + +int cmdu_ackq_init(void *cmdu_q) +{ + struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q; + + memset(q, 0, sizeof(*q)); + pthread_mutex_init(&q->qlock, NULL); + timer_init(&q->ageing_timer, cmdu_ackq_ageing_timer_run); + + return 0; +} + +struct cmdu_ackq_entry *cmdu_ackq_lookup(void *cmdu_q, uint16_t type, + uint16_t mid, uint8_t *dest) +{ + struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q; + int idx = cmdu_ackq_hash(type, mid, dest); + struct cmdu_ackq_entry *msg = NULL; + + pthread_mutex_lock(&q->qlock); + hlist_for_each_entry(msg, &q->table[idx], hlist) { + if (msg->type == type && msg->mid == mid && + !memcmp(msg->origin, dest, 6)) { + + pthread_mutex_unlock(&q->qlock); + return msg; + } + } + pthread_mutex_unlock(&q->qlock); + + return NULL; +} + +void cmdu_ackq_reset(void *cmdu_q) +{ + struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q; + struct cmdu_ackq_entry *msg = NULL; + int idx = 0; + + fprintf(stderr, "Resetting CMDU Message Queue..\n"); + fprintf(stderr, "*****************************************\n"); + pthread_mutex_lock(&q->qlock); + for (idx = 0; idx < CMDU_BACKLOG_MAX; idx++) { + hlist_for_each_entry(msg, &q->table[idx], hlist) { + fprintf(stderr, "idx:%d, type:%d, mid:%d\n", idx, msg->type, msg->mid); + cmdu_ackq_delete_msg(msg); + } + q->table[idx].first = NULL; + } + fprintf(stderr, "*****************************************\n"); + + q->pending_cnt = 0; + pthread_mutex_unlock(&q->qlock); +} + + +/* In this function, type = cmdutype that is expected with 'mid' from 'dest' */ +int cmdu_ackq_enqueue(void *cmdu_q, uint16_t type, uint16_t mid, uint8_t *dest, + uint32_t timeout) +{ + struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q; + struct cmdu_ackq_entry *msg = NULL; + + msg = cmdu_ackq_lookup(cmdu_q, type, mid, dest); + if (msg) { + fprintf(stderr, + "Duplicate: type = 0x%04x mid = %hu origin = " MACFMT "\n", + type, mid, MAC2STR(dest)); + + return -1; + } + + msg = cmdu_ackq_create_msg(type, mid, dest, timeout); + if (msg) { + int idx = cmdu_ackq_hash(type, mid, dest); + + pthread_mutex_lock(&q->qlock); + hlist_add_head(&msg->hlist, &q->table[idx]); + + q->pending_cnt++; + fprintf(stderr, + "ENQ: type = 0x%04x mid = %hu origin = " MACFMT "\n", + type, mid, MAC2STR(dest)); + + + if (timer_pending(&q->ageing_timer)) { + if (timercmp(&q->next_tmo, &msg->ageing_tmo, >)) { + q->next_tmo.tv_sec = msg->ageing_tmo.tv_sec; + q->next_tmo.tv_usec = msg->ageing_tmo.tv_usec; + + timer_set(&q->ageing_timer, msg->ageing_time); + fprintf(stderr, "Adjust ageout timer ========>\n"); + } + } else { + fprintf(stderr, "Start ageout timer ========>\n"); + q->next_tmo.tv_sec = msg->ageing_tmo.tv_sec; + q->next_tmo.tv_usec = msg->ageing_tmo.tv_usec; + timer_set(&q->ageing_timer, msg->ageing_time); + } + + pthread_mutex_unlock(&q->qlock); + return 0; + } + + return -1; +} + +int cmdu_ackq_dequeue(void *cmdu_q, uint16_t type, uint16_t mid, uint8_t *src) +{ + struct cmdu_ackq *q = (struct cmdu_ackq *)cmdu_q; + struct cmdu_ackq_entry *msg = NULL; + int idx; + + msg = cmdu_ackq_lookup(cmdu_q, type, mid, src); + if (!msg) { + fprintf(stderr, + "DROP! CMDU not found: type = 0x%04x mid = %hu origin = " MACFMT "\n", + type, mid, MAC2STR(src)); + + return -1; + } + + idx = cmdu_ackq_hash(type, mid, src); + + pthread_mutex_lock(&q->qlock); + hlist_del(&msg->hlist, &q->table[idx]); + q->pending_cnt--; + pthread_mutex_unlock(&q->qlock); + + fprintf(stderr, + "DEQ: type = 0x%04x mid = %hu origin = " MACFMT "\n", + type, mid, MAC2STR(src)); + + cmdu_ackq_delete_msg(msg); + + return 0; +} diff --git a/src/cmdu_ackq.h b/src/cmdu_ackq.h new file mode 100644 index 0000000000000000000000000000000000000000..6adb61df1efa0248f0d6e70eabc18424d8f95601 --- /dev/null +++ b/src/cmdu_ackq.h @@ -0,0 +1,55 @@ +/* + * cmdu_ackq.h + * CMDU pending response and ack queue management + * + * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved. + * + * Author: anjan.chanda@iopsys.eu + * + * See LICENSE file for license related information. + * + */ + +#ifndef CMDU_ACKQ_H +#define CMDU_ACKQ_H + + +#include "hlist.h" + +#define CMDU_BACKLOG_MAX 128 +#define MAC_ADDR_HASH(a) (a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4] ^ a[5]) +// TODO: improve hash func +#define cmdu_ackq_hash(t, m, o) \ + ((MAC_ADDR_HASH(o) ^ (t) ^ (m)) & (CMDU_BACKLOG_MAX - 1)) + +/* struct holds a pending cmdu with 'mid' from 'origin' */ +struct cmdu_ackq_entry { + uint16_t type; + uint16_t mid; + uint8_t origin[6]; + struct hlist_node hlist; + + uint32_t ageing_time; /* in msecs */ + struct timeval ageing_tmo; +}; + +/* queue of cmdus for which response is pending */ +struct cmdu_ackq { + pthread_mutex_t qlock; + + /* hashtable of pending cmdu_ackq_entry */ + struct hlist_head table[CMDU_BACKLOG_MAX]; + + int pending_cnt; + atimer_t ageing_timer; + struct timeval next_tmo; +}; + +extern int cmdu_ackq_init(void *q); +extern void cmdu_ackq_reset(void *q); +extern int cmdu_ackq_dequeue(void *q, uint16_t type, uint16_t mid, uint8_t *src); +extern int cmdu_ackq_enqueue(void *q, uint16_t type, uint16_t mid, uint8_t *dest, + uint32_t timeout); + + +#endif /* CMDU_ACKQ_H */ diff --git a/src/cmdu_input.c b/src/cmdu_input.c index 58d17f407161e63755202871dc602250aecfd424..db6b4867a33489f0a4b6fe3f4c932d7a3b3a449e 100644 --- a/src/cmdu_input.c +++ b/src/cmdu_input.c @@ -34,13 +34,13 @@ #include "timer.h" #include "config.h" #include "cmdu.h" +#include "cmdu_ackq.h" #include "i1905_dm.h" #include "i1905.h" #include "i1905_extension.h" -// TODO: combine 3 following headers into one -#include "1905_defs.h" +// TODO: combine following headers into one #include "1905_tlvs.h" #include "lldp_tlvs.h" @@ -166,6 +166,10 @@ int i1905_handle_topology_response(struct i1905_interface_private *pif, return -1; } + + memcpy(aladdr_origin, devinfo->aladdr, 6); + ret = i1905_dm_neighbor_update(i1905_interface_priv(pif), + aladdr_origin, tv[0][0]); } if (tv[1][0]) { @@ -175,7 +179,10 @@ int i1905_handle_topology_response(struct i1905_interface_private *pif, struct tlv_device_bridge_caps *brcaps = (struct tlv_device_bridge_caps *)tv[1][num]->data; - //i1905_dm_neighbor_update(pif, ); //TODO + ret = i1905_dm_neighbor_update(i1905_interface_priv(pif), + aladdr_origin, tv[1][num]); + if (ret) + break; num++; } } @@ -187,7 +194,11 @@ int i1905_handle_topology_response(struct i1905_interface_private *pif, struct tlv_non1905_neighbor *non1905 = (struct tlv_non1905_neighbor *)tv[2][num]->data; - //i1905_dm_neighbor_update(pif, ); //TODO + + ret = i1905_dm_neighbor_update(i1905_interface_priv(pif), + aladdr_origin, tv[2][num]); + if (ret) + break; num++; } } @@ -199,7 +210,11 @@ int i1905_handle_topology_response(struct i1905_interface_private *pif, struct tlv_1905neighbor *nbrs = (struct tlv_1905neighbor *)tv[3][num]->data; - //i1905_dm_neighbor_update(pif, ); //TODO + + ret = i1905_dm_neighbor_update(i1905_interface_priv(pif), + aladdr_origin, tv[3][num]); + if (ret) + break; num++; } } @@ -343,23 +358,39 @@ static const cmdu_handler_t i1905ftable[] = { int i1905_process_cmdu(struct i1905_interface_private *pif, struct cmdu_buff *rxf) { - uint16_t type; + uint16_t type, mid; + uint8_t *src; int ret; + if (!rxf->cdata) return -1; - // TODO: discard duplicates - type = buf_get_be16((uint8_t *)&rxf->cdata->hdr.type); + mid = buf_get_be16((uint8_t *)&rxf->cdata->hdr.mid); + src = rxf->head + 6; - if (i1905ftable[type]) { - ret = i1905ftable[type](pif, rxf); + fprintf(stderr, "%s: from src " MACFMT ", type = %hu\n", + __func__, MAC2STR(src), type); + + if (type >= CMDU_TYPE_1905_END) { + fprintf(stderr, "%s: Unknown cmdu!\n", __func__); + return -1; } - fprintf(stderr, "%s: ----->\n", __func__); + if (is_cmdu_type_response(type)) { + /* discard responses with no matching request awaiting */ + ret = cmdu_ackq_dequeue(&pif->txack_q, type, mid, src); + if (ret) { + fprintf(stderr, "%s: drop unexpected CMDU (mid = %d)\n", + __func__, mid); + return -1; + } + } - return ret; -} + if (i1905ftable[type]) + ret = i1905ftable[type](pif, rxf); + return ret; +} diff --git a/src/i1905.c b/src/i1905.c index c1b3f5b2541341b41c0e0a5f3835f6975cf38a7a..2541564cd89595e219ad84fa50cec5aa6817d716 100644 --- a/src/i1905.c +++ b/src/i1905.c @@ -31,14 +31,14 @@ #include "timer.h" #include "config.h" #include "cmdu.h" +#include "cmdu_ackq.h" #include "i1905_dm.h" #include "i1905.h" #include "i1905_extension.h" -// TODO: combine 3 following headers into one -#include "1905_defs.h" -#include "i1905_tlvs.h" +// TODO: combine following headers into one +#include "1905_tlvs.h" #include "lldp_tlvs.h" @@ -125,18 +125,6 @@ int i1905_stop(struct i1905_private *p) return 0; } -int i1905_get_dm(struct i1905_private *p) -{ - //TODO - return 0; -} - -int i1905_free_dm(struct i1905_private *p) -{ - //TODO - return 0; -} - int i1905_cmdu_rxq_handler(void *data) { struct i1905_interface_private *pif = @@ -173,12 +161,11 @@ static struct i1905_interface *i1905_alloc_interface(const char *ifname, INIT_LIST_HEAD(&n->vendorlist); INIT_LIST_HEAD(&n->nbrlist); + INIT_LIST_HEAD(&n->non1905_nbrlist); INIT_LIST_HEAD(&n->iflinklist); n->priv = (void *)(n + 1); - fprintf(stderr, "%s: %d\n", __func__, __LINE__); - return n; } @@ -199,6 +186,7 @@ int i1905_cmdu_tx(struct i1905_interface_private *ifp, struct i1905_interface *iface = i1905_interface_priv(ifp); struct ether_header *eh; struct sockaddr_ll sa; + uint16_t resp_type; int ret; @@ -235,11 +223,18 @@ int i1905_cmdu_tx(struct i1905_interface_private *ifp, ret = sendto(ifp->sock_1905, data, datalen, 0, (struct sockaddr*)&sa, sizeof(struct sockaddr_ll)); if (ret < 0) { - printf("%s: failed!!!!!!!\n", __func__); + fprintf(stderr, "%s: failed!!!!!!!\n", __func__); return -1; } - *mid = 1000; /* TODO: generate mid */ + if (*mid == 0) + *mid = cmdu_get_next_mid(); + + resp_type = cmdu_expect_response(type); + if (resp_type != CMDU_TYPE_NONE) { + cmdu_ackq_enqueue(&ifp->txack_q, resp_type, *mid, dst, + CMDU_DEFAULT_TIMEOUT); + } return 0; } @@ -317,7 +312,6 @@ static void i1905_recv_1905(struct uloop_fd *fd, unsigned int events) return; } - fprintf(stderr, "%s: before receive\n", __func__); res = recvfrom(pif->sock_1905, rxf->head, 1518, 0, NULL, NULL); if (res == -1) { @@ -431,7 +425,6 @@ static void i1905_recv_lldp(struct uloop_fd *fd, unsigned int events) } - fprintf(stderr, "%s: before receive\n", __func__); res = recvfrom(pif->sock_lldp, rxf->head, 1518, 0, NULL, NULL); if (res == -1) { @@ -537,6 +530,8 @@ static int i1905_setup_interface_priv(struct i1905_interface *n) p->rxwork.func = i1905_cmdu_rxq_handler; worker_init(&p->rxwork); + cmdu_ackq_init(&p->txack_q); + i1905_init_interface_socket_1905(n, p); i1905_init_interface_socket_lldp(n, p); @@ -635,9 +630,9 @@ int i1905_run_bridge_discovery(struct i1905_private *p) return -1; } - lldpbuf[0] = (TLV_TYPE_CHASSIS_ID << 1) | ((7 & 0x80) >> 7); + lldpbuf[0] = (LLDP_TLV_CHASSIS_ID << 1) | ((7 & 0x80) >> 7); lldpbuf[1] = 7 & 0x7f; - lldpbuf[2] = CHASSIS_ID_TLV_SUBTYPE_MAC_ADDRESS; + lldpbuf[2] = LLDP_CHASSIS_ID_SUBTYPE_MAC_ADDRESS; memcpy(&lldpbuf[3], iface->aladdr, 6); ret = cmdu_put(frm, lldpbuf, 9); @@ -649,9 +644,9 @@ int i1905_run_bridge_discovery(struct i1905_private *p) } memset(lldpbuf, 0, 256); - lldpbuf[0] = (TLV_TYPE_PORT_ID << 1) | ((7 & 0x80) >> 7); + lldpbuf[0] = (LLDP_TLV_PORT_ID << 1) | ((7 & 0x80) >> 7); lldpbuf[1] = 7 & 0x7f; - lldpbuf[2] = PORT_ID_TLV_SUBTYPE_MAC_ADDRESS; + lldpbuf[2] = LLDP_PORT_ID_SUBTYPE_MAC_ADDRESS; memcpy(&lldpbuf[3], iface->macaddr, 6); ret = cmdu_put(frm, lldpbuf, 9); @@ -663,9 +658,9 @@ int i1905_run_bridge_discovery(struct i1905_private *p) } memset(lldpbuf, 0, 256); - lldpbuf[0] = (TLV_TYPE_TIME_TO_LIVE << 1) | ((2 & 0x80) >> 7); + lldpbuf[0] = (LLDP_TLV_TTL << 1) | ((2 & 0x80) >> 7); lldpbuf[1] = 2 & 0x7f; - buf_put_be16(&lldpbuf[2], TIME_TO_LIVE_TLV_1905_DEFAULT_VALUE); + buf_put_be16(&lldpbuf[2], LLDP_TTL_1905_DEFAULT_VALUE); ret = cmdu_put(frm, lldpbuf, 4); if (ret) { diff --git a/src/i1905.h b/src/i1905.h index e73c2de760a86baac0c5c0e1e9c82ff6edf3b8e4..cd6d049dca35c3dae0bcf8502420a0dc6d57e4fc 100644 --- a/src/i1905.h +++ b/src/i1905.h @@ -29,6 +29,7 @@ struct i1905_interface_private { struct uloop_fd uloop_lldp; struct cmdu_queue rxqueue; struct worker rxwork; + struct cmdu_ackq txack_q; void *iface; /* points to i1905_interface */ struct ubus_object obj; @@ -72,14 +73,14 @@ extern struct i1905_dm *i1905_dm_get(); extern int i1905_dm_init(struct i1905_dm *dm); extern int i1905_dm_free(struct i1905_dm *dm); -extern int i1905_dm_neighour_discovered(struct i1905_interface *iface, +extern int i1905_dm_neighbor_discovered(struct i1905_interface *iface, uint8_t *aladdr, uint8_t *macaddr); -extern int i1905_dm_neighour_changed(struct i1905_interface *iface, +extern int i1905_dm_neighbor_changed(struct i1905_interface *iface, uint8_t *aladdr); -extern int i1905_dm_neighour_update(struct i1905_interface *iface, +extern int i1905_dm_neighbor_update(struct i1905_interface *iface, uint8_t *aladdr, struct tlv *t); #endif /* I1905_H */ diff --git a/src/i1905_dm.c b/src/i1905_dm.c index 02c782ecf19f8fc5b78e950b45c7fe8e4f45bd60..ee778cd0d1f2f9fb5e2e0a4643d06b7d9df37cd3 100644 --- a/src/i1905_dm.c +++ b/src/i1905_dm.c @@ -26,14 +26,57 @@ #include <easy/easy.h> +#include "util.h" +#include "bufutil.h" #include "cmdu.h" #include "i1905_dm.h" -#include "1905_defs.h" -#include "i1905_tlvs.h" +#include "1905_tlvs.h" #include "lldp_tlvs.h" +struct i1905_bridge_tuple *i1905_dm_neighbor_brtuple_create(void) +{ + struct i1905_bridge_tuple *br; + + br = calloc(1, sizeof(*br)); + if (!br) { + fprintf(stderr, "-ENOMEM\n"); + return NULL; + } + + return br; +} + +struct i1905_net_non1905_neighbor *i1905_dm_neighbor_non1905_nbr_create(void) +{ + struct i1905_net_non1905_neighbor *xnbr; + + xnbr = calloc(1, sizeof(*xnbr)); + if (!xnbr) { + fprintf(stderr, "-ENOMEM\n"); + return NULL; + } + + return xnbr; +} + +struct i1905_net_neighbor *i1905_dm_neighbor_nbr_create(void) +{ + struct i1905_net_neighbor *rnbr; + + rnbr = calloc(1, sizeof(*rnbr)); + if (!rnbr) { + fprintf(stderr, "-ENOMEM\n"); + return NULL; + } + + //INIT_LIST_HEAD(&rnbr->riflist); + INIT_LIST_HEAD(&rnbr->metriclist); + + return rnbr; +} + struct i1905_interface *i1905_dm_neighbor_interface_create(void) { struct i1905_interface *rif; @@ -46,6 +89,7 @@ struct i1905_interface *i1905_dm_neighbor_interface_create(void) INIT_LIST_HEAD(&rif->vendorlist); INIT_LIST_HEAD(&rif->nbrlist); + INIT_LIST_HEAD(&rif->non1905_nbrlist); INIT_LIST_HEAD(&rif->iflinklist); return rif; @@ -65,7 +109,7 @@ struct i1905_device *i1905_dm_neighbor_create(void) INIT_LIST_HEAD(&rdev->ipv6list); INIT_LIST_HEAD(&rdev->vendorlist); INIT_LIST_HEAD(&rdev->iflist); - INIT_LIST_HEAD(&rdev->non1905_nbrlist); + //INIT_LIST_HEAD(&rdev->non1905_nbrlist); INIT_LIST_HEAD(&rdev->nbrlist); INIT_LIST_HEAD(&rdev->l2_nbrlist); INIT_LIST_HEAD(&rdev->brlist); @@ -74,6 +118,19 @@ struct i1905_device *i1905_dm_neighbor_create(void) return rdev; } +struct i1905_interface *i1905_dm_neighbor_interface_lookup(struct i1905_device *rdev, + uint8_t *ifmacaddr) +{ + struct i1905_interface *rif = NULL; + + + list_for_each_entry(rif, &rdev->iflist, list) { + if (hwaddr_equal(rif->macaddr, ifmacaddr)) + break; + } + + return rif; +} struct i1905_device *i1905_dm_neighbor_lookup(struct i1905_interface *iface, uint8_t *aladdr) @@ -91,15 +148,184 @@ struct i1905_device *i1905_dm_neighbor_lookup(struct i1905_interface *iface, return rdev; } + + + +int i1905_dm_neighbor_update_non1905_nbrlist(struct i1905_device *rdev, struct tlv *t) +{ + struct tlv_non1905_neighbor *non1905_nbr = + (struct tlv_non1905_neighbor *)t->data; + struct i1905_interface *rif; + int j; + + + rif = i1905_dm_neighbor_interface_lookup(rdev, non1905_nbr->local_macaddr); + if (!rif) { + rif = i1905_dm_neighbor_interface_create(); + if (!rif) { + fprintf(stderr, "-ENOMEM\n"); + return -1; + } + + memcpy(rif->macaddr, non1905_nbr->local_macaddr, 6); + memcpy(rif->aladdr, rdev->aladdr, 6); + rif->device = rdev; + rif->priv = NULL; + list_add_tail(&rif->list, &rdev->iflist); + } + + /* XXX: replace old non-1905 nbrlist with this one */ + list_flush(&rif->non1905_nbrlist, struct i1905_net_non1905_neighbor, list); + + for (j = 0; j < non1905_nbr->num_non1905_nbrs; j++) { + struct i1905_net_non1905_neighbor *rdev_xnbr = NULL; + + rdev_xnbr = i1905_dm_neighbor_non1905_nbr_create(); + if (rdev_xnbr) { + memcpy(rdev_xnbr->macaddr, non1905_nbr->non1905_nbr[j].macaddr, 6); + list_add_tail(&rdev_xnbr->list, &rif->non1905_nbrlist); + } + } + + return 0; +} + +int i1905_dm_neighbor_update_nbrlist(struct i1905_device *rdev, struct tlv *t) +{ + struct tlv_1905neighbor *nbr = + (struct tlv_1905neighbor *)t->data; + struct i1905_interface *rif; + int j; + + + rif = i1905_dm_neighbor_interface_lookup(rdev, nbr->local_macaddr); + if (!rif) { + rif = i1905_dm_neighbor_interface_create(); + if (!rif) { + fprintf(stderr, "-ENOMEM\n"); + return -1; + } + + memcpy(rif->macaddr, nbr->local_macaddr, 6); + memcpy(rif->aladdr, rdev->aladdr, 6); + rif->device = rdev; + rif->priv = NULL; + list_add_tail(&rif->list, &rdev->iflist); + } + + /* XXX: quickest way is to replace old nbrlist with this one */ + list_flush(&rif->nbrlist, struct i1905_net_neighbor, list); + + for (j = 0; j < nbr->num_1905nbrs; j++) { + struct i1905_net_neighbor *rdev_nbr = NULL; + + rdev_nbr = i1905_dm_neighbor_nbr_create(); + if (rdev_nbr) { + memcpy(rdev_nbr->aladdr, nbr->nbr[j].aladdr, 6); + rdev_nbr->br_present = nbr->nbr[j].has_bridge; + list_add_tail(&rdev_nbr->list, &rif->nbrlist); + } + } + + return 0; +} + +int i1905_dm_neighbor_update_brlist(struct i1905_device *rdev, struct tlv *t) +{ + struct tlv_device_bridge_caps *brcaps = + (struct tlv_device_bridge_caps *)t->data; + struct i1905_bridge_tuple *bp, *tmp; + int i; + + + + /* replace old brlist with this one */ + list_for_each_entry_safe(bp, tmp, &rdev->brlist, list) { + list_del(&bp->list); + if (bp->num_macs) + free(bp->macaddrs); + free(bp); + } + + for (i = 0; i < brcaps->num_tuples; i++) { + struct i1905_bridge_tuple *br = NULL; + + br = i1905_dm_neighbor_brtuple_create(); + if (!br) { + fprintf(stderr, "-ENOMEM\n"); + return -1; + } + + br->num_macs = brcaps->tuple[i].num_macaddrs; + memcpy(br->macaddrs, brcaps->tuple[i].addr, brcaps->tuple[i].num_macaddrs); + list_add_tail(&br->list, &rdev->brlist); + } + + return 0; +} + +int i1905_dm_neighbor_update_devinfo(struct i1905_device *rdev, struct tlv *t) +{ + struct tlv_device_info *devinfo = + (struct tlv_device_info *)t->data; + int i; + + + for (i = 0; i < devinfo->num_interface; i++) { + struct local_interface *tif = devinfo->interface; + struct i1905_interface *rif; + + rif = i1905_dm_neighbor_interface_lookup(rdev, tif->macaddr); + if (!rif) { + rif = i1905_dm_neighbor_interface_create(); + if (!rif) { + fprintf(stderr, "-ENOMEM\n"); + return -1; + } + + memcpy(rif->macaddr, tif->macaddr, 6); + memcpy(rif->aladdr, rdev->aladdr, 6); + rif->device = rdev; + rif->priv = NULL; + rif->media = buf_get_be16((uint8_t *)&tif->mediatype); + if (tif->sizeof_mediainfo > 0) { + rif->mediainfo = calloc(1, tif->sizeof_mediainfo); + if (!rif->mediainfo) { + fprintf(stderr, "-ENOMEM\n"); + } + + memcpy(rif->mediainfo, tif->mediainfo, + tif->sizeof_mediainfo); + } + + list_add_tail(&rif->list, &rdev->iflist); + } else { + memcpy(rif->aladdr, rdev->aladdr, 6); + rif->media = buf_get_be16((uint8_t *)&tif->mediatype); + if (tif->sizeof_mediainfo > 0) { + if (rif->mediainfo) + free(rif->mediainfo); + + rif->mediainfo = calloc(1, tif->sizeof_mediainfo); + if (!rif->mediainfo) { + fprintf(stderr, "-ENOMEM\n"); + } + + memcpy(rif->mediainfo, tif->mediainfo, + tif->sizeof_mediainfo); + } + } + } + + return 0; +} + int i1905_dm_neighbor_update(struct i1905_interface *iface, uint8_t *aladdr, struct tlv *t) { struct i1905_selfdevice *self = (struct i1905_selfdevice *)iface->device; - struct i1905_interface *rif = NULL; struct i1905_device *rdev = NULL; - int origin = 0; - int found = 0; - int ret; + int ret = 0; rdev = i1905_dm_neighbor_lookup(iface, aladdr); if (!rdev) { @@ -109,12 +335,16 @@ int i1905_dm_neighbor_update(struct i1905_interface *iface, uint8_t *aladdr, switch (t->type) { case TLV_TYPE_DEVICE_INFORMATION_TYPE: + ret = i1905_dm_neighbor_update_devinfo(rdev, t); break; case TLV_TYPE_DEVICE_BRIDGING_CAPABILITIES: + ret = i1905_dm_neighbor_update_brlist(rdev, t); break; case TLV_TYPE_NON_1905_NEIGHBOR_DEVICE_LIST: + ret = i1905_dm_neighbor_update_non1905_nbrlist(rdev, t); break; case TLV_TYPE_NEIGHBOR_DEVICE_LIST: + ret = i1905_dm_neighbor_update_nbrlist(rdev, t); break; case TLV_TYPE_POWER_OFF_INTERFACE: break; @@ -125,7 +355,7 @@ int i1905_dm_neighbor_update(struct i1905_interface *iface, uint8_t *aladdr, break; } - return 0; + return ret; } int i1905_dm_neighbor_discovered(struct i1905_interface *iface, uint8_t *aladdr, diff --git a/src/i1905_dm.h b/src/i1905_dm.h index 55b5b2c857d542bd8de3893247a92d0e9caaf015..fcd630d4731f70ed81d8bb756b553d048977367c 100644 --- a/src/i1905_dm.h +++ b/src/i1905_dm.h @@ -49,6 +49,18 @@ struct i1905_registrar { struct list_head list; }; +struct i1905_metric { + bool br_present; + uint32_t tx_errors; + uint32_t rx_errors; + uint32_t tx_packets; + uint32_t rx_packets; + uint32_t available; /* in percentage */ + uint32_t max_rate; /* max throughput at MAC layer */ + uint32_t max_phyrate; + uint8_t rssi; /* FIXME: average rssi */ +}; + /* remote interface */ struct i1905_rinterface { uint8_t macaddr[6]; @@ -57,13 +69,28 @@ struct i1905_rinterface { struct list_head list; }; +struct i1905_net_neighbor_metric { + uint8_t peer_macaddr[6]; + struct i1905_metric m; + struct list_head list; +}; + struct i1905_net_neighbor { - uint8_t macaddr[6]; + uint8_t local_macaddr[6]; + uint8_t aladdr[6]; + bool br_present; uint8_t num_ifaces; - struct list_head riflist; /* list of struct i1905_rinterface */ + //struct list_head riflist; /* list of struct i1905_rinterface */ + uint8_t num_metrics; + struct list_head metriclist; /* list of i1905_net_neighbor_metric*/ struct list_head list; }; +struct i1905_net_non1905_neighbor { + //uint8_t local_macaddr[6]; + uint8_t macaddr[6]; + struct list_head list; +}; struct i1905_genphy { uint8_t oui[3]; @@ -77,17 +104,6 @@ struct i1905_vendor_info { struct list_head list; }; -struct i1905_metric { - bool br_present; - uint32_t tx_errors; - uint32_t rx_errors; - uint32_t tx; - uint32_t rx; - uint32_t available; /* in percentage */ - uint32_t max_rate; /* max throughput at MAC layer */ - uint32_t max_phyrate; - uint8_t rssi; /* FIXME: average rssi */ -}; enum i1905_fwdrule_mask { I1905_FWDRULE_SRC = 1 << 0, @@ -165,6 +181,7 @@ struct i1905_interface { struct list_head iflinklist; /* list of interface links */ + struct list_head non1905_nbrlist; // XXX: moved from device due to TLV struct list_head nbrlist; /* TODO: needed ? */ struct list_head list; @@ -208,6 +225,12 @@ struct i1905_ipv6 { struct list_head list; }; +struct i1905_bridge_tuple { + uint8_t num_macs; + uint8_t *macaddrs; /* array of interface macaddress */ + struct list_head list; +}; + /* represents another 1905 device in the network */ struct i1905_device { uint32_t tsp; @@ -235,10 +258,10 @@ struct i1905_device { struct list_head ipv6list; /* list of i1905_ipv6 */ struct list_head vendorlist; /* list of i1905_vendor_info */ struct list_head iflist; /* list of i1905_interface */ - struct list_head non1905_nbrlist; + //struct list_head non1905_nbrlist; struct list_head nbrlist; /* list of struct i1905_net_neighbor */ struct list_head l2_nbrlist; - struct list_head brlist; /* list of */ + struct list_head brlist; /* list of i1905_bridge_tuple */ struct i1905_security security; struct list_head reglist; /* list of i1905_registrar in network */ diff --git a/src/i1905_ubus.c b/src/i1905_ubus.c index 9916cfb1b71615158dab10c0c4e27e55448ace24..6289688f252f8aaa59ccd55116e399d2e42de1f4 100644 --- a/src/i1905_ubus.c +++ b/src/i1905_ubus.c @@ -23,6 +23,7 @@ #include "worker.h" #include "config.h" #include "cmdu.h" +#include "cmdu_ackq.h" #include "i1905_dm.h" #include "i1905.h" diff --git a/src/lldp_tlvs.h b/src/lldp_tlvs.h index a1aa3ca20579e29ae335c8744c460baa89a9a08a..d5f048a0b8b162f4c83e6acb9c177fcadaa2957e 100644 --- a/src/lldp_tlvs.h +++ b/src/lldp_tlvs.h @@ -1,209 +1,61 @@ /* - * lldp_tlvs.h: IEEE-1905 lldp tlvs handling + * lldp_tlvs.h: LLDP tlvs definition */ -#ifndef _LLDP_TLVS_H_ -#define _LLDP_TLVS_H_ - - -#define TLV_TYPE_END_OF_LLDPPDU (0) -#define TLV_TYPE_CHASSIS_ID (1) -#define TLV_TYPE_PORT_ID (2) -#define TLV_TYPE_TIME_TO_LIVE (3) - -//////////////////////////////////////////////////////////////////////////////// -// End of LLDPPDU TLV associated structures ("Section 8.5.1") -//////////////////////////////////////////////////////////////////////////////// -struct endOfLldppduTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_END_OF_LLDPPDU - - // This structure does not contain anything at all -}; - -//////////////////////////////////////////////////////////////////////////////// -// Chassis ID TLV associated structures ("Section 8.5.2") -//////////////////////////////////////////////////////////////////////////////// -struct chassisIdTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_CHASSIS_ID - -#define CHASSIS_ID_TLV_SUBTYPE_CHASSIS_COMPONENT (1) -#define CHASSIS_ID_TLV_SUBTYPE_INTERFACE_ALIAS (2) -#define CHASSIS_ID_TLV_SUBTYPE_PORT_COMPONENT (3) -#define CHASSIS_ID_TLV_SUBTYPE_MAC_ADDRESS (4) -#define CHASSIS_ID_TLV_SUBTYPE_NETWORK_ADDRESS (5) -#define CHASSIS_ID_TLV_SUBTYPE_INTERFACE_NAME (6) -#define CHASSIS_ID_TLV_SUBTYPE_LOGICALLY_ASSIGNED (7) - uint8_t chassis_id_subtype; // One of the values from above - - uint8_t chassis_id[256]; // Specific identifier for the particular - // chassis. - // NOTE: In our case (1905 context) we are - // only interested in generating/ - // consuming chassis subtype "4" (MAC - // address), thus "chassis_id" will - // hold a six bytes array representing - // the MAC address of the transmitting - // AL entity (as explained in - // "IEEE Std 1905.1-2013 Section 6.1") -}; - -//////////////////////////////////////////////////////////////////////////////// -// Port ID TLV associated structures ("Section 8.5.3") -//////////////////////////////////////////////////////////////////////////////// -struct portIdTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_PORT_ID - -#define PORT_ID_TLV_SUBTYPE_INTERFACE_ALIAS (1) -#define PORT_ID_TLV_SUBTYPE_PORT_COMPONENT (2) -#define PORT_ID_TLV_SUBTYPE_MAC_ADDRESS (3) -#define PORT_ID_TLV_SUBTYPE_NETWORK_ADDRESS (4) -#define PORT_ID_TLV_SUBTYPE_INTERFACE_NAME (5) -#define PORT_ID_TLV_SUBTYPE_AGENT_CIRCUIT_ID (6) -#define PORT_ID_TLV_SUBTYPE_LOGICALLY_ASSIGNED (7) - uint8_t port_id_subtype; // One of the values from above - - uint8_t port_id[256]; // Alpha-numeric string that contains the - // specific identifier for the port from which - // this LLDPPDU was transmitted - // NOTE: In our case (1905 context) we are - // only interested in generating/ - // consuming port subtype "3" (MAC - // address), thus "port_id" will hold a - // six bytes array representing the MAC - // address of the transmitting interface - // (as explained in "IEEE Std - // 1905.1-2013 Section 6.1") - // NOTE2: The standard says "alpha-numeric" - // string... but the implementations I - // have checked store a 6 bytes MAC - // address and not its string - // representation... So we are also - // storing 6 bytes here. -}; - -//////////////////////////////////////////////////////////////////////////////// -// Time to live TLV associated structures ("Section 8.5.4") -//////////////////////////////////////////////////////////////////////////////// -struct timeToLiveTypeTLV { - uint8_t tlv_type; // Must always be set to - // TLV_TYPE_TIME_TO_LIVE - -#define TIME_TO_LIVE_TLV_1905_DEFAULT_VALUE (180) - uint16_t ttl; // Time (in seconds) - // NOTE: In our case (1905 context) we are - // always setting this parameter to - // "180" (as explained in "IEEE Std - // 1905.1-2013 Section 6.1") -}; - -#if 0 -//////////////////////////////////////////////////////////////////////////////// -// Main API functions -//////////////////////////////////////////////////////////////////////////////// - -// This function receives a pointer to a stream of bytes representing an LLPD -// TLV according to "Section 8.5" -// -// It then returns a pointer to a structure whose fields have already been -// filled with the appropiate values extracted from the parsed stream. -// -// The actual type of the returned pointer structure depends on the value of -// the first byte pointed by "packet_stream" (ie. the "Type" field of the TLV): -// -// TLV_TYPE_END_OF_LLDPPDU --> struct endOfLldppduTLV * -// TLV_TYPE_CHASSIS_ID --> struct chassisIdTLV * -// TLV_TYPE_PORT_ID --> struct portIdTLV * -// TLV_TYPE_TIME_TO_LIVE --> struct timeToLiveTypeTLV * -// -// If an error was encountered while parsing the stream, a NULL pointer is -// returned instead. -// Otherwise, the returned structure is dynamically allocated, and once it is -// no longer needed, the user must call the "free_lldp_TLV_structure()" function -// -uint8_t *parse_lldp_TLV_from_packet(INT8U *packet_stream); - -// This is the opposite of "parse_lldp_TLV_from_packet()": it receives a -// pointer to a TLV structure and then returns a pointer to a buffer which: -// - is a packet representation of the TLV -// - has a length equal to the value returned in the "len" output argument -// -// "memory_structure" must point to a structure of one of the types returned by -// "parse_lldp_TLV_from_packet()" -// -// If there is a problem this function returns NULL, otherwise the returned -// buffer must be later freed by the caller (it is a regular, non-nested buffer, -// so you just need to call "free()"). -// -// Note that the input structure is *not* freed. You still need to later call -// "free_lldp_TLV_structure()" -// -uint8_t *forge_lldp_TLV_from_structure(INT8U *memory_structure, uint16_t *len); - -//////////////////////////////////////////////////////////////////////////////// -// Utility API functions -//////////////////////////////////////////////////////////////////////////////// - -// This function receives a pointer to a TLV structure and then traverses it -// and all nested structures, calling "free()" on each one of them -// -// "memory_structure" must point to a structure of one of the types returned by -// "parse_lldp_TLV_from_packet()" -// -void free_lldp_TLV_structure(uint8_t *memory_structure); - -// 'forge_lldp_TLV_from_structure()' returns a regular buffer which can be freed -// using this macro defined to be FREE -// -#define free_lldp_TLV_packet FREE - -// This function returns '0' if the two given pointers represent TLV structures -// of the same type and they contain the same data -// -// "memory_structure_1" and "memory_structure_2" must point (each) to a -// structure of one of the types returned by "parse_lldp_TLV_from_packet()" -// -uint8_t compare_lldp_TLV_structures(INT8U *memory_structure_1, INT8U *memory_structure_2); - -// The next function is used to call function "callback()" on each element of -// the "memory_structure" structure -// -// "memory_structure" must point to a structure of one of the types returned by -// "parse_lldp_TLV_from_packet()" -// -// It takes four arguments: -// - The structure whose elements are going to be visited -// - A callback function that will be executed on each element with the -// following arguments: -// * A pointer to the "write()" function that will be used to dump text. -// This is always the "write_function()" pointer provided as third -// argument to the "visit_lldp_TLV_structure()" function. -// * The size of the element to print (1, 2, 4, n bytes) -// * A prefix string. -// This is always the "prefix" value provided as fourth argument to the -// "visit_lldp_TLV_structure()" function/ -// * The name of the element (ex: "mac_address") -// * A 'fmt' string which must be used to print the contents of the element -// * A pointer to the element itself -// - The "write()" function that will be used when the callback is executed -// - A "prefix" string argument that will be used when the callback is -// executed (it usually contains "context" information that the callback -// function prints before anything else to make it easy to follow the -// structure traversing order) -// -void visit_lldp_TLV_structure(uint8_t *memory_structure, PRINT_CALLBACK callback, PRINT_WRITER write_function, const char *prefix, struct blob_buf *bb); - -// Use this function for debug purposes. It turns a TLV_TYPE_* variable into its -// string representation. -// -// Example: TLV_TYPE_CHASSIS_ID --> "TLV_TYPE_CHASSIS_ID" -// -// Return "Unknown" if the provided type does not exist. -// -char *convert_lldp_TLV_type_to_string(uint8_t tlv_type); - -#endif // 0 - -#endif +#ifndef LLDP_TLVS_H +#define LLDP_TLVS_H + + +/* Tlv types */ +#define LLDP_TLV_EOL 0 +#define LLDP_TLV_CHASSIS_ID 1 +#define LLDP_TLV_PORT_ID 2 +#define LLDP_TLV_TTL 3 + + +/* TLV: end of LLDPPDU */ +struct tlv_eol { +} __attribute__((packed)); + + +#define LLDP_CHASSIS_ID_SUBTYPE_CHASSIS_COMPONENT 1 +#define LLDP_CHASSIS_ID_SUBTYPE_INTERFACE_ALIAS 2 +#define LLDP_CHASSIS_ID_SUBTYPE_PORT_COMPONENT 3 +#define LLDP_CHASSIS_ID_SUBTYPE_MAC_ADDRESS 4 +#define LLDP_CHASSIS_ID_SUBTYPE_NETWORK_ADDRESS 5 +#define LLDP_CHASSIS_ID_SUBTYPE_INTERFACE_NAME 6 +#define LLDP_CHASSIS_ID_SUBTYPE_LOGICALLY_ASSIGNED 7 + +/* TLV: chassis-id */ +struct tlv_chassis_id { + uint8_t subtype; + uint8_t id[256]; +} __attribute__((packed)); + + + +#define LLDP_PORT_ID_SUBTYPE_INTERFACE_ALIAS 1 +#define LLDP_PORT_ID_SUBTYPE_PORT_COMPONENT 2 +#define LLDP_PORT_ID_SUBTYPE_MAC_ADDRESS 3 +#define LLDP_PORT_ID_SUBTYPE_NETWORK_ADDRESS 4 +#define LLDP_PORT_ID_SUBTYPE_INTERFACE_NAME 5 +#define LLDP_PORT_ID_SUBTYPE_AGENT_CIRCUIT_ID 6 +#define LLDP_PORT_ID_SUBTYPE_LOGICALLY_ASSIGNED 7 + +/* TLV: port-id */ +struct tlv_port_id { + uint8_t subtype; + uint8_t id[256]; +} __attribute__((packed)); + + + +#define LLDP_TTL_1905_DEFAULT_VALUE 180 /* in secs */ + +/* TLV: ttl */ +struct tlv_ttl { + uint16_t ttl; /* in secs */ +} __attribute__((packed)); + + +#endif /* LLDP_TLVS_H */ diff --git a/src/main.c b/src/main.c index 57ee1bd8b7a1764755e438bec04e3b794850788b..833db5aa7c79f7762404b007e88c0833bc597fce 100644 --- a/src/main.c +++ b/src/main.c @@ -28,6 +28,7 @@ #include "worker.h" #include "config.h" #include "cmdu.h" +#include "cmdu_ackq.h" #include "i1905_dm.h" #include "i1905.h" diff --git a/src/util.h b/src/util.h index 76b6e7d3a400d9fa8fc2927050074d5ff38a25cd..70bc0e4a54a986df5c975c51af8a6010cd19ca9d 100644 --- a/src/util.h +++ b/src/util.h @@ -3,6 +3,7 @@ #define NETIF_UTIL_H +#include <libubox/list.h> void get_random_bytes(int num, uint8_t *buf); void bufprintf(uint8_t *buf, int len, const char *label); @@ -39,4 +40,19 @@ extern int br_get_iflist(const char *brname, int *num, char ifs[][16]); #define MAC2STR(_m) (_m)[0], (_m)[1], (_m)[2], (_m)[3], (_m)[4], (_m)[5] + + +#ifndef list_flush +#define list_flush(head, type, member) \ +do { \ + type *__p, *__tmp; \ + \ + if (!list_empty(head)) \ + list_for_each_entry_safe(__p, __tmp, head, member) { \ + list_del(&__p->member); \ + free(__p); \ + } \ +} while (0) +#endif + #endif /* NETIF_UTIL_H */