/**************************************************************************** * apps/examples/bridge/bridge_main.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "netutils/netlib.h" #if defined(CONFIG_EXAMPLES_BRIDGE_NET1_DHCPC) || \ defined(CONFIG_EXAMPLES_BRIDGE_NET2_DHCPC) # include "netutils/dhcpc.h" #endif /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /**************************************************************************** * Private Data ****************************************************************************/ static in_addr_t g_net1_ipaddr; static in_addr_t g_net2_ipaddr; static uint8_t g_net1_buffer[CONFIG_EXAMPLES_BRIDGE_NET1_IOBUFIZE]; static uint8_t g_net2_buffer[CONFIG_EXAMPLES_BRIDGE_NET2_IOBUFIZE]; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: briget_net1_setup ****************************************************************************/ static int briget_net1_setup(void) { /* If this task is executed as an NSH built-in function, then the * network has already been configured by NSH's start-up logic. */ #ifndef CONFIG_NSH_NETINIT struct in_addr addr; #if defined(CONFIG_EXAMPLES_BRIDGE_NET1_DHCPC) || \ defined(CONFIG_EXAMPLES_BRIDGE_NET1_NOMAC) uint8_t mac[IFHWADDRLEN]; #endif #ifdef CONFIG_EXAMPLES_BRIDGE_NET1_DHCPC struct dhcpc_state ds; void *handle; char inetaddr[INET_ADDRSTRLEN]; #endif printf("NET1: Configuring %s\n", CONFIG_EXAMPLES_BRIDGE_NET1_IFNAME); /* Many embedded network interfaces must have a software assigned MAC */ #ifdef CONFIG_EXAMPLES_BRIDGE_NET1_NOMAC mac[0] = (CONFIG_EXAMPLES_BRIDGE_NET1_MACADDR >> (8 * 5)) & 0xff; mac[1] = (CONFIG_EXAMPLES_BRIDGE_NET1_MACADDR >> (8 * 4)) & 0xff; mac[2] = (CONFIG_EXAMPLES_BRIDGE_NET1_MACADDR >> (8 * 3)) & 0xff; mac[3] = (CONFIG_EXAMPLES_BRIDGE_NET1_MACADDR >> (8 * 2)) & 0xff; mac[4] = (CONFIG_EXAMPLES_BRIDGE_NET1_MACADDR >> (8 * 1)) & 0xff; mac[5] = (CONFIG_EXAMPLES_BRIDGE_NET1_MACADDR >> (8 * 0)) & 0xff; netlib_setmacaddr(CONFIG_EXAMPLES_BRIDGE_NET1_IFNAME, mac); #endif /* Set up our host address */ #ifdef CONFIG_EXAMPLES_BRIDGE_NET1_DHCPC addr.s_addr = 0; #else addr.s_addr = HTONL(CONFIG_EXAMPLES_BRIDGE_NET1_IPADDR); #endif netlib_set_ipv4addr(CONFIG_EXAMPLES_BRIDGE_NET1_IFNAME, &addr); /* Set up the default router address */ addr.s_addr = HTONL(CONFIG_EXAMPLES_BRIDGE_NET1_DRIPADDR); netlib_set_dripv4addr(CONFIG_EXAMPLES_BRIDGE_NET1_IFNAME, &addr); /* Setup the subnet mask */ addr.s_addr = HTONL(CONFIG_EXAMPLES_BRIDGE_NET1_NETMASK); netlib_set_ipv4netmask(CONFIG_EXAMPLES_BRIDGE_NET1_IFNAME, &addr); /* New versions of netlib_set_ipvXaddr will not bring the network up, * So ensure the network is really up at this point. */ netlib_ifup("eth0"); #ifdef CONFIG_EXAMPLES_BRIDGE_NET1_DHCPC /* Get the MAC address of the NIC */ netlib_getmacaddr(CONFIG_EXAMPLES_BRIDGE_NET1_IFNAME, mac); /* Set up the DHCPC modules */ handle = dhcpc_open("eth0", &mac, IFHWADDRLEN); /* Get an IP address. Note: there is no logic here for renewing the * address in this example. The address should be renewed in * ds.lease_time/2 seconds. */ if (!handle) { fprintf(stderr, "NET1 ERROR: dhcpc_open failed\n"); return ERROR; } if (dhcpc_request(handle, &ds) != OK) { fprintf(stderr, "NET1 ERROR: dhcpc_request failed\n"); return ERROR; } netlib_set_ipv4addr(CONFIG_EXAMPLES_BRIDGE_NET1_IFNAME, &ds.ipaddr); if (ds.netmask.s_addr != 0) { netlib_set_ipv4netmask(CONFIG_EXAMPLES_BRIDGE_NET1_IFNAME, &ds.netmask); } if (ds.default_router.s_addr != 0) { netlib_set_dripv4addr(CONFIG_EXAMPLES_BRIDGE_NET1_IFNAME, &ds.default_router); } if (ds.dnsaddr.s_addr != 0) { netlib_set_ipv4dnsaddr(&ds.dnsaddr); } dhcpc_close(handle); printf("NET1: Assigned IP: %s\n", net_ntoa_r(ds.ipaddr, inetaddr, sizeof(inetaddr))); /* Save the IP address in network order */ g_net1_ipaddr = ds.ipaddr; #else /* Save the IP address in network order */ g_net1_ipaddr = HTONL(CONFIG_EXAMPLES_BRIDGE_NET1_IPADDR); #endif /* CONFIG_EXAMPLES_BRIDGE_NET1_DHCPC */ #else /* CONFIG_NSH_NETINIT */ /* Hmmm.. there is an issue here. Where do we get the IP address if we * are a builtin in application? */ # warning Missing logic #endif /* CONFIG_NSH_NETINIT */ return OK; } /**************************************************************************** * Name: briget_net2_setup ****************************************************************************/ static int briget_net2_setup(void) { /* If this task is executed as an NSH built-in function, then the * network has already been configured by NSH's start-up logic. */ #ifndef CONFIG_NSH_NETINIT struct in_addr addr; #if defined(CONFIG_EXAMPLES_BRIDGE_NET2_DHCPC) || \ defined(CONFIG_EXAMPLES_BRIDGE_NET2_NOMAC) uint8_t mac[IFHWADDRLEN]; #endif #ifdef CONFIG_EXAMPLES_BRIDGE_NET2_DHCPC struct dhcpc_state ds; void *handle; char inetaddr[INET_ADDRSTRLEN]; #endif printf("NET2: Configuring %s\n", CONFIG_EXAMPLES_BRIDGE_NET2_IFNAME); /* Many embedded network interfaces must have a software assigned MAC */ #ifdef CONFIG_EXAMPLES_BRIDGE_NET2_NOMAC mac[0] = (CONFIG_EXAMPLES_BRIDGE_NET2_MACADDR >> (8 * 5)) & 0xff; mac[1] = (CONFIG_EXAMPLES_BRIDGE_NET2_MACADDR >> (8 * 4)) & 0xff; mac[2] = (CONFIG_EXAMPLES_BRIDGE_NET2_MACADDR >> (8 * 3)) & 0xff; mac[3] = (CONFIG_EXAMPLES_BRIDGE_NET2_MACADDR >> (8 * 2)) & 0xff; mac[4] = (CONFIG_EXAMPLES_BRIDGE_NET2_MACADDR >> (8 * 1)) & 0xff; mac[5] = (CONFIG_EXAMPLES_BRIDGE_NET2_MACADDR >> (8 * 0)) & 0xff; netlib_setmacaddr(CONFIG_EXAMPLES_BRIDGE_NET2_IFNAME, mac); #endif /* Set up our host address */ #ifdef CONFIG_EXAMPLES_BRIDGE_NET2_DHCPC addr.s_addr = 0; #else addr.s_addr = HTONL(CONFIG_EXAMPLES_BRIDGE_NET2_IPADDR); #endif netlib_set_ipv4addr(CONFIG_EXAMPLES_BRIDGE_NET2_IFNAME, &addr); /* Set up the default router address */ addr.s_addr = HTONL(CONFIG_EXAMPLES_BRIDGE_NET2_DRIPADDR); netlib_set_dripv4addr(CONFIG_EXAMPLES_BRIDGE_NET2_IFNAME, &addr); /* Setup the subnet mask */ addr.s_addr = HTONL(CONFIG_EXAMPLES_BRIDGE_NET2_NETMASK); netlib_set_ipv4netmask(CONFIG_EXAMPLES_BRIDGE_NET2_IFNAME, &addr); #ifdef CONFIG_EXAMPLES_BRIDGE_NET2_DHCPC /* Get the MAC address of the NIC */ netlib_getmacaddr(CONFIG_EXAMPLES_BRIDGE_NET2_IFNAME, mac); /* Set up the DHCPC modules */ handle = dhcpc_open(&mac, IFHWADDRLEN); /* Get an IP address. Note: there is no logic here for renewing the * address in this example. The address should be renewed in * ds.lease_time/2 seconds. */ if (!handle) { fprintf(stderr, "NET2 ERROR: dhcpc_open failed\n"); return ERROR; } if (dhcpc_request(handle, &ds) != OK) { fprintf(stderr, "NET2 ERROR: dhcpc_request failed\n"); return ERROR; } netlib_set_ipv4addr(CONFIG_EXAMPLES_BRIDGE_NET2_IFNAME, &ds.ipaddr); if (ds.netmask.s_addr != 0) { netlib_set_ipv4netmask(CONFIG_EXAMPLES_BRIDGE_NET2_IFNAME, &ds.netmask); } if (ds.default_router.s_addr != 0) { netlib_set_dripv4addr(CONFIG_EXAMPLES_BRIDGE_NET2_IFNAME, &ds.default_router); } if (ds.dnsaddr.s_addr != 0) { netlib_set_ipv4dnsaddr(&ds.dnsaddr); } dhcpc_close(handle); printf("NET1: Assigned IP: %s\n", inet_ntoa_r(ds.ipaddr, inetaddr, sizeof(inetaddr))); /* Save the IP address in network order */ g_net2_ipaddr = ds.ipaddr; #else /* Save the IP address in network order */ g_net2_ipaddr = HTONL(CONFIG_EXAMPLES_BRIDGE_NET2_IPADDR); #endif /* CONFIG_EXAMPLES_BRIDGE_NET2_DHCPC */ #else /* CONFIG_NSH_NETINIT */ /* Hmmm.. there is an issue here. Where do we get the IP address if we * are a builtin in application? */ # warning Missing logic #endif /* CONFIG_NSH_NETINIT */ return OK; } /**************************************************************************** * Name: bridge_net1_worker ****************************************************************************/ static int bridge_net1_worker(int argc, char *argv[]) { struct sockaddr_in receiver; struct sockaddr_in sender; struct sockaddr_in fromaddr; struct sockaddr_in toaddr; socklen_t addrlen; ssize_t nrecvd; ssize_t nsent; int optval; int recvsd; int sndsd; printf("NET1: Worker started. PID=%d\n", getpid()); /* Create a UDP receive socket on network 1 */ receiver.sin_family = AF_INET; receiver.sin_port = htons(CONFIG_EXAMPLES_BRIDGE_NET1_RECVPORT); receiver.sin_addr.s_addr = g_net1_ipaddr; printf("NET1: Create receive socket: %u.%u.%u.%u:%u\n", ip4_addr1(receiver.sin_addr.s_addr), ip4_addr2(receiver.sin_addr.s_addr), ip4_addr3(receiver.sin_addr.s_addr), ip4_addr4(receiver.sin_addr.s_addr), htons(receiver.sin_port)); recvsd = socket(PF_INET, SOCK_DGRAM, 0); if (recvsd < 0) { fprintf(stderr, "NET1 ERROR: Failed to create receive socket: %d\n", errno); return EXIT_FAILURE; } /* Set socket to reuse address */ optval = 1; if (setsockopt(recvsd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) < 0) { fprintf(stderr, "NET1 ERROR: setsockopt SO_REUSEADDR failure: %d\n", errno); goto errout_with_recvsd; } /* Bind the socket to a local address */ if (bind(recvsd, (struct sockaddr *)&receiver, sizeof(struct sockaddr_in)) < 0) { fprintf(stderr, "NET1 ERROR: bind failure: %d\n", errno); goto errout_with_recvsd; } /* Create a UDP send socket on network 2 */ printf("NET1: Create send socket: %u.%u.%u.%u:INPORT_ANY\n", ip4_addr1(g_net2_ipaddr), ip4_addr2(g_net2_ipaddr), ip4_addr3(g_net2_ipaddr), ip4_addr4(g_net2_ipaddr)); sndsd = socket(PF_INET, SOCK_DGRAM, 0); if (sndsd < 0) { fprintf(stderr, "NET1 ERROR: Failed to create send socket: %d\n", errno); goto errout_with_recvsd; } /* Set socket to reuse address */ optval = 1; if (setsockopt(sndsd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) < 0) { fprintf(stderr, "NET1 ERROR: setsockopt SO_REUSEADDR failure: %d\n", errno); goto errout_with_sendsd; } /* Bind the socket to a local address */ sender.sin_family = AF_INET; sender.sin_port = 0; sender.sin_addr.s_addr = g_net2_ipaddr; if (bind(sndsd, (struct sockaddr *)&sender, sizeof(struct sockaddr_in)) < 0) { printf("NET1: bind failure: %d\n", errno); goto errout_with_sendsd; } /* Then receive and forward UDP packets forever */ for (; ; ) { /* Read a packet on network 1 */ printf("NET1: Receiving up to %d bytes on network 1\n", CONFIG_EXAMPLES_BRIDGE_NET1_IOBUFIZE); addrlen = sizeof(struct sockaddr_in); nrecvd = recvfrom(recvsd, g_net1_buffer, CONFIG_EXAMPLES_BRIDGE_NET1_IOBUFIZE, 0, (FAR struct sockaddr *)&fromaddr, &addrlen); printf("NET1: Received %ld bytes from %u.%u.%u.%u:%u\n", (long)nrecvd, ip4_addr1(fromaddr.sin_addr.s_addr), ip4_addr2(fromaddr.sin_addr.s_addr), ip4_addr3(fromaddr.sin_addr.s_addr), ip4_addr4(fromaddr.sin_addr.s_addr), ntohs(fromaddr.sin_port)); /* Check for a receive error or zero bytes received. The negative * return value indicates a receive error; Zero would mean that the * other side of the "connection" performed an "orderly" shutdown. * This should not occur with a UDP socket and so must also be an * error of some kind. */ if (nrecvd <= 0) { if (nrecvd < 0) { fprintf(stderr, "NET1 ERROR: recvfrom failed: %d\n", errno); } else { fprintf(stderr, "NET1 ERROR: recvfrom returned zero\n"); } goto errout_with_sendsd; } /* Send the newly received packet out network 2 */ toaddr.sin_family = AF_INET; toaddr.sin_port = htons(CONFIG_EXAMPLES_BRIDGE_NET2_HOSTPORT); toaddr.sin_addr.s_addr = htonl(CONFIG_EXAMPLES_BRIDGE_NET2_IPHOST); printf("NET1: Sending %ld bytes on network 2: %u.%u.%u.%u:%u\n", (long)nrecvd, ip4_addr1(toaddr.sin_addr.s_addr), ip4_addr2(toaddr.sin_addr.s_addr), ip4_addr3(toaddr.sin_addr.s_addr), ip4_addr4(toaddr.sin_addr.s_addr), htons(toaddr.sin_port)); nsent = sendto(sndsd, g_net1_buffer, nrecvd, 0, (struct sockaddr *)&toaddr, sizeof(struct sockaddr_in)); /* Check for send errors */ if (nsent < 0) { fprintf(stderr, "NET1 ERROR: sendto failed: %d\n", errno); goto errout_with_sendsd; } else if (nsent != nrecvd) { fprintf(stderr, "NET1 ERROR: Bad send length: %ld Expected: %ld\n", (long)nsent, (long)nrecvd); goto errout_with_sendsd; } } close(recvsd); close(recvsd); return EXIT_SUCCESS; errout_with_sendsd: close(sndsd); errout_with_recvsd: close(recvsd); return EXIT_FAILURE; } /**************************************************************************** * Name: bridge_net2_worker ****************************************************************************/ static int bridge_net2_worker(int argc, char *argv[]) { struct sockaddr_in receiver; struct sockaddr_in sender; struct sockaddr_in fromaddr; struct sockaddr_in toaddr; socklen_t addrlen; ssize_t nrecvd; ssize_t nsent; int optval; int recvsd; int sndsd; printf("NET2: Worker started. PID=%d\n", getpid()); /* Create a UDP receive socket on network 2 */ receiver.sin_family = AF_INET; receiver.sin_port = htons(CONFIG_EXAMPLES_BRIDGE_NET2_RECVPORT); receiver.sin_addr.s_addr = g_net2_ipaddr; printf("NET2: Create receive socket: %u.%u.%u,%u:%u\n", ip4_addr1(receiver.sin_addr.s_addr), ip4_addr2(receiver.sin_addr.s_addr), ip4_addr3(receiver.sin_addr.s_addr), ip4_addr4(receiver.sin_addr.s_addr), htons(receiver.sin_port)); recvsd = socket(PF_INET, SOCK_DGRAM, 0); if (recvsd < 0) { fprintf(stderr, "NET2 ERROR: Failed to create receive socket: %d\n", errno); return EXIT_FAILURE; } /* Set socket to reuse address */ optval = 1; if (setsockopt(recvsd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) < 0) { fprintf(stderr, "NET2 ERROR: setsockopt SO_REUSEADDR failure: %d\n", errno); goto errout_with_recvsd; } /* Bind the socket to a local address */ if (bind(recvsd, (struct sockaddr *)&receiver, sizeof(struct sockaddr_in)) < 0) { fprintf(stderr, "NET2 ERROR: bind failure: %d\n", errno); goto errout_with_recvsd; } /* Create a UDP send socket on network 1 */ printf("NET2: Create send socket: %u.%u.%u.%u:INPORT_ANY\n", ip4_addr1(g_net1_ipaddr), ip4_addr2(g_net1_ipaddr), ip4_addr3(g_net1_ipaddr), ip4_addr4(g_net1_ipaddr)); sndsd = socket(PF_INET, SOCK_DGRAM, 0); if (sndsd < 0) { fprintf(stderr, "NET2 ERROR: Failed to create send socket: %d\n", errno); goto errout_with_recvsd; } /* Set socket to reuse address */ optval = 1; if (setsockopt(sndsd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) < 0) { fprintf(stderr, "NET2 ERROR: setsockopt SO_REUSEADDR failure: %d\n", errno); goto errout_with_sendsd; } /* Bind the socket to a local address */ sender.sin_family = AF_INET; sender.sin_port = 0; sender.sin_addr.s_addr = g_net1_ipaddr; if (bind(sndsd, (struct sockaddr *)&sender, sizeof(struct sockaddr_in)) < 0) { printf("NET2: bind failure: %d\n", errno); goto errout_with_sendsd; } /* Then receive and forward UDP packets forever */ for (; ; ) { /* Read a packet on network 2 */ printf("NET2: Receiving up to %d bytes on network 2\n", CONFIG_EXAMPLES_BRIDGE_NET2_IOBUFIZE); addrlen = sizeof(struct sockaddr_in); nrecvd = recvfrom(recvsd, g_net2_buffer, CONFIG_EXAMPLES_BRIDGE_NET2_IOBUFIZE, 0, (FAR struct sockaddr *)&fromaddr, &addrlen); printf("NET2: Received %ld bytes from %u.%u.%u.%u:%u\n", (long)nrecvd, ip4_addr1(fromaddr.sin_addr.s_addr), ip4_addr2(fromaddr.sin_addr.s_addr), ip4_addr3(fromaddr.sin_addr.s_addr), ip4_addr4(fromaddr.sin_addr.s_addr), ntohs(fromaddr.sin_port)); /* Check for a receive error or zero bytes received. The negative * return value indicates a receive error; Zero would mean that the * other side of the "connection" performed an "orderly" shutdown. * This should not occur with a UDP socket and so must also be an * error of some kind. */ if (nrecvd <= 0) { if (nrecvd < 0) { fprintf(stderr, "NET2 ERROR: recvfrom failed: %d\n", errno); } else { fprintf(stderr, "NET2 ERROR: recvfrom returned zero\n"); } goto errout_with_sendsd; } /* Send the newly received packet out network 1 */ toaddr.sin_family = AF_INET; toaddr.sin_port = htons(CONFIG_EXAMPLES_BRIDGE_NET1_HOSTPORT); toaddr.sin_addr.s_addr = htonl(CONFIG_EXAMPLES_BRIDGE_NET1_IPHOST); printf("NET2: Sending %ld bytes on network 1: %u.%u.%u.%u:%u\n", (long)nrecvd, ip4_addr1(toaddr.sin_addr.s_addr), ip4_addr2(toaddr.sin_addr.s_addr), ip4_addr3(toaddr.sin_addr.s_addr), ip4_addr4(toaddr.sin_addr.s_addr), htons(toaddr.sin_port)); nsent = sendto(sndsd, g_net2_buffer, nrecvd, 0, (struct sockaddr *)&toaddr, sizeof(struct sockaddr_in)); /* Check for send errors */ if (nsent < 0) { fprintf(stderr, "NET2 ERROR: sendto failed: %d\n", errno); goto errout_with_sendsd; } else if (nsent != nrecvd) { fprintf(stderr, "NET2 ERROR: Bad send length: %ld Expected: %ld\n", (long)nsent, (long)nrecvd); goto errout_with_sendsd; } } close(recvsd); close(recvsd); return EXIT_SUCCESS; errout_with_sendsd: close(sndsd); errout_with_recvsd: close(recvsd); return EXIT_FAILURE; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * bridge_main ****************************************************************************/ int main(int argc, FAR char *argv[]) { pid_t net1_worker; pid_t net2_worker; int ret; /* Initialize networks */ ret = briget_net1_setup(); if (ret != OK) { fprintf(stderr, "ERROR: Failed to setup network 1\n"); return EXIT_FAILURE; } ret = briget_net2_setup(); if (ret != OK) { fprintf(stderr, "ERROR: Failed to setup network 2\n"); return EXIT_FAILURE; } /* Start network daemons */ printf("Start network 1 worker\n"); net1_worker = task_create("NET1 Worker", CONFIG_EXAMPLES_BRIDGE_NET1_PRIORITY, CONFIG_EXAMPLES_BRIDGE_NET1_STACKSIZE, bridge_net1_worker, NULL); if (net1_worker < 0) { fprintf(stderr, "ERROR: Failed to start network daemon 1\n"); return EXIT_FAILURE; } printf("Start network 2 worker\n"); net2_worker = task_create("NET2 Worker", CONFIG_EXAMPLES_BRIDGE_NET2_PRIORITY, CONFIG_EXAMPLES_BRIDGE_NET2_STACKSIZE, bridge_net2_worker, NULL); if (net2_worker < 0) { fprintf(stderr, "ERROR: Failed to start network daemon 2\n"); return EXIT_FAILURE; } return EXIT_SUCCESS; }