From 1f5358bb4f1ca736ac9d89e221a533fa96f67289 Mon Sep 17 00:00:00 2001 From: olabjorsne Date: Tue, 19 Jan 2021 17:33:36 +0100 Subject: [PATCH] Multiport linux support - See doc/multiple_ports.rst for information on how to configure and run a mulitport configuration - Verified on Raspberry Pi with additional USB ethernet interfaces --- doc/multiple_ports.rst | 39 ++- .../GSDML-V2.4-rtlabs-IODevice-20201211.xml | 10 + sample_app/sampleapp_common.c | 250 ++++++++++++++++-- sample_app/sampleapp_common.h | 97 ++++++- src/common/pf_eth.c | 65 ++++- src/common/pf_eth.h | 22 +- src/common/pf_lldp.c | 37 ++- src/common/pf_lldp.h | 12 +- src/device/pf_port.c | 20 ++ src/device/pf_port.h | 22 ++ src/device/pnet_api.c | 25 +- src/pf_types.h | 3 +- src/pnal.h | 28 +- src/ports/linux/pnal_eth.c | 18 +- src/ports/linux/pnal_sys.h | 19 -- src/ports/linux/sampleapp_main.c | 166 ++++++------ src/ports/rt-kernel/dwmac1000.c | 6 +- src/ports/rt-kernel/pnal_eth.c | 71 ++--- src/ports/rt-kernel/pnal_sys.h | 23 +- src/ports/rt-kernel/sampleapp_main.c | 86 ++---- test/mocks.cpp | 16 +- test/mocks.h | 2 +- test/test_cmrpc.cpp | 2 +- test/test_dcp.cpp | 16 +- test/test_lldp.cpp | 2 +- test/utils_for_testing.cpp | 2 +- 26 files changed, 739 insertions(+), 320 deletions(-) diff --git a/doc/multiple_ports.rst b/doc/multiple_ports.rst index ed3a4fe8..8612e942 100644 --- a/doc/multiple_ports.rst +++ b/doc/multiple_ports.rst @@ -2,6 +2,7 @@ Multiple ports ============== This section describes how to configure the p-net stack, sample application and system for multiple network interfaces or ports. +So far, multiple port has only been tested using the linux port. Terminology @@ -92,12 +93,40 @@ Run ``ifconfig`` to check that the bridge is up and its network interfaces are a TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 -Configuration of p-net stack and sample application (TBD) +Configuration of p-net stack and sample application --------------------------------------------------------- To run p-net and the sample application with multiple ports a couple of things need to be done: -* Reconfigure setting ``PNET_MAX_PORT`` to the actual number of physical ports available in the system. - For this example ``PNET_MAX_PORT`` shall be set to 2. - -* TBD - update this document when multiport support is implemented +Reconfigure setting ``PNET_MAX_PORT`` to the actual number of physical ports available in the system. + For this example ``PNET_MAX_PORT`` shall be set to 2. + +Example of initial log when starting the demo application with a multi port configuration:: + + pi@pndevice-pi:~/profinet/build $ sudo ./pn_dev -v + ** Starting Profinet demo application ** + Number of slots: 5 (incl slot for DAP module) + P-net log level: 0 (DEBUG=0, FATAL=4) + App verbosity level: 1 + Nbr of ports: 2 + Network interfaces: br0,eth0,eth1 + Button1 file: + Button2 file: + Station name: rt-labs-dev + Management port: br0 C2:38:F3:A6:0A:66 + Physical port [1]: eth0 B8:27:EB:67:14:8A + Physical port [2]: eth1 58:EF:68:B5:11:0F + Current hostname: pndevice-pi + Current IP address: 192.168.0.50 + Current Netmask: 255.255.255.0 + Current Gateway: 192.168.0.1 + Storage directory: /home/pi/profinet/build + +Update gsdml file +----------------- +The sample app gsdml file contains a commented out block that defines +a second physical port. In the sample application gsdml file, search for "IDS_P2" +and enable commented out lines as described in the gsdml file. + +Note that you will have to the reload gsdml file in all tools you are using and +also the Automated RT tester any time the file is changed. \ No newline at end of file diff --git a/sample_app/GSDML-V2.4-rtlabs-IODevice-20201211.xml b/sample_app/GSDML-V2.4-rtlabs-IODevice-20201211.xml index f970a544..7eba1dda 100644 --- a/sample_app/GSDML-V2.4-rtlabs-IODevice-20201211.xml +++ b/sample_app/GSDML-V2.4-rtlabs-IODevice-20201211.xml @@ -59,6 +59,15 @@ + + + @@ -195,6 +204,7 @@ + diff --git a/sample_app/sampleapp_common.c b/sample_app/sampleapp_common.c index 0e8d2e3e..c0f43179 100644 --- a/sample_app/sampleapp_common.c +++ b/sample_app/sampleapp_common.c @@ -60,13 +60,7 @@ static void ip_to_string (pnal_ipaddr_t ip, char * outputstring) (uint8_t) (ip & 0xFF)); } -/** - * Convert MAC address to string - * @param mac In: MAC address - * @param outputstring Out: Resulting string buffer. Should have size - * PNAL_ETH_ADDRSTR_SIZE. - */ -static void mac_to_string (pnal_ethaddr_t mac, char * outputstring) +void app_mac_to_string (pnal_ethaddr_t mac, char * outputstring) { snprintf ( outputstring, @@ -189,7 +183,6 @@ static const char * ioxs_to_string (pnet_ioxs_values_t ioxs) } void app_print_network_details ( - pnal_ethaddr_t * p_macbuffer, pnal_ipaddr_t ip, pnal_ipaddr_t netmask, pnal_ipaddr_t gateway) @@ -197,16 +190,13 @@ void app_print_network_details ( char ip_string[PNAL_INET_ADDRSTR_SIZE]; /* Terminated string */ char netmask_string[PNAL_INET_ADDRSTR_SIZE]; /* Terminated string */ char gateway_string[PNAL_INET_ADDRSTR_SIZE]; /* Terminated string */ - char mac_string[PNAL_ETH_ADDRSTR_SIZE]; /* Terminated string */ char hostname_string[PNAL_HOSTNAME_MAX_SIZE]; /* Terminated string */ - mac_to_string (*p_macbuffer, mac_string); ip_to_string (ip, ip_string); ip_to_string (netmask, netmask_string); ip_to_string (gateway, gateway_string); pnal_get_hostname (hostname_string); - printf ("MAC address: %s\n", mac_string); printf ("Current hostname: %s\n", hostname_string); printf ("Current IP address: %s\n", ip_string); printf ("Current Netmask: %s\n", netmask_string); @@ -1265,6 +1255,7 @@ void app_plug_dap (pnet_t * net, void * arg) PNET_MOD_DAP_IDENT, PNET_SUBMOD_DAP_IDENT, &cfg_dap_data); + app_exp_submodule_ind ( net, arg, @@ -1274,6 +1265,7 @@ void app_plug_dap (pnet_t * net, void * arg) PNET_MOD_DAP_IDENT, PNET_SUBMOD_DAP_INTERFACE_1_IDENT, &cfg_dap_data); + app_exp_submodule_ind ( net, arg, @@ -1283,12 +1275,49 @@ void app_plug_dap (pnet_t * net, void * arg) PNET_MOD_DAP_IDENT, PNET_SUBMOD_DAP_INTERFACE_1_PORT_1_IDENT, &cfg_dap_data); + +#if PNET_MAX_PORT >= 2 + app_exp_submodule_ind ( + net, + arg, + APP_API, + PNET_SLOT_DAP_IDENT, + PNET_SUBSLOT_DAP_INTERFACE_1_PORT_2_IDENT, + PNET_MOD_DAP_IDENT, + PNET_SUBMOD_DAP_INTERFACE_1_PORT_2_IDENT, + &cfg_dap_data); +#endif + +#if PNET_MAX_PORT >= 3 + app_exp_submodule_ind ( + net, + arg, + APP_API, + PNET_SLOT_DAP_IDENT, + PNET_SUBSLOT_DAP_INTERFACE_1_PORT_3_IDENT, + PNET_MOD_DAP_IDENT, + PNET_SUBMOD_DAP_INTERFACE_1_PORT_3_IDENT, + &cfg_dap_data); +#endif + +#if PNET_MAX_PORT >= 4 + app_exp_submodule_ind ( + net, + arg, + APP_API, + PNET_SLOT_DAP_IDENT, + PNET_SUBSLOT_DAP_INTERFACE_1_PORT_4_IDENT, + PNET_MOD_DAP_IDENT, + PNET_SUBMOD_DAP_INTERFACE_1_PORT_4_IDENT, + &cfg_dap_data); +#endif } /************ Configuration of product ID, software version etc **************/ -int app_adjust_stack_configuration (pnet_cfg_t * stack_config) +int app_pnet_cfg_init_default (pnet_cfg_t * stack_config) { + uint16_t i; memset (stack_config, 0, sizeof (pnet_cfg_t)); stack_config->tick_us = APP_TICK_INTERVAL_US; @@ -1363,9 +1392,16 @@ int app_adjust_stack_configuration (pnet_cfg_t * stack_config) stack_config->min_device_interval = 32; /* Corresponds to 1 ms */ /* LLDP settings */ - strcpy (stack_config->if_cfg.ports[0].port_id, "port-001"); - stack_config->if_cfg.ports[0].rtclass_2_status = 0; - stack_config->if_cfg.ports[0].rtclass_3_status = 0; + for (i = 0; i < PNET_MAX_PORT; i++) + { + snprintf ( + stack_config->if_cfg.ports[i].port_id, + PNET_LLDP_PORT_ID_MAX_SIZE, + "port-%03d", + i + 1); + stack_config->if_cfg.ports[i].rtclass_2_status = 0; + stack_config->if_cfg.ports[i].rtclass_3_status = 0; + } /* Network configuration */ stack_config->send_hello = true; @@ -1379,6 +1415,190 @@ int app_adjust_stack_configuration (pnet_cfg_t * stack_config) return 0; } +/** + * Initialize a network interface configuration from a network + * interface name. + * This includes reading the Ethernet MAC address. + * If the network interface can not be found or the operation + * fails to read the mac address from the network interface, + * error is returned. + * @param netif_name In: Network interface name + * @param p_netif Out: Network interface configuration + * @param verbosity In: Verbosity + * @return 0 on success + * -1 on error + */ +int app_port_cfg_init ( + const char * netif_name, + pnet_netif_t * p_netif, + int verbosity) +{ + pnal_ethaddr_t mac; + char mac_string[PNAL_ETH_ADDRSTR_SIZE]; /* Terminated string */ + + int ret = pnal_get_macaddress (netif_name, &mac); + if (ret != 0) + { + printf ( + "Error: The given network interface does not exist: \"%s\"\n", + netif_name); + return -1; + } + else + { + if (verbosity > 0) + { + app_mac_to_string (mac, mac_string); + printf ("%-10s %s\n", netif_name, mac_string); + } + } + + strncpy (p_netif->if_name, netif_name, PNET_INTERFACE_NAME_MAX_SIZE); + memcpy (p_netif->eth_addr.addr, mac.addr, sizeof (pnal_ethaddr_t)); + + return 0; +} + +int app_get_netif_namelist ( + const char * arg_str, + app_netif_namelist_t * p_if_list, + int max_port) +{ + int ret = 0; + uint16_t i = 0; + uint16_t j = 0; + uint16_t if_index = 0; + uint16_t if_list_size = max_port + 1; /* NELEMENTS (p_if_list->netif) dynamic + for test. */ + char c; + + memset (p_if_list, 0, sizeof (*p_if_list)); + c = arg_str[i++]; + while (c != '\0' && if_index < if_list_size) + { + if (c != ',') + { + p_if_list->netif[if_index].name[j++] = c; + } + else + { + p_if_list->netif[if_index].name[j++] = '\0'; + j = 0; + if_index++; + } + c = arg_str[i++]; + } + + if (max_port == 1) + { + if (if_index >= max_port) + { + printf ("Error: Only 1 network interface expected.\n"); + ret = -1; + } + + if (strlen (p_if_list->netif[0].name) == 0) + { + printf ("Error: Zero length network interface name.\n"); + ret = -1; + } + p_if_list->netif[1] = p_if_list->netif[0]; + } + + if (max_port > 1) + { + if (if_index != max_port) + { + printf ("Error: %u network interfaces expected.\n", max_port + 1); + ret = -1; + } + + for (i = 0; i <= max_port; i++) + { + if (strlen (p_if_list->netif[i].name) == 0) + { + printf ("Error: Zero length network interface name (%d).\n", i); + ret = -1; + } + } + } + + return ret; +} + +int app_pnet_cfg_init_netifs ( + const char * netif_list_str, + pnet_cfg_t * p_cfg, + int verbosity) +{ + int ret = 0; + int i = 0; + pnal_ipaddr_t ip; + pnal_ipaddr_t netmask; + pnal_ipaddr_t gateway; + app_netif_namelist_t if_list; + + ret = app_get_netif_namelist (netif_list_str, &if_list, PNET_MAX_PORT); + if (ret != 0) + { + return ret; + } + + if (verbosity > 0) + { + printf ("Management port: "); + } + if ( + app_port_cfg_init ( + if_list.netif[0].name, + &p_cfg->if_cfg.main_port, + verbosity) != 0) + { + return -1; + } + + for (i = 1; i <= PNET_MAX_PORT; i++) + { + if (verbosity > 0) + { + printf ("Physical port [%u]: ", i); + } + + if ( + app_port_cfg_init ( + if_list.netif[i].name, + &p_cfg->if_cfg.ports[i - 1].phy_port, + verbosity) != 0) + { + return -1; + } + } + + /* Read IP, netmask, gateway from operating system */ + ip = pnal_get_ip_address (if_list.netif[0].name); + netmask = pnal_get_netmask (if_list.netif[0].name); + gateway = pnal_get_gateway (if_list.netif[0].name); + + if (gateway == IP_INVALID) + { + printf ( + "Error: Invalid gateway IP address for Ethernet interface: %s\n", + if_list.netif[0].name); + return -1; + } + + if (verbosity > 0) + { + app_print_network_details (ip, netmask, gateway); + } + + app_copy_ip_to_struct (&p_cfg->if_cfg.ip_cfg.ip_addr, ip); + app_copy_ip_to_struct (&p_cfg->if_cfg.ip_cfg.ip_gateway, gateway); + app_copy_ip_to_struct (&p_cfg->if_cfg.ip_cfg.ip_mask, netmask); + + return ret; +} + /*************************** Helper functions ********************************/ void app_copy_ip_to_struct ( diff --git a/sample_app/sampleapp_common.h b/sample_app/sampleapp_common.h index d061fbbe..7d85098a 100644 --- a/sample_app/sampleapp_common.h +++ b/sample_app/sampleapp_common.h @@ -71,7 +71,7 @@ extern "C" { #define APP_LOGBOOK_ERROR_CODE 0x20 /* Manufacturer specific */ #define APP_LOGBOOK_ERROR_DECODE 0x82 /* Manufacturer specific */ #define APP_LOGBOOK_ERROR_CODE_1 PNET_ERROR_CODE_1_FSPM -#define APP_LOGBOOK_ERROR_CODE_2 0x00 /* Manufacturer specific */ +#define APP_LOGBOOK_ERROR_CODE_2 0x00 /* Manufacturer specific */ #define APP_LOGBOOK_ENTRY_DETAIL 0xFEE1DEAD /* Manufacturer specific */ /* @@ -132,6 +132,33 @@ static const cfg_submodule_type_t cfg_available_submodule_types[] = { PNET_DIR_NO_IO, 0, 0}, +#if PNET_MAX_PORT >= 2 + {"DAP Port 2", + APP_API, + PNET_MOD_DAP_IDENT, + PNET_SUBMOD_DAP_INTERFACE_1_PORT_2_IDENT, + PNET_DIR_NO_IO, + 0, + 0}, +#endif +#if PNET_MAX_PORT >= 3 + {"DAP Port 3", + APP_API, + PNET_MOD_DAP_IDENT, + PNET_SUBMOD_DAP_INTERFACE_1_PORT_3_IDENT, + PNET_DIR_NO_IO, + 0, + 0}, +#endif +#if PNET_MAX_PORT >= 4 + {"DAP Port 4", + APP_API, + PNET_MOD_DAP_IDENT, + PNET_SUBMOD_DAP_INTERFACE_1_PORT_4_IDENT, + PNET_DIR_NO_IO, + 0, + 0}, +#endif {"Input 8 bits", APP_API, APP_MOD_8_0_IDENT, @@ -162,14 +189,26 @@ struct cmd_args char path_button1[PNET_MAX_FILE_FULLPATH_SIZE]; /** Terminated string */ char path_button2[PNET_MAX_FILE_FULLPATH_SIZE]; /** Terminated string */ char path_storage_directory[PNET_MAX_DIRECTORYPATH_SIZE]; /** Terminated */ - char station_name[PNET_STATION_NAME_MAX_SIZE]; /** Terminated string */ - char eth_interface[PNET_INTERFACE_NAME_MAX_SIZE]; /** Terminated string */ + char station_name[PNET_STATION_NAME_MAX_SIZE]; /** Terminated string */ + char eth_interfaces + [PNET_INTERFACE_NAME_MAX_SIZE * (PNET_MAX_PORT + 1) + + PNET_MAX_PORT]; /** Terminated string */ int verbosity; int show; bool factory_reset; bool remove_files; }; +typedef struct app_netif_name +{ + char name[PNET_INTERFACE_NAME_MAX_SIZE]; +} app_netif_name_t; + +typedef struct app_netif_namelist +{ + app_netif_name_t netif[PNET_MAX_PORT + 1]; +} app_netif_namelist_t; + typedef struct app_subslot { bool used; @@ -233,9 +272,16 @@ typedef enum app_demo_state /********************* Helper function declarations ***************************/ /** - * Print out current IP address, MAC address etc. + * Convert MAC address to string + * @param mac In: MAC address + * @param outputstring Out: Resulting string buffer. Should have size + * PNAL_ETH_ADDRSTR_SIZE. + */ +void app_mac_to_string (pnal_ethaddr_t mac, char * outputstring); + +/** + * Print out current IP address, netmask and default gateway. * - * @param p_macbuffer In: MAC address * @param ip In: IP address * @param netmask In: Netmask * @param gateway In: Gateway @@ -243,7 +289,6 @@ typedef enum app_demo_state * -1 if an error occurred. */ void app_print_network_details ( - pnal_ethaddr_t * p_macbuffer, pnal_ipaddr_t ip, pnal_ipaddr_t netmask, pnal_ipaddr_t gateway); @@ -255,7 +300,45 @@ void app_print_network_details ( * @return 0 if the operation succeeded. * -1 if an error occurred. */ -int app_adjust_stack_configuration (pnet_cfg_t * stack_config); +int app_pnet_cfg_init_default (pnet_cfg_t * stack_config); + +/** + * Initialize interface configuration from argument string. + * + * @param netif_list_str In: Comma separated list of network interfaces. + * Terminated string. + * @param p_cfg InOut: p-net configuration + * @param verbosity In: Verbosity + * @return 0 on success + * -1 on error + */ +int app_pnet_cfg_init_netifs ( + const char * netif_list_str, + pnet_cfg_t * p_cfg, + int verbosity); + +/** + * Parse a comma separated list of network interfaces and check + * that the number of interfaces match the PNET_MAX_PORT configuration. + * Examples: + * PNET_MAX_PORT arg_str status + * 1 "eth0" ok + * 1 "eth0,eth1" err + * 2 "br0,eth0,eth1" ok + * 2 "br0,eth0," err + * + * @param arg_str In: Network interface list as comma separated, + * terminated string. For example "eth0" or + * "br0,eth0,eth1". + * @param p_if_list Out: List of network interfaces + * @param max_port In: PNET_MAX_PORT, passed as argument to allow test + * @return 0 if network interface list matches configuration + * -1 on error + */ +int app_get_netif_namelist ( + const char * arg_str, + app_netif_namelist_t * p_if_list, + int max_port); /** * Plug DAP (sub-)modules. This operation shall be called after p-net diff --git a/src/common/pf_eth.c b/src/common/pf_eth.c index 426c2ed3..92c4f5d0 100644 --- a/src/common/pf_eth.c +++ b/src/common/pf_eth.c @@ -32,13 +32,68 @@ #include #include "pf_includes.h" -int pf_eth_init (pnet_t * net) +int pf_eth_init (pnet_t * net, const pnet_cfg_t * p_cfg) { - int ret = 0; + int port; + pf_port_iterator_t port_iterator; + pf_port_t * p_port_data; + const pnet_port_cfg_t * p_port_cfg; + pnal_ethertype_t main_port_receive_type; memset (net->eth_id_map, 0, sizeof (net->eth_id_map)); - return ret; +#if (PNET_MAX_PORT == 1) + main_port_receive_type = PNAL_ETHTYPE_ALL; +#else + main_port_receive_type = PNAL_ETHTYPE_PROFINET; +#endif + + /* Init management port */ + net->eth_handle = pnal_eth_init ( + p_cfg->if_cfg.main_port.if_name, + main_port_receive_type, + pf_eth_recv, + (void *)net); + if (net->eth_handle == NULL) + { + LOG_ERROR ( + PNET_LOG, + "Failed to init \"%s\"\n", + p_cfg->if_cfg.main_port.if_name); + return -1; + } + + /* Init physical ports */ + pf_port_init_iterator_over_ports (net, &port_iterator); + port = pf_port_get_next (&port_iterator); + while (port != 0) + { + p_port_data = pf_port_get_state (net, port); + p_port_cfg = pf_port_get_config (net, port); + +#if PNET_MAX_PORT > 1 + p_port_data->eth_handle = pnal_eth_init ( + p_port_cfg->phy_port.if_name, + PNAL_ETHTYPE_LLDP, + pf_eth_recv, + (void *)net); +#else + /* In single port configuration managed port is also physical port 1 */ + p_port_data->eth_handle = net->eth_handle; +#endif + + if (p_port_data->eth_handle == NULL) + { + LOG_ERROR ( + PNET_LOG, + "Failed to init \"%s\"\n", + p_port_cfg->phy_port.if_name); + return -1; + } + + port = pf_port_get_next (&port_iterator); + } + return 0; } int pf_eth_send (pnet_t * net, pnal_eth_handle_t * handle, pnal_buf_t * buf) @@ -56,7 +111,7 @@ int pf_eth_send (pnet_t * net, pnal_eth_handle_t * handle, pnal_buf_t * buf) return sent_len; } -int pf_eth_recv (void * arg, pnal_buf_t * p_buf) +int pf_eth_recv (pnal_eth_handle_t * eth_handle, void * arg, pnal_buf_t * p_buf) { int ret = 0; /* Means: "Not handled" */ uint16_t eth_type_pos = 2 * sizeof (pnet_ethaddr_t); @@ -106,7 +161,7 @@ int pf_eth_recv (void * arg, pnal_buf_t * p_buf) } break; case PNAL_ETHTYPE_LLDP: - ret = pf_lldp_recv (net, p_buf, frame_pos); + ret = pf_lldp_recv (net, eth_handle, p_buf, frame_pos); break; case PNAL_ETHTYPE_IP: /* IP-packets (UDP) are also received via the UDP sockets. Do not count diff --git a/src/common/pf_eth.h b/src/common/pf_eth.h index fce1123b..00e8c197 100644 --- a/src/common/pf_eth.h +++ b/src/common/pf_eth.h @@ -21,12 +21,17 @@ extern "C" { #endif /** - * Initialize the ETH component. + * Initialize ETH component and network interfaces according to configuration + * If device is configured with one network interface (PNET_MAX_PORT==1), + * the management port and physical port 1 refers to same network interface. + * In a multi port configuration, the management port and physical ports are + * different network interfaces. * @param net InOut: The p-net stack instance - * @return 0 if the ETH component could be initialized. - * -1 if an error occurred. + * @param p_cfg In: Configuration + * @return 0 on success + * -1 on error */ -int pf_eth_init (pnet_t * net); +int pf_eth_init (pnet_t * net, const pnet_cfg_t * p_cfg); /** * Send raw Ethernet data. @@ -71,15 +76,16 @@ void pf_eth_frame_id_map_remove (pnet_t * net, uint16_t frame_id); * handler, depending on the frame_id within the packet. The frame_id is located * right after the packet type. Take care of handling the VLAN tag!! * - * Note that this itself is a callback, and its arguments should fulfill the - * prototype os_raw_frame_handler_t + * Note also that this function is a callback and will be passed as an argument + * to pnal_eth_init(). * + * @param eth_handle InOut: Network interface the frame was received on. * @param arg InOut: User argument, will be converted to pnet_t - * @param p_buf In: The Ethernet frame. Might be freed. + * @param p_buf InOut: The Ethernet frame. Might be freed. * @return 0 If the frame was NOT handled by this function. * 1 If the frame was handled and the buffer freed. */ -int pf_eth_recv (void * arg, pnal_buf_t * p_buf); +int pf_eth_recv (pnal_eth_handle_t * eth_handle, void * arg, pnal_buf_t * p_buf); #ifdef __cplusplus } diff --git a/src/common/pf_lldp.c b/src/common/pf_lldp.c index cec348fc..715445e7 100644 --- a/src/common/pf_lldp.c +++ b/src/common/pf_lldp.c @@ -849,10 +849,11 @@ size_t pf_lldp_construct_frame (pnet_t * net, int loc_port_num, uint8_t buf[]) } LOG_DEBUG ( PF_LLDP_LOG, - "LLDP(%d): Sending LLDP frame. MAC " + "LLDP(%d): Send port %u MAC: " "%02X:%02X:%02X:%02X:%02X:%02X " - "IP: %s Chassis ID: \"%s\" Port number: %u Port ID: \"%s\"\n", + "IP: %s Chassis ID: \"%s\" Port ID: \"%s\"\n", __LINE__, + loc_port_num, device_mac_address->addr[0], device_mac_address->addr[1], device_mac_address->addr[2], @@ -861,7 +862,6 @@ size_t pf_lldp_construct_frame (pnet_t * net, int loc_port_num, uint8_t buf[]) device_mac_address->addr[5], ip_string, chassis_id_description, - loc_port_num, p_port_cfg->port_id); #endif @@ -901,6 +901,7 @@ static void pf_lldp_send (pnet_t * net, int loc_port_num) { /* FIXME: Buffer size should include Ethernet header (14 bytes) */ pnal_buf_t * p_buffer = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE); + pf_port_t * p_port_data = pf_port_get_state (net, loc_port_num); if (p_buffer != NULL) { @@ -909,7 +910,7 @@ static void pf_lldp_send (pnet_t * net, int loc_port_num) p_buffer->len = pf_lldp_construct_frame (net, loc_port_num, p_buffer->payload); - (void)pf_eth_send (net, net->eth_handle, p_buffer); + (void)pf_eth_send (net, p_port_data->eth_handle, p_buffer); } pnal_buf_free (p_buffer); @@ -1728,11 +1729,16 @@ void pf_lldp_update_peer ( pf_lldp_store_peer_info (net, loc_port_num, lldp_peer_info); } -int pf_lldp_recv (pnet_t * net, pnal_buf_t * p_frame_buf, uint16_t offset) +int pf_lldp_recv ( + pnet_t * net, + pnal_eth_handle_t * eth_handle, + pnal_buf_t * p_frame_buf, + uint16_t offset) { uint8_t * buf = p_frame_buf->payload + offset; uint16_t buf_len = p_frame_buf->len - offset; pf_lldp_peer_info_t peer_data; + int loc_port_num = pf_port_get_port_number (net, eth_handle); int err = 0; err = pf_lldp_parse_packet (buf, buf_len, &peer_data); @@ -1741,9 +1747,10 @@ int pf_lldp_recv (pnet_t * net, pnal_buf_t * p_frame_buf, uint16_t offset) { LOG_DEBUG ( PF_LLDP_LOG, - "LLDP(%d): Received LLDP packet from %02X:%02X:%02X:%02X:%02X:%02X " + "LLDP(%d): Receive port %u MAC: %02X:%02X:%02X:%02X:%02X:%02X " "Len: %d Chassis ID: %s Port ID: %s\n", __LINE__, + loc_port_num, peer_data.mac_address.addr[0], peer_data.mac_address.addr[1], peer_data.mac_address.addr[2], @@ -1754,13 +1761,21 @@ int pf_lldp_recv (pnet_t * net, pnal_buf_t * p_frame_buf, uint16_t offset) peer_data.chassis_id.string, peer_data.port_id.string); - pf_lldp_update_peer (net, PNET_PORT_1, &peer_data); + if (pf_port_is_valid (net, loc_port_num)) + { + pf_lldp_update_peer (net, loc_port_num, &peer_data); + } + else + { + LOG_ERROR ( + PF_LLDP_LOG, + "LLDP(%d): Unexpected local port %u, frame discarded\n", + __LINE__, + loc_port_num); + } } - if (p_frame_buf != NULL) - { - pnal_buf_free (p_frame_buf); - } + pnal_buf_free (p_frame_buf); return 1; /* Means: handled */ } diff --git a/src/common/pf_lldp.h b/src/common/pf_lldp.h index 1433e573..03135965 100644 --- a/src/common/pf_lldp.h +++ b/src/common/pf_lldp.h @@ -341,12 +341,20 @@ void pf_lldp_send_disable (pnet_t * net, int loc_port_num); * Parse LLDP tlv format and store selected information. * Trigger alarms if needed. * @param net InOut: The p-net stack instance. - * @param p_frame_buf InOut: The Ethernet frame. + * @param eth_handle In: Network interface the LLDP message was + * received on. This should be a physical port + * and not the management port (unless system + * only supports a single physical port). + * @param p_frame_buf InOut: Received LLDP message. * @param offset In: The offset to start of LLDP data. * @return 0 If the frame was NOT handled by this function. * 1 If the frame was handled and the buffer freed. */ -int pf_lldp_recv (pnet_t * net, pnal_buf_t * p_frame_buf, uint16_t offset); +int pf_lldp_recv ( + pnet_t * net, + pnal_eth_handle_t * eth_handle, + pnal_buf_t * p_frame_buf, + uint16_t offset); /************ Internal functions, made available for unit testing ************/ diff --git a/src/device/pf_port.c b/src/device/pf_port.c index 0273554a..b164f1e0 100644 --- a/src/device/pf_port.c +++ b/src/device/pf_port.c @@ -120,3 +120,23 @@ bool pf_port_subslot_is_dap_port_id (uint16_t subslot) int port = pf_port_dap_subslot_to_local_port (subslot); return (port != 0); } + +bool pf_port_is_valid (pnet_t * net, int loc_port_num) +{ + return (loc_port_num > 0 && loc_port_num <= PNET_MAX_PORT); +} + +int pf_port_get_port_number (pnet_t * net, pnal_eth_handle_t * eth_handle) +{ + int loc_port_num; + + for (loc_port_num = 1; loc_port_num <= PNET_MAX_PORT; loc_port_num++) + { + if (net->port[loc_port_num - 1].eth_handle == eth_handle) + { + return loc_port_num; + } + } + + return 0; +} diff --git a/src/device/pf_port.h b/src/device/pf_port.h index 7b7198d8..a14b09c0 100644 --- a/src/device/pf_port.h +++ b/src/device/pf_port.h @@ -129,6 +129,28 @@ pf_port_t * pf_port_get_state (pnet_t * net, int loc_port_num); */ const pnet_port_cfg_t * pf_port_get_config (pnet_t * net, int loc_port_num); +/** + * Check if port number corresponds to a valid physical port. + * + * @param net In: The p-net stack instance + * @param loc_port_num In: Local port number. + * Valid range: 1 .. PNET_MAX_PORT + * @return true if port number is valid, + * false if not + */ +bool pf_port_is_valid (pnet_t * net, int loc_port_num); + +/** + * Get port number for network interface. If network interface + * is not a physical port, zero is returned. + * + * @param net In: The p-net stack instance. + * @param eth_handle In: Network interface handle. + * @return local port number + * 0 if no local port matches the network interface handle + */ +int pf_port_get_port_number (pnet_t * net, pnal_eth_handle_t * eth_handle); + #ifdef __cplusplus } #endif diff --git a/src/device/pnet_api.c b/src/device/pnet_api.c index c971dd01..b509b514 100644 --- a/src/device/pnet_api.c +++ b/src/device/pnet_api.c @@ -24,14 +24,12 @@ #include "pf_includes.h" #include "pf_block_reader.h" -int pnet_init_only ( - pnet_t * net, - const pnet_cfg_t * p_cfg) +int pnet_init_only (pnet_t * net, const pnet_cfg_t * p_cfg) { memset (net, 0, sizeof (*net)); - net->cmdev_initialized = false; /* TODO How to handle that pf_cmdev_exit() is - used before pf_cmdev_init()? */ + net->cmdev_initialized = false; /* TODO How to handle that pf_cmdev_exit() + is used before pf_cmdev_init()? */ pf_cmsu_init (net); pf_cmwrr_init (net); @@ -45,16 +43,12 @@ int pnet_init_only ( return -1; } - /* Initialize everything (and the DCP protocol) */ - /* First initialize the network interface */ - net->eth_handle = - pnal_eth_init (p_cfg->if_cfg.main_port.if_name, pf_eth_recv, (void *)net); - if (net->eth_handle == NULL) + if (pf_eth_init (net, p_cfg) != 0) { + LOG_ERROR (PNET_LOG, "Failed to initialise network interfaces\n"); return -1; } - pf_eth_init (net); pf_scheduler_init (net, p_cfg->tick_us); pf_cmina_init (net); /* Read from permanent pool */ @@ -81,8 +75,7 @@ int pnet_init_only ( return 0; } -pnet_t * pnet_init ( - const pnet_cfg_t * p_cfg) +pnet_t * pnet_init (const pnet_cfg_t * p_cfg) { pnet_t * net = NULL; @@ -484,7 +477,7 @@ int pnet_alarm_send_ack ( return ret; } -/************************** Low-level diagnosis functions*********************/ +/************************** Low-level diagnosis functions ******************/ int pnet_diag_add ( pnet_t * net, @@ -545,7 +538,7 @@ int pnet_diag_remove ( usi); } -/************************** Diagnosis in standard format *********************/ +/************************** Diagnosis in standard format *******************/ int pnet_diag_std_add ( pnet_t * net, @@ -596,7 +589,7 @@ int pnet_diag_std_remove ( ext_ch_error_type); } -/************************** Diagnosis in USI format **************************/ +/************************** Diagnosis in USI format ************************/ int pnet_diag_usi_add ( pnet_t * net, diff --git a/src/pf_types.h b/src/pf_types.h index b0cf99ab..51422d18 100644 --- a/src/pf_types.h +++ b/src/pf_types.h @@ -2682,6 +2682,7 @@ typedef struct pf_lldp_port */ typedef struct pf_port { + pnal_eth_handle_t * eth_handle; uint8_t port_num; pf_pdport_t pdport; pf_lldp_port_t lldp; @@ -2703,7 +2704,7 @@ struct pnet uint32_t dcp_sam_timeout; /* Handle to the SAM timeout instance */ uint32_t dcp_identresp_timeout; /* Handle to the DCP identify timeout instance */ - pnal_eth_handle_t * eth_handle; + pnal_eth_handle_t * eth_handle; /* Management port */ pf_eth_frame_id_map_t eth_id_map[PF_ETH_MAX_MAP]; volatile pf_scheduler_timeouts_t scheduler_timeouts[PF_MAX_TIMEOUTS]; volatile uint32_t scheduler_timeout_first; diff --git a/src/pnal.h b/src/pnal.h index 94bfe1ea..3a8e6d87 100644 --- a/src/pnal.h +++ b/src/pnal.h @@ -108,7 +108,7 @@ typedef struct pnal_port_stats #define PNAL_IP4_ADDR_TO_U32(ipaddr, a, b, c, d) \ ipaddr = PNAL_MAKEU32 (a, b, c, d) -enum pnal_eth_type +typedef enum pnal_ethertype { PNAL_ETHTYPE_IP = 0x0800U, PNAL_ETHTYPE_ARP = 0x0806U, @@ -116,7 +116,8 @@ enum pnal_eth_type PNAL_ETHTYPE_PROFINET = 0x8892U, PNAL_ETHTYPE_ETHERCAT = 0x88A4U, PNAL_ETHTYPE_LLDP = 0x88CCU, -}; + PNAL_ETHTYPE_ALL = 0xFFFFU, +} pnal_ethertype_t; /* 255.255.255.255 */ #ifndef PNAL_IPADDR_NONE @@ -262,6 +263,26 @@ pnal_buf_t * pnal_buf_alloc (uint16_t length); void pnal_buf_free (pnal_buf_t * p); uint8_t pnal_buf_header (pnal_buf_t * p, int16_t header_size_increment); +/** + * Network interface handle, forward declaration. + */ +typedef struct pnal_eth_handle_t pnal_eth_handle_t; + +/** + * The prototype of raw Ethernet reception call-back functions. + * + * @param eth_handle InOut: Network interface handle + * @param arg InOut: User-defined (may be NULL). + * @param p_buf InOut: The incoming Ethernet frame + * + * @return 0 If the frame was NOT handled by this function. + * 1 If the frame was handled and the buffer freed. + */ +typedef int (pnal_eth_callback_t) ( + pnal_eth_handle_t * eth_handle, + void * arg, + pnal_buf_t * p_buf); + /** * Get status of Ethernet link on specified port * @@ -316,6 +337,8 @@ int pnal_eth_send (pnal_eth_handle_t * handle, pnal_buf_t * buf); * Initialize receiving of raw Ethernet frames (in separate thread) * * @param if_name In: Ethernet interface name + * @param receive_type In: Ethernet frame types that shall be received + * by the network interface / port. * @param callback In: Callback for received raw Ethernet frames * @param arg InOut: User argument passed to the callback * @@ -323,6 +346,7 @@ int pnal_eth_send (pnal_eth_handle_t * handle, pnal_buf_t * buf); */ pnal_eth_handle_t * pnal_eth_init ( const char * if_name, + pnal_ethertype_t receive_type, pnal_eth_callback_t * callback, void * arg); diff --git a/src/ports/linux/pnal_eth.c b/src/ports/linux/pnal_eth.c index 6879859b..c9fb42fb 100644 --- a/src/ports/linux/pnal_eth.c +++ b/src/ports/linux/pnal_eth.c @@ -28,6 +28,14 @@ #include #include +typedef struct pnal_eth_handle_t +{ + pnal_eth_callback_t * callback; + void * arg; + int socket; + os_thread_t * thread; +} pnal_eth_handle_t; + /** * @internal * Run a thread that listens to incoming raw Ethernet sockets. @@ -56,7 +64,7 @@ static void os_eth_task (void * thread_arg) if (eth_handle->callback != NULL) { - handled = eth_handle->callback (eth_handle->arg, p); + handled = eth_handle->callback (eth_handle, eth_handle->arg, p); } else { @@ -73,6 +81,7 @@ static void os_eth_task (void * thread_arg) pnal_eth_handle_t * pnal_eth_init ( const char * if_name, + pnal_ethertype_t receive_type, pnal_eth_callback_t * callback, void * arg) { @@ -82,6 +91,8 @@ pnal_eth_handle_t * pnal_eth_init ( struct sockaddr_ll sll; int ifindex; struct timeval timeout; + const uint16_t linux_receive_type = + (receive_type == PNAL_ETHTYPE_ALL) ? ETH_P_ALL : receive_type; handle = malloc (sizeof (pnal_eth_handle_t)); if (handle == NULL) @@ -91,7 +102,7 @@ pnal_eth_handle_t * pnal_eth_init ( handle->arg = arg; handle->callback = callback; - handle->socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL)); + handle->socket = socket (PF_PACKET, SOCK_RAW, htons (linux_receive_type)); /* Adjust send timeout */ timeout.tv_sec = 0; @@ -123,7 +134,7 @@ pnal_eth_handle_t * pnal_eth_init ( /* Bind socket to all protocols */ sll.sll_family = AF_PACKET; sll.sll_ifindex = ifindex; - sll.sll_protocol = htons (ETH_P_ALL); + sll.sll_protocol = htons (linux_receive_type); bind (handle->socket, (struct sockaddr *)&sll, sizeof (sll)); if (handle->socket > -1) @@ -142,6 +153,5 @@ pnal_eth_handle_t * pnal_eth_init ( int pnal_eth_send (pnal_eth_handle_t * handle, pnal_buf_t * buf) { int ret = send (handle->socket, buf->payload, buf->len, 0); - return ret; } diff --git a/src/ports/linux/pnal_sys.h b/src/ports/linux/pnal_sys.h index e79123c8..e38d1a51 100644 --- a/src/ports/linux/pnal_sys.h +++ b/src/ports/linux/pnal_sys.h @@ -32,25 +32,6 @@ typedef struct os_buf uint16_t len; } pnal_buf_t; -/** - * The prototype of raw Ethernet reception call-back functions. - * * - * @param arg In: User-defined (may be NULL). - * @param p_buf In: The incoming Ethernet frame - * - * @return 0 If the frame was NOT handled by this function. - * 1 If the frame was handled and the buffer freed. - */ -typedef int (pnal_eth_callback_t) (void * arg, pnal_buf_t * p_buf); - -typedef struct os_eth_handle -{ - pnal_eth_callback_t * callback; - void * arg; - int socket; - os_thread_t * thread; -} pnal_eth_handle_t; - #ifdef __cplusplus } #endif diff --git a/src/ports/linux/sampleapp_main.c b/src/ports/linux/sampleapp_main.c index 545b4c13..f94b9072 100644 --- a/src/ports/linux/sampleapp_main.c +++ b/src/ports/linux/sampleapp_main.c @@ -34,10 +34,19 @@ #include #include +#if PNET_MAX_PORT == 1 #define APP_DEFAULT_ETHERNET_INTERFACE "eth0" -#define APP_THREAD_PRIORITY 15 -#define APP_THREAD_STACKSIZE 4096 /* bytes */ -#define APP_MAIN_SLEEPTIME_US 5000 * 1000 +#elif PNET_MAX_PORT == 2 +#define APP_DEFAULT_ETHERNET_INTERFACE "br0,eth0,eth1" +#elif PNET_MAX_PORT == 3 +#define APP_DEFAULT_ETHERNET_INTERFACE "br0,eth0,eth1,eth2" +#else +#define APP_DEFAULT_ETHERNET_INTERFACE "" +#endif + +#define APP_THREAD_PRIORITY 15 +#define APP_THREAD_STACKSIZE 4096 /* bytes */ +#define APP_MAIN_SLEEPTIME_US 5000 * 1000 /************************* Utilities ******************************************/ @@ -125,7 +134,7 @@ struct cmd_args parse_commandline_arguments (int argc, char * argv[]) strcpy (output_arguments.path_button2, ""); strcpy (output_arguments.path_storage_directory, ""); strcpy (output_arguments.station_name, APP_DEFAULT_STATION_NAME); - strcpy (output_arguments.eth_interface, APP_DEFAULT_ETHERNET_INTERFACE); + strcpy (output_arguments.eth_interfaces, APP_DEFAULT_ETHERNET_INTERFACE); output_arguments.verbosity = 0; output_arguments.show = 0; output_arguments.factory_reset = false; @@ -149,7 +158,12 @@ struct cmd_args parse_commandline_arguments (int argc, char * argv[]) output_arguments.remove_files = true; break; case 'i': - strcpy (output_arguments.eth_interface, optarg); + if ((strlen (optarg) + 1) > sizeof (output_arguments.eth_interfaces)) + { + printf ("Error: The argument to -i is too long.\n"); + exit (EXIT_FAILURE); + } + strcpy (output_arguments.eth_interfaces, optarg); break; case 's': strcpy (output_arguments.station_name, optarg); @@ -299,6 +313,48 @@ void pn_main_thread (void * arg) printf ("Quitting the sample application\n\n"); } +int app_pnet_cfg_init_storage (pnet_cfg_t * p_cfg, struct cmd_args * p_args) +{ + strcpy (p_cfg->file_directory, p_args->path_storage_directory); + + if (p_args->verbosity > 0) + { + printf ("Storage directory: %s\n\n", p_cfg->file_directory); + } + + /* Validate paths */ + if (!pnal_does_file_exist (p_cfg->file_directory)) + { + printf ( + "Error: The given storage directory does not exist: %s\n", + p_cfg->file_directory); + return -1; + } + + if (p_args->path_button1[0] != '\0') + { + if (!pnal_does_file_exist (p_args->path_button1)) + { + printf ( + "Error: The given input file for Button1 does not exist: %s\n", + p_args->path_button1); + return -1; + } + } + + if (p_args->path_button2[0] != '\0') + { + if (!pnal_does_file_exist (p_args->path_button2)) + { + printf ( + "Error: The given input file for Button2 does not exist: %s\n", + p_args->path_button2); + return -1; + } + } + return 0; +} + /****************************** Main ******************************************/ int main (int argc, char * argv[]) @@ -307,10 +363,6 @@ int main (int argc, char * argv[]) pnet_cfg_t pnet_default_cfg; app_data_and_stack_t appdata_and_stack; app_data_t appdata; - pnal_ethaddr_t macbuffer; - pnal_ipaddr_t ip; - pnal_ipaddr_t netmask; - pnal_ipaddr_t gateway; int ret = 0; memset (&appdata, 0, sizeof (appdata)); @@ -331,101 +383,31 @@ int main (int argc, char * argv[]) PNET_MAX_SLOTS); printf ("P-net log level: %u (DEBUG=0, FATAL=4)\n", LOG_LEVEL); printf ("App verbosity level: %u\n", appdata.arguments.verbosity); - printf ("Ethernet interface: %s\n", appdata.arguments.eth_interface); + printf ("Number of ports: %u\n", PNET_MAX_PORT); + printf ("Network interfaces: %s\n", appdata.arguments.eth_interfaces); printf ("Button1 file: %s\n", appdata.arguments.path_button1); printf ("Button2 file: %s\n", appdata.arguments.path_button2); - printf ("Default station name: %s\n", appdata.arguments.station_name); - } - - /* Read IP, netmask, gateway and MAC address from operating system */ - ret = pnal_get_macaddress (appdata.arguments.eth_interface, &macbuffer); - if (ret != 0) - { - printf ( - "Error: The given Ethernet interface does not exist: %s\n", - appdata.arguments.eth_interface); - exit (EXIT_FAILURE); - } - - ip = pnal_get_ip_address (appdata.arguments.eth_interface); - netmask = pnal_get_netmask (appdata.arguments.eth_interface); - gateway = pnal_get_gateway (appdata.arguments.eth_interface); - if (gateway == IP_INVALID) - { - printf ( - "Error: Invalid gateway IP address for Ethernet interface: %s\n", - appdata.arguments.eth_interface); - exit (EXIT_FAILURE); - } - - if (appdata.arguments.verbosity > 0) - { - app_print_network_details (&macbuffer, ip, netmask, gateway); + printf ("Station name: %s\n", appdata.arguments.station_name); } - /* Prepare stack config with IP address, gateway, station name etc */ - app_adjust_stack_configuration (&pnet_default_cfg); - app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_addr, ip); - app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_gateway, gateway); - app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_mask, netmask); - strcpy (pnet_default_cfg.station_name, appdata.arguments.station_name); - strcpy ( - pnet_default_cfg.file_directory, - appdata.arguments.path_storage_directory); - - strncpy ( - pnet_default_cfg.if_cfg.main_port.if_name, - appdata.arguments.eth_interface, - PNET_INTERFACE_NAME_MAX_SIZE); - memcpy ( - pnet_default_cfg.if_cfg.main_port.eth_addr.addr, - macbuffer.addr, - sizeof (pnal_ethaddr_t)); - - strncpy ( - pnet_default_cfg.if_cfg.ports[0].phy_port.if_name, - appdata.arguments.eth_interface, - PNET_INTERFACE_NAME_MAX_SIZE); - memcpy ( - pnet_default_cfg.if_cfg.ports[0].phy_port.eth_addr.addr, - macbuffer.addr, - sizeof (pnal_ethaddr_t)); - + app_pnet_cfg_init_default (&pnet_default_cfg); pnet_default_cfg.cb_arg = (void *)&appdata; + strcpy (pnet_default_cfg.station_name, appdata.arguments.station_name); - if (appdata.arguments.verbosity > 0) + ret = app_pnet_cfg_init_netifs ( + appdata.arguments.eth_interfaces, + &pnet_default_cfg, + appdata.arguments.verbosity); + if (ret != 0) { - printf ("Storage directory: %s\n\n", pnet_default_cfg.file_directory); + exit (EXIT_FAILURE); } - /* Validate paths */ - if (!pnal_does_file_exist (pnet_default_cfg.file_directory)) + ret = app_pnet_cfg_init_storage (&pnet_default_cfg, &appdata.arguments); + if (ret != 0) { - printf ( - "Error: The given storage directory does not exist: %s\n", - pnet_default_cfg.file_directory); exit (EXIT_FAILURE); } - if (appdata.arguments.path_button1[0] != '\0') - { - if (!pnal_does_file_exist (appdata.arguments.path_button1)) - { - printf ( - "Error: The given input file for Button1 does not exist: %s\n", - appdata.arguments.path_button1); - exit (EXIT_FAILURE); - } - } - if (appdata.arguments.path_button2[0] != '\0') - { - if (!pnal_does_file_exist (appdata.arguments.path_button2)) - { - printf ( - "Error: The given input file for Button2 does not exist: %s\n", - appdata.arguments.path_button2); - exit (EXIT_FAILURE); - } - } /* Remove files and exit */ if (appdata.arguments.remove_files == true) diff --git a/src/ports/rt-kernel/dwmac1000.c b/src/ports/rt-kernel/dwmac1000.c index 0c8a3fc0..938c45fe 100644 --- a/src/ports/rt-kernel/dwmac1000.c +++ b/src/ports/rt-kernel/dwmac1000.c @@ -240,7 +240,7 @@ typedef struct dwmac1000 uint32_t cr; } dwmac1000_t; -static pnal_eth_callback_t * input_rx_hook = NULL; +static pnal_eth_sys_recv_callback_t * input_rx_hook = NULL; static void * input_rx_arg = NULL; #ifdef DEBUG_DATA @@ -613,7 +613,7 @@ static void dwmac1000_input (dwmac1000_t * dwmac1000, struct netif * netif) /* Pass pbuf to rx hook if set */ if (input_rx_hook != NULL) { - handled = input_rx_hook (input_rx_arg, p); + handled = input_rx_hook (netif, input_rx_arg, p); if (handled != 0) { return; @@ -719,7 +719,7 @@ int eth_ioctl (drv_t * drv, void * arg, int req, void * param) if (req == IOCTL_NET_SET_RX_HOOK) { - input_rx_hook = (pnal_eth_callback_t *)param; + input_rx_hook = (pnal_eth_sys_recv_callback_t *)param; input_rx_arg = arg; return 0; } diff --git a/src/ports/rt-kernel/pnal_eth.c b/src/ports/rt-kernel/pnal_eth.c index adc1311f..3f593bd8 100644 --- a/src/ports/rt-kernel/pnal_eth.c +++ b/src/ports/rt-kernel/pnal_eth.c @@ -28,42 +28,57 @@ #define MAX_NUMBER_OF_IF 1 #define NET_DRIVER_NAME "/net" -static struct netif * interface[MAX_NUMBER_OF_IF]; +typedef struct pnal_eth_handle_t +{ + struct netif * netif; + pnal_eth_callback_t * eth_rx_callback; + void * arg; +} pnal_eth_handle_t; + +static pnal_eth_handle_t interface[MAX_NUMBER_OF_IF]; static int nic_index = 0; +static int pnal_eth_sys_recv ( + struct netif * netif, + void * arg, + pnal_buf_t * p_buf) +{ + int ret = -1; + pnal_eth_handle_t * handle; + if (arg != NULL && p_buf != NULL) + { + handle = (pnal_eth_handle_t *)arg; + ret = handle->eth_rx_callback (handle, handle->arg, p_buf); + } + return ret; +} + pnal_eth_handle_t * pnal_eth_init ( const char * if_name, + pnal_ethertype_t receive_type, pnal_eth_callback_t * callback, void * arg) { - pnal_eth_handle_t * handle; + pnal_eth_handle_t * handle = NULL; struct netif * found_if; drv_t * drv; - handle = malloc (sizeof (pnal_eth_handle_t)); - UASSERT (handle != NULL, EMEM); - - handle->arg = arg; - handle->callback = callback; - handle->if_id = -1; + (void)receive_type; /* Ignore, for now all frames will be received. */ if (nic_index < MAX_NUMBER_OF_IF) { drv = dev_find_driver (NET_DRIVER_NAME); - if (drv != NULL) + found_if = netif_find (if_name); + if (drv != NULL && found_if != NULL) { - eth_ioctl (drv, arg, IOCTL_NET_SET_RX_HOOK, callback); - - found_if = netif_find (if_name); - if (found_if == NULL) - { - interface[nic_index] = netif_default; - } - else - { - interface[nic_index] = found_if; - } - handle->if_id = nic_index++; + handle = &interface[nic_index]; + nic_index++; + + handle->arg = arg; + handle->eth_rx_callback = callback; + handle->netif = found_if; + + eth_ioctl (drv, handle, IOCTL_NET_SET_RX_HOOK, pnal_eth_sys_recv); } else { @@ -71,15 +86,7 @@ pnal_eth_handle_t * pnal_eth_init ( } } - if (handle->if_id > -1) - { - return handle; - } - else - { - free (handle); - return NULL; - } + return handle; } int pnal_eth_send (pnal_eth_handle_t * handle, pnal_buf_t * buf) @@ -91,9 +98,9 @@ int pnal_eth_send (pnal_eth_handle_t * handle, pnal_buf_t * buf) /* TODO: remove tot_len from os_buff */ buf->tot_len = buf->len; - if (interface[handle->if_id]->linkoutput != NULL) + if (handle->netif->linkoutput != NULL) { - interface[handle->if_id]->linkoutput (interface[handle->if_id], buf); + handle->netif->linkoutput (handle->netif, buf); ret = buf->len; } } diff --git a/src/ports/rt-kernel/pnal_sys.h b/src/ports/rt-kernel/pnal_sys.h index 30a3997e..50e51fb0 100644 --- a/src/ports/rt-kernel/pnal_sys.h +++ b/src/ports/rt-kernel/pnal_sys.h @@ -34,25 +34,12 @@ typedef struct pbuf pnal_buf_t; */ #define IOCTL_NET_SET_RX_HOOK 0x601 -int eth_ioctl (drv_t * drv, void * arg, int req, void * param); +typedef int (pnal_eth_sys_recv_callback_t) ( + struct netif * netif, + void * arg, + pnal_buf_t * p_buf); -/** - * The prototype of raw Ethernet reception call-back functions. - * * - * @param arg In: User-defined (may be NULL). - * @param p_buf In: The incoming Ethernet frame - * - * @return 0 If the frame was NOT handled by this function. - * 1 If the frame was handled and the buffer freed. - */ -typedef int (pnal_eth_callback_t) (void * arg, pnal_buf_t * p_buf); - -typedef struct os_eth_handle -{ - pnal_eth_callback_t * callback; - void * arg; - int if_id; -} pnal_eth_handle_t; +int eth_ioctl (drv_t * drv, void * arg, int req, void * param); #ifdef __cplusplus } diff --git a/src/ports/rt-kernel/sampleapp_main.c b/src/ports/rt-kernel/sampleapp_main.c index 182fd015..7d81f63f 100644 --- a/src/ports/rt-kernel/sampleapp_main.c +++ b/src/ports/rt-kernel/sampleapp_main.c @@ -163,29 +163,22 @@ SHELL_CMD (cmd_pnio_remove_files); int main (void) { int ret = -1; - struct cmd_args cmdline_arguments; app_data_t appdata; - pnal_ethaddr_t macbuffer; - pnal_ipaddr_t ip; - pnal_ipaddr_t netmask; - pnal_ipaddr_t gateway; - g_net = NULL; + gp_appdata = &appdata; /* Prepare appdata */ - memset (&cmdline_arguments, 0, sizeof (cmdline_arguments)); - strcpy (cmdline_arguments.eth_interface, APP_DEFAULT_ETHERNET_INTERFACE); - strcpy (cmdline_arguments.station_name, APP_DEFAULT_STATION_NAME); - cmdline_arguments.verbosity = (LOG_LEVEL <= LOG_LEVEL_WARNING) ? 1 : 0; memset (&appdata, 0, sizeof (appdata)); appdata.alarm_allowed = true; - appdata.arguments = cmdline_arguments; + strcpy (appdata.arguments.eth_interfaces, APP_DEFAULT_ETHERNET_INTERFACE); + strcpy (appdata.arguments.station_name, APP_DEFAULT_STATION_NAME); + appdata.arguments.verbosity = (LOG_LEVEL <= LOG_LEVEL_WARNING) ? 1 : 0; + appdata.main_events = os_event_create(); appdata.main_timer = os_timer_create (APP_TICK_INTERVAL_US, main_timer_tick, NULL, false); - gp_appdata = &appdata; - printf ("\n** Starting Profinet sample application " PNET_VERSION " **\n"); + printf ("\n** Profinet sample application **\n"); if (appdata.arguments.verbosity > 0) { printf ( @@ -193,68 +186,27 @@ int main (void) PNET_MAX_SLOTS); printf ("P-net log level: %u (DEBUG=0, FATAL=4)\n", LOG_LEVEL); printf ("App verbosity level: %u\n", appdata.arguments.verbosity); - printf ("Ethernet interface: %s\n", appdata.arguments.eth_interface); + printf ("Number of ports: %u\n", PNET_MAX_PORT); + printf ("Network interfaces: %s\n", appdata.arguments.eth_interfaces); printf ("Default station name: %s\n", appdata.arguments.station_name); } - /* Read IP, netmask, gateway and MAC address from operating system */ - ret = pnal_get_macaddress (appdata.arguments.eth_interface, &macbuffer); - if (ret != 0) - { - printf ( - "Error: The given Ethernet interface does not exist: %s\n", - appdata.arguments.eth_interface); - return -1; - } + app_pnet_cfg_init_default (&pnet_default_cfg); + pnet_default_cfg.cb_arg = (void *)&appdata; + strcpy (pnet_default_cfg.station_name, appdata.arguments.station_name); + strcpy (pnet_default_cfg.file_directory, APP_DEFAULT_FILE_DIRECTORY); - ip = pnal_get_ip_address (appdata.arguments.eth_interface); - netmask = pnal_get_netmask (appdata.arguments.eth_interface); - gateway = pnal_get_gateway (appdata.arguments.eth_interface); - if (gateway == IP_INVALID) + ret = app_pnet_cfg_init_netifs ( + appdata.arguments.eth_interfaces, + &pnet_default_cfg, + appdata.arguments.verbosity); + if (ret != 0) { - printf ( - "Error: Invalid gateway IP address for Ethernet interface: %s\n", - appdata.arguments.eth_interface); return -1; } - if (appdata.arguments.verbosity > 0) - { - app_print_network_details (&macbuffer, ip, netmask, gateway); - } - - /* Prepare stack config with IP address, gateway, station name etc */ - app_adjust_stack_configuration (&pnet_default_cfg); - app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_addr, ip); - app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_gateway, gateway); - app_copy_ip_to_struct (&pnet_default_cfg.if_cfg.ip_cfg.ip_mask, netmask); - - strcpy (pnet_default_cfg.file_directory, APP_DEFAULT_FILE_DIRECTORY); - strcpy (pnet_default_cfg.station_name, gp_appdata->arguments.station_name); - - strncpy ( - pnet_default_cfg.if_cfg.main_port.if_name, - appdata.arguments.eth_interface, - PNET_INTERFACE_NAME_MAX_SIZE); - memcpy ( - pnet_default_cfg.if_cfg.main_port.eth_addr.addr, - macbuffer.addr, - sizeof (pnet_ethaddr_t)); - - strncpy ( - pnet_default_cfg.if_cfg.ports[0].phy_port.if_name, - appdata.arguments.eth_interface, - PNET_INTERFACE_NAME_MAX_SIZE); - memcpy ( - pnet_default_cfg.if_cfg.ports[0].phy_port.eth_addr.addr, - macbuffer.addr, - sizeof (pnet_ethaddr_t)); - - pnet_default_cfg.cb_arg = (void *)gp_appdata; - - /* Initialize Profinet stack */ - g_net = pnet_init ( - &pnet_default_cfg); + /* Initialize profinet stack */ + g_net = pnet_init (&pnet_default_cfg); if (g_net == NULL) { printf ("Failed to initialize p-net application.\n"); diff --git a/test/mocks.cpp b/test/mocks.cpp index f0fbec7d..056bf2eb 100644 --- a/test/mocks.cpp +++ b/test/mocks.cpp @@ -18,6 +18,13 @@ #include #include +typedef struct pnal_eth_handle_t +{ + const char * if_name; + pnal_eth_callback_t * callback; + void * arg; +} pnal_eth_handle_t; + uint8_t pnet_log_level; os_mutex_t * mock_mutex; @@ -25,6 +32,7 @@ mock_os_data_t mock_os_data; mock_lldp_data_t mock_lldp_data; mock_file_data_t mock_file_data; mock_fspm_data_t mock_fspm_data; +pnal_eth_handle_t mock_eth_handle; void mock_clear (void) { @@ -57,7 +65,13 @@ pnal_eth_handle_t * mock_pnal_eth_init ( { pnal_eth_handle_t * handle; - handle = (pnal_eth_handle_t *)calloc (1, sizeof (pnal_eth_handle_t)); + handle = &mock_eth_handle; + + handle->if_name = if_name; + handle->arg = arg; + handle->callback = callback; + + mock_os_data.eth_if_handle = handle; return handle; } diff --git a/test/mocks.h b/test/mocks.h index 839c1e0c..a9372cad 100644 --- a/test/mocks.h +++ b/test/mocks.h @@ -52,6 +52,7 @@ typedef struct mock_os_data_obj uint32_t system_uptime_10ms; int interface_index; + pnal_eth_handle_t * eth_if_handle; char file_fullpath[100]; /* Full file path at latest save operation */ uint16_t file_size; @@ -82,7 +83,6 @@ typedef struct mock_file_data typedef struct mock_fspm_data { char im_location[PNET_LOCATION_MAX_SIZE]; - } mock_fspm_data_t; extern mock_os_data_t mock_os_data; diff --git a/test/test_cmrpc.cpp b/test/test_cmrpc.cpp index 3a9b432d..db15bed2 100644 --- a/test/test_cmrpc.cpp +++ b/test/test_cmrpc.cpp @@ -659,7 +659,7 @@ TEST_F (CmrpcTest, CmrpcConnectReleaseIOSAR_DA) EXPECT_EQ (appdata.call_counters.state_calls, 1); EXPECT_EQ (appdata.cmdev_state, PNET_EVENT_STARTUP); EXPECT_EQ (appdata.call_counters.connect_calls, 1); - EXPECT_EQ (mock_os_data.eth_send_count, 1); + EXPECT_EQ (mock_os_data.eth_send_count, PNET_MAX_PORT); TEST_TRACE ("\nGenerating mock release request IOSAR_DA\n"); mock_set_pnal_udp_recvfrom_buffer ( diff --git a/test/test_dcp.cpp b/test/test_dcp.cpp index 3509ace7..f4187fa6 100644 --- a/test/test_dcp.cpp +++ b/test/test_dcp.cpp @@ -101,10 +101,10 @@ TEST_F (DcpTest, DcpHelloTest) p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE); memcpy (p_buf->payload, get_name_req, sizeof (get_name_req)); - ret = pf_eth_recv (net, p_buf); + ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf); EXPECT_EQ (ret, 1); - EXPECT_EQ (mock_os_data.eth_send_count, 2); + EXPECT_EQ (mock_os_data.eth_send_count, PNET_MAX_PORT + 1); EXPECT_EQ (appdata.call_counters.led_off_calls, 1); EXPECT_EQ (appdata.call_counters.led_on_calls, 0); @@ -125,36 +125,36 @@ TEST_F (DcpTest, DcpRunTest) TEST_TRACE ("\nGenerating mock set name request\n"); p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE); memcpy (p_buf->payload, set_name_req, sizeof (set_name_req)); - ret = pf_eth_recv (net, p_buf); + ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf); EXPECT_EQ (ret, 1); TEST_TRACE ("\nGenerating mock set IP request\n"); p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE); memcpy (p_buf->payload, set_ip_req, sizeof (set_ip_req)); - ret = pf_eth_recv (net, p_buf); + ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf); EXPECT_EQ (ret, 1); TEST_TRACE ("\nGenerating mock set ident request\n"); p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE); memcpy (p_buf->payload, ident_req, sizeof (ident_req)); - ret = pf_eth_recv (net, p_buf); + ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf); EXPECT_EQ (ret, 1); TEST_TRACE ("\nGenerating mock factory reset request\n"); p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE); memcpy (p_buf->payload, factory_reset_req, sizeof (factory_reset_req)); - ret = pf_eth_recv (net, p_buf); + ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf); EXPECT_EQ (ret, 1); TEST_TRACE ("\nGenerating mock flash LED request\n"); p_buf = pnal_buf_alloc (PF_FRAME_BUFFER_SIZE); memcpy (p_buf->payload, signal_req, sizeof (signal_req)); - ret = pf_eth_recv (net, p_buf); + ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf); EXPECT_EQ (ret, 1); /* Wait for LED to flash three times at 1 Hz */ run_stack (4 * 1000 * 1000); - EXPECT_EQ (mock_os_data.eth_send_count, 9); + EXPECT_EQ (mock_os_data.eth_send_count, 9 + (PNET_MAX_PORT - 1) * 4); EXPECT_EQ (mock_os_data.set_ip_suite_count, 2); EXPECT_EQ (appdata.call_counters.led_on_calls, 3); diff --git a/test/test_lldp.cpp b/test/test_lldp.cpp index 7eae4c08..89b2df26 100644 --- a/test/test_lldp.cpp +++ b/test/test_lldp.cpp @@ -460,7 +460,7 @@ TEST_F (LldpTest, LldpInitTest) EXPECT_EQ (appdata.call_counters.ccontrol_calls, 0); EXPECT_EQ (appdata.call_counters.read_calls, 0); EXPECT_EQ (appdata.call_counters.write_calls, 0); - EXPECT_EQ (mock_os_data.eth_send_count, 1); + EXPECT_EQ (mock_os_data.eth_send_count, PNET_MAX_PORT); } TEST_F (LldpTest, LldpGenerateAliasName) diff --git a/test/utils_for_testing.cpp b/test/utils_for_testing.cpp index 2b07e0f9..1919be67 100644 --- a/test/utils_for_testing.cpp +++ b/test/utils_for_testing.cpp @@ -621,7 +621,7 @@ void PnetIntegrationTestBase::send_data (uint8_t * data_packet, uint16_t len) *(p_ctr + 1) = appdata.data_cycle_ctr & 0xff; p_buf->len = len; - ret = pf_eth_recv (net, p_buf); + ret = pf_eth_recv (mock_os_data.eth_if_handle, net, p_buf); EXPECT_EQ (ret, 1); if (ret == 0) {