| /**************************************************************************** |
| * apps/examples/ipforward/ipforward.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 <nuttx/config.h> |
| |
| #include <sys/ioctl.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <pthread.h> |
| #include <errno.h> |
| |
| #include <net/if.h> |
| #include <arpa/inet.h> |
| |
| #include <nuttx/net/ip.h> |
| #include <nuttx/net/tcp.h> |
| #include <nuttx/net/icmpv6.h> |
| #include <nuttx/net/tun.h> |
| |
| #include "netutils/netlib.h" |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| #define MAX_DEVNAME 8 |
| #define IPFWD_BUFSIZE CONFIG_NET_TUN_PKTSIZE |
| #define NBYTES_PER_LINE 32 |
| #define IPFWD_NPACKETS 3 |
| |
| #ifdef CONFIG_NET_IPv6 |
| # define IPADDR_TYPE FAR const uint16_t * |
| # define IP_HDRLEN IPv6_HDRLEN |
| #else |
| # define IPADDR_TYPE uint32_t |
| # define IP_HDRLEN IPv4_HDRLEN |
| #endif |
| |
| #if defined(CONFIG_NET_ETHERNET) |
| # define MAC_ADDRLEN 6 /* IFHWADDRLEN */ |
| #elif defined(CONFIG_NET_6LOWPAN) |
| # ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR |
| # define MAC_ADDRLEN 10 /* NET_6LOWPAN_EADDRSIZE */ |
| # else |
| # define MAC_ADDRLEN 2 /* NET_6LOWPAN_SADDRSIZE */ |
| # endif |
| #else |
| # define MAC_ADDRLEN 0 /* No link layer address */ |
| #endif |
| |
| /**************************************************************************** |
| * Name: Private Types |
| ****************************************************************************/ |
| |
| struct ipfwd_tun_s |
| { |
| int it_fd; |
| char it_devname[MAX_DEVNAME]; |
| }; |
| |
| struct ipfwd_state_s |
| { |
| struct ipfwd_tun_s if_tun0; |
| struct ipfwd_tun_s if_tun1; |
| pthread_t if_receiver; |
| pthread_t if_sender; |
| }; |
| |
| struct ipfwd_arg_s |
| { |
| int ia_fd; |
| IPADDR_TYPE ia_srcipaddr; |
| IPADDR_TYPE ia_destipaddr; |
| uint8_t ia_buffer[IPFWD_BUFSIZE]; |
| }; |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| /* Network addresses: |
| * |
| * g_tun0_laddr is the address assigned to the tun0 device. g_tun1_laddr |
| * is the address assigned to tun1 device. Both are loal addresses can the |
| * target can received addresses on. |
| * |
| * g_netmask is the network mask that defines the networks: tun0 is on |
| * network 0; tun1 is on network 1. |
| * |
| * g_tun0_raddr and g_tun1_raddr are addresses that are not local to the |
| * target, but should instead be forwarded via the correct network device. |
| * g_tun0_raddr lies on network 0 and g_tun1_raddr lies on network 1 and so |
| * should be forwarded from network 0 to network1 by the NuttX IP forwarding |
| * logic. |
| */ |
| |
| #ifdef CONFIG_NET_IPv6 |
| static const uint16_t g_tun0_laddr[8] = |
| { |
| HTONS(0x7c00), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), /* Netork 0 */ |
| HTONS(0x0097), |
| }; |
| |
| static const uint16_t g_tun1_laddr[8] = |
| { |
| HTONS(0x7c00), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0x0001), /* Netork 1 */ |
| HTONS(0x0139), |
| }; |
| |
| static const uint16_t g_tun0_raddr[8] = |
| { |
| HTONS(0x7c00), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), /* Netork 0 */ |
| HTONS(0x0062), |
| }; |
| |
| static const uint16_t g_tun1_raddr[8] = |
| { |
| HTONS(0x7c00), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0), |
| HTONS(0x0001), /* Netork 1 */ |
| HTONS(0x0147), |
| }; |
| |
| static const uint16_t g_netmask[8] = |
| { |
| HTONS(0xffff), |
| HTONS(0xffff), |
| HTONS(0xffff), |
| HTONS(0xffff), |
| HTONS(0xffff), |
| HTONS(0xffff), |
| HTONS(0xffff), |
| HTONS(0), |
| }; |
| #else |
| static const uint32_t g_tun0_laddr = HTONL(0x0a000097); /* Netork 0 */ |
| static const uint32_t g_tun1_laddr = HTONL(0x0a000139); /* Netork 1 */ |
| static const uint32_t g_tun0_raddr = HTONL(0x0a000062); /* Netork 0 */ |
| static const uint32_t g_tun1_raddr = HTONL(0x0a000147); /* Netork 1 */ |
| static const uint32_t g_netmask = HTONL(0xffffff00); |
| #endif |
| |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_TCP |
| static const char g_payload[] = "Hi there TUN receiver!"; |
| #endif |
| |
| #ifdef CONFIG_NET_IPv4 |
| static uint16_t g_ipid; |
| #endif |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: ipfwd_tun_configure |
| ****************************************************************************/ |
| |
| static int ipfwd_tun_configure(FAR struct ipfwd_tun_s *tun) |
| { |
| struct ifreq ifr; |
| int errcode; |
| int ret; |
| |
| tun->it_fd = open("/dev/tun", O_RDWR); |
| if (tun->it_fd < 0) |
| { |
| errcode = errno; |
| fprintf(stderr, "ERROR: Failed to open /dev/tun: %d\n", errcode); |
| return -errcode; |
| } |
| |
| memset(&ifr, 0, sizeof(ifr)); |
| ifr.ifr_flags = IFF_TUN; |
| |
| ret = ioctl(tun->it_fd, TUNSETIFF, (unsigned long)&ifr); |
| if (ret < 0) |
| { |
| errcode = errno; |
| fprintf(stderr, "ERROR: ioctl TUNSETIFF failed: %d\n", errcode); |
| close(tun->it_fd); |
| return -errcode; |
| } |
| |
| strlcpy(tun->it_devname, ifr.ifr_name, MAX_DEVNAME); |
| printf("Created TUN device: %s\n", tun->it_devname); |
| return 0; |
| } |
| |
| /**************************************************************************** |
| * Name: ipfwd_netconfig |
| ****************************************************************************/ |
| |
| static int ipfwd_netconfig(FAR struct ipfwd_tun_s *tun, IPADDR_TYPE ipaddr, |
| IPADDR_TYPE netmask) |
| { |
| int ret; |
| |
| #ifdef CONFIG_NET_IPv6 |
| |
| struct in6_addr addr; |
| |
| memcpy(addr.s6_addr16, ipaddr, 8 * sizeof(uint16_t)); |
| ret = netlib_set_ipv6addr(tun->it_devname, &addr); |
| if (ret < 0) |
| { |
| fprintf(stderr, "ERROR: netlib_set_ipv6addr() failed with %d\n", ret); |
| return ret; |
| } |
| |
| memcpy(addr.s6_addr16, netmask, 8 * sizeof(uint16_t)); |
| ret = netlib_set_ipv6netmask(tun->it_devname, &addr); |
| if (ret < 0) |
| { |
| fprintf(stderr, "ERROR: netlib_set_ipv6netmask() failed with %d\n", |
| ret); |
| return ret; |
| } |
| |
| #else /* CONFIG_NET_IPv4 */ |
| |
| struct in_addr addr; |
| |
| addr.s_addr = ipaddr; |
| ret = netlib_set_ipv4addr(tun->it_devname, &addr); |
| if (ret < 0) |
| { |
| fprintf(stderr, "ERROR: netlib_set_ipv4addr() failed\n", ret); |
| return ret; |
| } |
| |
| addr.s_addr = netmask; |
| ret = netlib_set_ipv4netmask(tun->it_devname, &addr); |
| if (ret < 0) |
| { |
| fprintf(stderr, "ERROR: netlib_set_ipv4netmask() failed\n", ret); |
| return ret; |
| } |
| #endif |
| |
| netlib_ifup(tun->it_devname); |
| return 0; |
| } |
| |
| /**************************************************************************** |
| * Name: Checksums |
| ****************************************************************************/ |
| |
| static uint16_t chksum(uint16_t sum, FAR const uint8_t *data, uint16_t len) |
| { |
| FAR const uint8_t *dataptr; |
| FAR const uint8_t *last_byte; |
| uint16_t t; |
| |
| dataptr = data; |
| last_byte = data + len - 1; |
| |
| while (dataptr < last_byte) |
| { |
| /* At least two more bytes */ |
| |
| t = ((uint16_t)dataptr[0] << 8) + dataptr[1]; |
| sum += t; |
| if (sum < t) |
| { |
| sum++; /* carry */ |
| } |
| |
| dataptr += 2; |
| } |
| |
| if (dataptr == last_byte) |
| { |
| t = (dataptr[0] << 8) + 0; |
| sum += t; |
| if (sum < t) |
| { |
| sum++; /* carry */ |
| } |
| } |
| |
| /* Return sum in host byte order. */ |
| |
| return sum; |
| } |
| |
| #ifdef CONFIG_NET_IPv4 |
| static uint16_t ipv4_chksum(FAR const uint8_t *buffer) |
| { |
| uint16_t sum; |
| |
| sum = chksum(0, buffer, IPv4_HDRLEN); |
| return (sum == 0) ? 0xffff : htons(sum); |
| } |
| #endif |
| |
| static uint16_t common_chksum(FAR uint8_t *buffer, uint8_t proto) |
| { |
| #ifdef CONFIG_NET_IPv6 |
| FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)buffer; |
| uint16_t upperlen; |
| uint16_t sum; |
| |
| /* The length reported in the IPv6 header is the length of the payload |
| * that follows the header. |
| */ |
| |
| upperlen = ((uint16_t)ipv6->len[0] << 8) + ipv6->len[1]; |
| |
| /* The checksum is calculated starting with a pseudo-header of IPv6 header |
| * fields according to the IPv6 standard, which consists of the source |
| * and destination addresses, the packet length and the next header field. |
| */ |
| |
| sum = upperlen + proto; |
| |
| /* Sum IP source and destination addresses. */ |
| |
| sum = chksum(sum, (FAR uint8_t *)&ipv6->srcipaddr, |
| 2 * sizeof(net_ipv6addr_t)); |
| |
| /* Sum IP payload data. */ |
| |
| sum = chksum(sum, &buffer[IPv6_HDRLEN], upperlen); |
| return (sum == 0) ? 0xffff : htons(sum); |
| #else |
| FAR struct ipv4_hdr_s *ipv4 = (FAR struct ipv4_hdr_s *)buffer; |
| uint16_t upperlen; |
| uint16_t sum; |
| |
| /* The length reported in the IPv4 header is the length of both the IPv4 |
| * header and the payload that follows the header. We need to subtract |
| * the size of the IPv4 header to get the size of the payload. |
| */ |
| |
| upperlen = (((uint16_t)(ipv4->len[0]) << 8) + ipv4->len[1]) - IPv4_HDRLEN; |
| |
| /* First sum pseudo-header. */ |
| |
| /* IP protocol and length fields. This addition cannot carry. */ |
| |
| sum = upperlen + proto; |
| |
| /* Sum IP source and destination addresses. */ |
| |
| sum = chksum(sum, (FAR uint8_t *)&ipv4->srcipaddr, 2 * sizeof(in_addr_t)); |
| |
| /* Sum IP payload data. */ |
| |
| sum = chksum(sum, &buffer[IPv4_HDRLEN], upperlen); |
| return (sum == 0) ? 0xffff : htons(sum); |
| #endif |
| } |
| |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_TCP |
| static uint16_t tcp_chksum(FAR uint8_t *buffer) |
| { |
| return common_chksum(buffer, IP_PROTO_TCP); |
| } |
| #endif /* CONFIG_NET_IPv6 */ |
| |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_ICMPv6 |
| static uint16_t icmpv6_chksum(FAR uint8_t *buffer) |
| { |
| return common_chksum(buffer, IP_PROTO_ICMP6); |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: ipfwd_dumppkt (and friends) |
| ****************************************************************************/ |
| |
| static char lib_nibble(unsigned char nibble) |
| { |
| if (nibble < 10) |
| { |
| return '0' + nibble; |
| } |
| else |
| { |
| return 'a' + nibble - 10; |
| } |
| } |
| |
| static void ipfwd_dumpbuffer(FAR uint8_t *buffer, size_t buflen) |
| { |
| unsigned int i; |
| unsigned int j; |
| unsigned int k; |
| |
| for (i = 0; i < buflen; i += NBYTES_PER_LINE) |
| { |
| putchar(' '); |
| putchar(' '); |
| |
| /* Generate hex values: 2 * NBYTES_PER_LINE + 1 bytes */ |
| |
| for (j = 0; j < NBYTES_PER_LINE; j++) |
| { |
| k = i + j; |
| |
| if (j == (NBYTES_PER_LINE / 2)) |
| { |
| putchar(' '); |
| } |
| |
| if (k < buflen) |
| { |
| putchar(lib_nibble((buffer[k] >> 4) & 0xf)); |
| putchar(lib_nibble(buffer[k] & 0xf)); |
| } |
| else |
| { |
| putchar(' '); |
| putchar(' '); |
| } |
| } |
| |
| putchar('\n'); |
| } |
| } |
| |
| static void ipfwd_dumppkt(FAR uint8_t *buffer, size_t buflen) |
| { |
| size_t dumpsize; |
| |
| if (buflen <= 0) |
| { |
| return; |
| } |
| |
| dumpsize = IP_HDRLEN; |
| if (dumpsize > buflen) |
| { |
| printf("Truncated "); |
| dumpsize = buflen; |
| } |
| |
| printf("IP Header:\n"); |
| ipfwd_dumpbuffer(buffer, dumpsize); |
| |
| buffer += dumpsize; |
| buflen -= dumpsize; |
| if (buflen <= 0) |
| { |
| printf("Packet truncated\n"); |
| return; |
| } |
| |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_TCP |
| dumpsize = TCP_HDRLEN; |
| if (dumpsize > buflen) |
| { |
| printf("Truncated "); |
| dumpsize = buflen; |
| } |
| |
| printf("TCP Header:\n"); |
| ipfwd_dumpbuffer(buffer, dumpsize); |
| |
| buffer += dumpsize; |
| buflen -= dumpsize; |
| if (buflen <= 0) |
| { |
| printf("Packet truncated\n"); |
| return; |
| } |
| |
| printf("Payload:\n"); |
| ipfwd_dumpbuffer(buffer, buflen); |
| #else |
| dumpsize = SIZEOF_ICMPV6_NEIGHBOR_SOLICIT_S(MAC_ADDRLEN); |
| if (dumpsize > buflen) |
| { |
| printf("Truncated "); |
| dumpsize = buflen; |
| } |
| |
| printf("ICMPv6 Neighbor Solicitation:\n"); |
| ipfwd_dumpbuffer(buffer, dumpsize); |
| #endif |
| } |
| |
| /**************************************************************************** |
| * Name: ipfwd_receiver |
| ****************************************************************************/ |
| |
| static FAR void *ipfwd_receiver(FAR void *arg) |
| { |
| FAR struct ipfwd_arg_s *fwd = (FAR struct ipfwd_arg_s *)arg; |
| ssize_t nread; |
| int errcode; |
| int i; |
| |
| for (i = 0; i < IPFWD_NPACKETS; i++) |
| { |
| nread = read(fwd->ia_fd, fwd->ia_buffer, IPFWD_BUFSIZE); |
| if (nread < 0) |
| { |
| errcode = errno; |
| fprintf(stderr, "ERROR: read() failed: %d\n", errcode); |
| break; |
| } |
| |
| printf("Received packet %d: size=%lu\n", |
| i + 1, (unsigned long)nread); |
| ipfwd_dumppkt(fwd->ia_buffer, nread); |
| } |
| |
| return NULL; |
| } |
| |
| /**************************************************************************** |
| * Name: ipfwd_sender |
| ****************************************************************************/ |
| |
| static FAR void *ipfwd_sender(FAR void *arg) |
| { |
| FAR struct ipfwd_arg_s *fwd = (FAR struct ipfwd_arg_s *)arg; |
| #ifdef CONFIG_NET_IPv6 |
| FAR struct ipv6_hdr_s *ipv6; |
| #else |
| FAR struct ipv4_hdr_s *ipv4; |
| #endif |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_TCP |
| FAR struct tcp_hdr_s *tcp; |
| FAR char *payload; |
| #endif |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_ICMPv6 |
| FAR struct icmpv6_neighbor_solicit_s *sol; |
| #endif |
| size_t paysize; |
| size_t pktlen; |
| ssize_t nwritten; |
| uint16_t l3hdrlen; |
| uint8_t proto; |
| int errcode; |
| int i; |
| |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_TCP |
| l3hdrlen = TCP_HDRLEN; |
| paysize = sizeof(g_payload); |
| proto = IP_PROTO_TCP; |
| #else |
| l3hdrlen = SIZEOF_ICMPV6_NEIGHBOR_SOLICIT_S(MAC_ADDRLEN); |
| paysize = 0; |
| proto = IP_PROTO_ICMP6; |
| #endif |
| |
| for (i = 0; i < IPFWD_NPACKETS; i++) |
| { |
| #ifdef CONFIG_NET_IPv6 |
| ipv6 = (FAR struct ipv6_hdr_s *)fwd->ia_buffer; |
| |
| /* Set up the IPv6 header */ |
| |
| ipv6->vtc = 0x60; /* Version/traffic class (MS) */ |
| ipv6->tcf = 0; /* Traffic class (LS)/Flow label (MS) */ |
| ipv6->flow = 0; /* Flow label (LS) */ |
| |
| /* Length excludes the IPv6 header */ |
| |
| pktlen = l3hdrlen + paysize; |
| ipv6->len[0] = (pktlen >> 8); |
| ipv6->len[1] = (pktlen & 0xff); |
| |
| ipv6->proto = proto; /* Next header */ |
| ipv6->ttl = 255; /* Hop limit */ |
| |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_TCP |
| /* Set the uniicast destination IP address */ |
| |
| net_ipv6addr_copy(ipv6->destipaddr, fwd->ia_destipaddr); |
| #else |
| /* Set the multicast destination IP address */ |
| |
| ipv6->destipaddr[0] = HTONS(0xff02); |
| ipv6->destipaddr[1] = HTONS(0x0000); |
| ipv6->destipaddr[2] = HTONS(0x0000); |
| ipv6->destipaddr[3] = HTONS(0x0000); |
| ipv6->destipaddr[4] = HTONS(0x0000); |
| ipv6->destipaddr[5] = HTONS(0x0001); |
| ipv6->destipaddr[6] = fwd->ia_destipaddr[6] | HTONS(0xff00); |
| ipv6->destipaddr[7] = fwd->ia_destipaddr[7]; |
| #endif |
| |
| /* Set source IP address. */ |
| |
| net_ipv6addr_copy(ipv6->srcipaddr, fwd->ia_srcipaddr); |
| |
| pktlen = IPv6_HDRLEN + l3hdrlen + paysize; |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_TCP |
| tcp = (FAR struct tcp_hdr_s *) |
| &fwd->ia_buffer[IPv6_HDRLEN]; |
| #else |
| sol = (FAR struct icmpv6_neighbor_solicit_s *) |
| &fwd->ia_buffer[IPv6_HDRLEN]; |
| #endif |
| #else |
| ipv4 = (FAR struct ipv4_hdr_s *)fwd->ia_buffer; |
| |
| /* Set up the IPv4 header */ |
| |
| ipv4->vhl = 0x45; |
| ipv4->tos = 0; |
| |
| pktlen = IPv4_HDRLEN + l3hdrlen + paysize; |
| ipv4->len[0] = (pktlen >> 8); |
| ipv4->len[1] = (pktlen & 0xff); |
| |
| ++g_ipid; |
| ipv4->ipid[0] = g_ipid >> 8; |
| ipv4->ipid[1] = g_ipid & 0xff; |
| |
| ipv4->ipoffset[0] = IP_FLAG_DONTFRAG >> 8; |
| ipv4->ipoffset[1] = IP_FLAG_DONTFRAG & 0xff; |
| ipv4->ttl = IP_TTL; |
| ipv4->proto = proto; |
| |
| net_ipv4addr_hdrcopy(ipv4->srcipaddr, &fwd->ia_srcipaddr); |
| net_ipv4addr_hdrcopy(ipv4->destipaddr, &fwd->ia_destipaddr); |
| |
| /* Calculate IP checksum. */ |
| |
| ipv4->ipchksum = 0; |
| ipv4->ipchksum = ~(ipv4_chksum(fwd->ia_buffer)); |
| |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_TCP |
| tcp = (FAR struct tcp_hdr_s *) |
| &fwd->ia_buffer[IPv4_HDRLEN]; |
| #else |
| sol = (FAR struct icmpv6_neighbor_solicit_s *) |
| &fwd->ia_buffer[IPv4_HDRLEN]; |
| #endif |
| #endif |
| |
| #ifdef CONFIG_EXAMPLES_IPFORWARD_TCP |
| /* Set up the TCP header. NOTE: Most of the elements are irrelevant |
| * in this test. The forwarding is L2 layer only and the L3 header |
| * content is not used in the forwarding. |
| */ |
| |
| memset(tcp, 0, sizeof(struct tcp_hdr_s)); |
| |
| tcp->srcport = HTONS((0x1234 + i) & 0xffff); |
| tcp->destport = HTONS(0xabcd); |
| tcp->tcpoffset = (TCP_HDRLEN / 4) << 4; |
| |
| payload = (FAR char *)tcp + TCP_HDRLEN; |
| memcpy(payload, g_payload, paysize); |
| |
| tcp->tcpchksum = ~tcp_chksum(fwd->ia_buffer); |
| #else |
| /* Set up the ICMPv6 Neighbor Solicitation message */ |
| |
| sol->type = ICMPv6_NEIGHBOR_SOLICIT; /* Message type */ |
| sol->code = 0; /* Message qualifier */ |
| sol->flags[0] = 0; /* flags */ |
| sol->flags[1] = 0; |
| sol->flags[2] = 0; |
| sol->flags[3] = 0; |
| |
| /* Copy the target address into the Neighbor Solicitation message */ |
| |
| net_ipv6addr_copy(sol->tgtaddr, fwd->ia_destipaddr); |
| |
| /* Set up the options */ |
| |
| sol->opttype = ICMPv6_OPT_SRCLLADDR; /* Option type */ |
| sol->optlen = ICMPv6_OPT_OCTECTS(MAC_ADDRLEN); /* Option length in octets */ |
| |
| /* Copy our link layer address into the message */ |
| |
| memset(sol->srclladdr, 0x88, MAC_ADDRLEN); |
| |
| /* Calculate the checksum over both the ICMP header and payload */ |
| |
| sol->chksum = 0; |
| sol->chksum = ~icmpv6_chksum(fwd->ia_buffer); |
| #endif |
| |
| printf("Sending packet %d: size=%lu\n", |
| i + 1, (unsigned long)pktlen); |
| ipfwd_dumppkt(fwd->ia_buffer, pktlen); |
| |
| nwritten = write(fwd->ia_fd, fwd->ia_buffer, pktlen); |
| if (nwritten < 0) |
| { |
| errcode = errno; |
| fprintf(stderr, "ERROR: write() failed: %d\n", errcode); |
| break; |
| } |
| |
| printf(" %lu bytes sent\n", (unsigned long)nwritten); |
| } |
| |
| return NULL; |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: fstest_main |
| ****************************************************************************/ |
| |
| int main(int argc, FAR char *argv[]) |
| { |
| struct ipfwd_state_s fwd; |
| struct ipfwd_arg_s tun0arg; |
| struct ipfwd_arg_s tun1arg; |
| FAR void *value; |
| int errcode = EXIT_SUCCESS; |
| int ret; |
| |
| /* Initialize the first TUN device */ |
| |
| ret = ipfwd_tun_configure(&fwd.if_tun0); |
| if (ret < 0) |
| { |
| fprintf(stderr, "ERROR: Failed to create tun0: %d\n", ret); |
| return ret; |
| } |
| |
| ret = ipfwd_netconfig(&fwd.if_tun0, g_tun0_laddr, g_netmask); |
| if (ret < 0) |
| { |
| fprintf(stderr, "ERROR: ipfwd_netconfig for tun0 failed: %d\n", ret); |
| goto errout_with_tun0; |
| } |
| |
| /* Initialize the second TUN device */ |
| |
| ret = ipfwd_tun_configure(&fwd.if_tun1); |
| if (ret < 0) |
| { |
| fprintf(stderr, "ERROR: Failed to create tun1: %d\n", ret); |
| goto errout_with_tun0; |
| } |
| |
| ret = ipfwd_netconfig(&fwd.if_tun1, g_tun1_laddr, g_netmask); |
| if (ret < 0) |
| { |
| fprintf(stderr, "ERROR: ipfwd_netconfig tun1 failed: %d\n", ret); |
| errcode = EXIT_FAILURE; |
| goto errout_with_tun1; |
| } |
| |
| /* Start receiver thread on tun1 */ |
| |
| tun1arg.ia_fd = fwd.if_tun1.it_fd; |
| tun1arg.ia_srcipaddr = g_tun1_raddr; |
| tun1arg.ia_destipaddr = g_tun0_raddr; |
| |
| ret = pthread_create(&fwd.if_receiver, NULL, ipfwd_receiver, &tun1arg); |
| if (ret != 0) |
| { |
| fprintf(stderr, "ERROR: pthread_create() failed for receiver: %d\n", |
| ret); |
| errcode = EXIT_FAILURE; |
| goto errout_with_tun1; |
| } |
| |
| /* Start sender thread on tun0 */ |
| |
| tun0arg.ia_fd = fwd.if_tun0.it_fd; |
| tun0arg.ia_srcipaddr = g_tun0_raddr; |
| tun0arg.ia_destipaddr = g_tun1_raddr; |
| |
| ret = pthread_create(&fwd.if_sender, NULL, ipfwd_sender, &tun0arg); |
| if (ret != 0) |
| { |
| fprintf(stderr, "ERROR: pthread_create() failed for sender: %d\n", |
| ret); |
| errcode = EXIT_FAILURE; |
| goto errout_with_receiver; |
| } |
| |
| /* Wait for sender thread to terminate */ |
| |
| ret = pthread_join(fwd.if_sender, &value); |
| if (ret != OK) |
| { |
| fprintf(stderr, "ERROR: pthread_join() failed for sender: %d\n", |
| ret); |
| } |
| |
| errout_with_receiver: |
| |
| /* Wait for receiver thread to terminate */ |
| |
| pthread_kill(fwd.if_receiver, 9); |
| ret = pthread_join(fwd.if_receiver, &value); |
| if (ret != OK) |
| { |
| fprintf(stderr, "ERROR: pthread_join() failed for receiver: %d\n", |
| ret); |
| } |
| |
| errout_with_tun1: |
| close(fwd.if_tun1.it_fd); |
| errout_with_tun0: |
| close(fwd.if_tun0.it_fd); |
| return errcode; |
| } |