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 */