void fnet_eth_output_ip4(fnet_netif_t *netif, fnet_ip4_addr_t dest_ip_addr, fnet_netbuf_t* nb) { fnet_mac_addr_t destination_addr; /* 48-bit destination address */ fnet_mac_addr_t * dest_ptr; /* Construct Ethernet header. Start with looking up deciding which * MAC address to use as a destination address. Broadcasts and * multicasts are special, all other addresses are looked up in the * ARP table. */ if(fnet_ip_addr_is_broadcast (dest_ip_addr, netif)) { fnet_memcpy (destination_addr, fnet_eth_broadcast, sizeof(fnet_mac_addr_t)); } else if(FNET_IP4_ADDR_IS_MULTICAST(dest_ip_addr)) { /* Hash IP multicast address to MAC address. */ destination_addr[0] = 0x01; destination_addr[1] = 0x0; destination_addr[2] = 0x5e; destination_addr[3] = (unsigned char)(FNET_IP4_ADDR2(dest_ip_addr)& 0x7f); destination_addr[4] = (unsigned char)(FNET_IP4_ADDR3(dest_ip_addr)); destination_addr[5] = (unsigned char)(FNET_IP4_ADDR4(dest_ip_addr)); //TBD Use macro } else /* Unicast address. */ { if((dest_ptr = fnet_arp_lookup(netif, dest_ip_addr))!=0) { fnet_memcpy (destination_addr, *dest_ptr, sizeof(fnet_mac_addr_t)); } else { fnet_arp_resolve(netif, dest_ip_addr, nb); goto EXIT; } } /* Send Ethernet frame. */ ((fnet_eth_if_t *)(netif->if_ptr))->output(netif, FNET_ETH_TYPE_IP4, destination_addr, nb); EXIT: return; }
/************************************************************************ * NAME: fnet_raw_output * * DESCRIPTION: RAW output function *************************************************************************/ static int fnet_raw_output( struct sockaddr *src_addr, const struct sockaddr *dest_addr, unsigned char protocol_number, fnet_socket_option_t *sockoption, fnet_netbuf_t *nb ) { int error = FNET_OK; fnet_netif_t *netif = FNET_NULL; #if FNET_CFG_IP4 if(dest_addr->sa_family == AF_INET) { error = fnet_ip_output(netif, ((struct sockaddr_in *)(src_addr))->sin_addr.s_addr, ((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr, protocol_number, sockoption->ip_opt.tos, #if FNET_CFG_MULTICAST (unsigned char)((FNET_IP4_ADDR_IS_MULTICAST(((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr)?sockoption->ip_opt.ttl_multicast:sockoption->ip_opt.ttl)), #else sockoption->ip_opt.ttl, #endif /* FNET_CFG_MULTICAST */ nb, 0, ((sockoption->flags & SO_DONTROUTE) > 0), 0 ); } #endif #if FNET_CFG_IP6 if(dest_addr->sa_family == AF_INET6) { /* Check Scope ID.*/ netif = fnet_netif_get_by_scope_id( ((const struct sockaddr_in6 *)dest_addr)->sin6_scope_id ); error = fnet_ip6_output( netif, fnet_socket_addr_is_unspecified(src_addr)? FNET_NULL : &((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr, &((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr, protocol_number, FNET_IP6_ADDR_IS_MULTICAST(&((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr)?sockoption->ip6_opt.hops_multicast:sockoption->ip6_opt.hops_unicast, nb,0); } #endif return (error); }
void fnet_eth_output_ip4(fnet_netif_t *netif, fnet_ip4_addr_t dest_ip_addr, fnet_netbuf_t *nb) { fnet_mac_addr_t destination_addr; /* 48-bit destination address */ /* Construct Ethernet header. Start with looking up deciding which * MAC address to use as a destination address. Broadcasts and * multicasts are special, all other addresses are looked up in the * ARP table. */ if(fnet_ip_addr_is_broadcast (dest_ip_addr, netif)) { fnet_memcpy (destination_addr, fnet_eth_broadcast, sizeof(fnet_mac_addr_t)); } else if(FNET_IP4_ADDR_IS_MULTICAST(dest_ip_addr)) { /* Hash IP multicast address to MAC address. */ destination_addr[0] = 0x01U; destination_addr[1] = 0x0U; destination_addr[2] = 0x5eU; destination_addr[3] = (fnet_uint8_t)(FNET_IP4_ADDR2(dest_ip_addr) & 0x7fU); destination_addr[4] = (fnet_uint8_t)(FNET_IP4_ADDR3(dest_ip_addr)); destination_addr[5] = (fnet_uint8_t)(FNET_IP4_ADDR4(dest_ip_addr)); /* TBD Use macro. */ } else /* Unicast address. */ { if(fnet_arp_get_mac( (fnet_netif_desc_t) netif, dest_ip_addr, destination_addr) == FNET_FALSE) { fnet_arp_resolve(netif, dest_ip_addr, nb); goto EXIT; } } /* Send Ethernet frame. */ fnet_eth_output(netif, FNET_ETH_TYPE_IP4, destination_addr, nb); EXIT: return; }
/************************************************************************ * DESCRIPTION: RAW output function *************************************************************************/ static fnet_error_t fnet_raw_output( struct sockaddr *src_addr, const struct sockaddr *dest_addr, fnet_uint8_t protocol_number, fnet_socket_option_t *sockoption, fnet_netbuf_t *nb ) { fnet_error_t error = FNET_ERR_OK; fnet_netif_t *netif = (fnet_netif_t *)fnet_netif_get_by_scope_id( dest_addr->sa_scope_id ); #if FNET_CFG_IP4 if(dest_addr->sa_family == AF_INET) { error = fnet_ip_output(netif, ((struct sockaddr_in *)(src_addr))->sin_addr.s_addr, ((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr, protocol_number, sockoption->ip_opt.tos, #if FNET_CFG_MULTICAST (fnet_uint8_t)((FNET_IP4_ADDR_IS_MULTICAST(((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr) ? sockoption->ip_opt.ttl_multicast : sockoption->ip_opt.ttl)), #else sockoption->ip_opt.ttl, #endif /* FNET_CFG_MULTICAST */ nb, FNET_FALSE, sockoption->so_dontroute, 0 ); } #endif #if FNET_CFG_IP6 if(dest_addr->sa_family == AF_INET6) { error = fnet_ip6_output( netif, fnet_socket_addr_is_unspecified(src_addr) ? FNET_NULL : & ((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr, &((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr, protocol_number, FNET_IP6_ADDR_IS_MULTICAST(&((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr) ? sockoption->ip6_opt.hops_multicast : sockoption->ip6_opt.hops_unicast, nb, 0); } #endif return (error); }
/************************************************************************ * NAME: fnet_icmp_input * * DESCRIPTION: ICMP input function. *************************************************************************/ static void fnet_icmp_input(fnet_netif_t *netif, struct sockaddr *src_addr, struct sockaddr *dest_addr, fnet_netbuf_t *nb, fnet_netbuf_t *ip4_nb) { fnet_icmp_header_t *hdr; fnet_prot_notify_t prot_cmd; fnet_ip4_addr_t src_ip; fnet_ip4_addr_t dest_ip; fnet_netbuf_free_chain(ip4_nb); /* Not used.*/ if((netif != 0) && (nb != 0) ) { if(fnet_netbuf_pullup(&nb, sizeof(fnet_icmp_header_t)) == FNET_ERR) /* The header must reside in contiguous area of memory. */ { goto DISCARD; } hdr = (fnet_icmp_header_t *)nb->data_ptr; src_ip = ((struct sockaddr_in*)(src_addr))->sin_addr.s_addr; dest_ip = ((struct sockaddr_in*)(dest_addr))->sin_addr.s_addr; if( #if FNET_CFG_CPU_ETH_HW_RX_PROTOCOL_CHECKSUM || FNET_CFG_CPU_ETH_HW_TX_PROTOCOL_CHECKSUM ((nb->flags & FNET_NETBUF_FLAG_HW_PROTOCOL_CHECKSUM) == 0) && #endif (fnet_checksum(nb, nb->total_length)) || (fnet_ip_addr_is_broadcast(src_ip, netif)) || FNET_IP4_ADDR_IS_MULTICAST(src_ip)) { goto DISCARD; } fnet_icmp_trace("RX", hdr); switch(hdr->type) { /************************** * ICMP Request Processing **************************/ case FNET_ICMP_ECHO: if((nb->total_length < sizeof(fnet_icmp_echo_header_t)) || /* An ICMP Echo Request destined to an IP broadcast or IP * multicast address MAY be silently discarded.(RFC1122)*/ (fnet_ip_addr_is_broadcast(dest_ip, netif)) || FNET_IP4_ADDR_IS_MULTICAST(dest_ip)) { goto DISCARD; } hdr->type = FNET_ICMP_ECHOREPLY; fnet_icmp_output(netif, dest_ip, src_ip, nb); break; #if 0 /* Optional functionality.*/ /************************ * Time Stamp Query ************************/ case FNET_ICMP_TSTAMP: /* The header must reside in contiguous area of memory. */ if(fnet_netbuf_pullup(&nb, sizeof(fnet_icmp_timestamp_header_t)) == FNET_ERR) { goto DISCARD; } hdr = nb->data_ptr; hdr->type = FNET_ICMP_TSTAMPREPLY; /* All times are in milliseconds since the stack timer start modulo 1 day. * The high-order bit is set as the time value is recorded in nonstandard units. */ ((fnet_icmp_timestamp_header_t *)hdr)->receive_timestamp = fnet_htonl(((fnet_timer_ticks() * FNET_TIMER_PERIOD_MS) % (24 * 60 * 60 * 1000)) | (0x80000000)); dest_ip = netif->ip4_addr.address; fnet_icmp_output(netif, dest_ip, src_ip, nb); break; /************************ * Address Mask Query ************************/ case FNET_ICMP_MASKREQ: /* The header must reside in contiguous area of memory*/ if(fnet_netbuf_pullup(&nb, sizeof(fnet_icmp_mask_header_t)) == FNET_ERR) { goto DISCARD; } hdr = nb->data_ptr; hdr->type = FNET_ICMP_MASKREPLY; ((fnet_icmp_mask_header_t *)hdr)->mask = netif->ip4_addr.subnetmask; dest_ip = netif->ip4_addr.address; fnet_icmp_output(netif, dest_ip, src_ip, nb); break; #endif /************************** * ICMP Error Processing **************************/ case FNET_ICMP_UNREACHABLE: switch(hdr->code) { case FNET_ICMP_UNREACHABLE_NET: /* net unreachable */ case FNET_ICMP_UNREACHABLE_NET_UNKNOWN: /* unknown net */ case FNET_ICMP_UNREACHABLE_NET_PROHIB: /* prohibited access */ case FNET_ICMP_UNREACHABLE_TOSNET: /* bad tos for net */ prot_cmd = FNET_PROT_NOTIFY_UNREACH_NET; break; case FNET_ICMP_UNREACHABLE_HOST: /* host unreachable */ case FNET_ICMP_UNREACHABLE_HOST_UNKNOWN: /* unknown host */ case FNET_ICMP_UNREACHABLE_ISOLATED: /* src host isolated */ case FNET_ICMP_UNREACHABLE_HOST_PROHIB: /* ditto */ case FNET_ICMP_UNREACHABLE_TOSHOST: /* bad tos for host */ prot_cmd = FNET_PROT_NOTIFY_UNREACH_HOST; break; case FNET_ICMP_UNREACHABLE_PROTOCOL: /* protocol unreachable */ prot_cmd = FNET_PROT_NOTIFY_UNREACH_PROTOCOL; break; case FNET_ICMP_UNREACHABLE_PORT: /* port unreachable */ prot_cmd = FNET_PROT_NOTIFY_UNREACH_PORT; break; case FNET_ICMP_UNREACHABLE_SRCFAIL: /* source route failed */ prot_cmd = FNET_PROT_NOTIFY_UNREACH_SRCFAIL; break; case FNET_ICMP_UNREACHABLE_NEEDFRAG: /* fragmentation needed and DF set*/ prot_cmd = FNET_PROT_NOTIFY_MSGSIZE; break; default: goto DISCARD; } fnet_icmp_notify_protocol(prot_cmd, nb); /* Protocol notification.*/ break; case FNET_ICMP_TIMXCEED: switch(hdr->code) { case FNET_ICMP_TIMXCEED_INTRANS: /* time to live exceeded in transit (ttl==0)*/ prot_cmd = FNET_PROT_NOTIFY_TIMXCEED_INTRANS; break; case FNET_ICMP_TIMXCEED_REASS: /* fragment reassembly time exceeded (ttl==0)*/ prot_cmd = FNET_PROT_NOTIFY_TIMXCEED_REASS; break; default: goto DISCARD; } fnet_icmp_notify_protocol(prot_cmd, nb); /* Protocol notification.*/ break; case FNET_ICMP_PARAMPROB: /* Parameter Problem Message.*/ if(hdr->code > 1u) { goto DISCARD; } prot_cmd = FNET_PROT_NOTIFY_PARAMPROB; fnet_icmp_notify_protocol(prot_cmd, nb); /* Protocol notification.*/ break; case FNET_ICMP_SOURCEQUENCH: /* Source Quench Message; packet lost, slow down.*/ if(hdr->code) { goto DISCARD; } prot_cmd = FNET_PROT_NOTIFY_QUENCH; fnet_icmp_notify_protocol(prot_cmd, nb); /* Protocol notification.*/ break; /************************ * Ignore others ************************/ /* case FNET_ICMP_REDIRECT: case FNET_ICMP_ECHOREPLY: case FNET_ICMP_ROUTERADVERT: case FNET_ICMP_ROUTERSOLICIT: case FNET_ICMP_TSTAMPREPLY: case FNET_ICMP_IREQREPLY: case FNET_ICMP_MASKREPLY:*/ default: goto DISCARD; }/* switch(hdr->type) */ } else { DISCARD: fnet_netbuf_free_chain(nb); } }
/************************************************************************ * NAME: fnet_icmp_error * * DESCRIPTION: Sends ICMP error message. *************************************************************************/ void fnet_icmp_error( fnet_netif_t *netif, fnet_uint8_t type, fnet_uint8_t code, fnet_netbuf_t *nb ) { fnet_ip_header_t *ipheader; fnet_netbuf_t *nb_header; fnet_icmp_err_header_t *icmpheader; fnet_ip4_addr_t source_addr; fnet_ip4_addr_t destination_addr; if(nb) { ipheader = (fnet_ip_header_t *)nb->data_ptr; source_addr = ipheader->source_addr; destination_addr = ipheader->desination_addr; /* Do not send error if not the first fragment of message (RFC1122)*/ if((FNET_IP_HEADER_GET_OFFSET(ipheader) != 0u) || /* Do not send error on ICMP error messages*/ ((ipheader->protocol == FNET_IP_PROTOCOL_ICMP) && (!FNET_ICMP_IS_QUERY_TYPE(((fnet_icmp_header_t *)((fnet_uint8_t *)(nb->data_ptr) + (FNET_IP_HEADER_GET_HEADER_LENGTH(ipheader) << 2)))->type))) /* Do not send error on a datagram whose source address does not define a single * host -- e.g., a zero address, a loopback address, a * broadcast address, a multicast address, or a Class E * address.*/ || (fnet_ip_addr_is_broadcast(source_addr, netif)) || FNET_IP4_ADDR_IS_MULTICAST(source_addr) || FNET_IP4_CLASS_E(source_addr) /* Do not send error on a datagram destined to an IP broadcast or IP multicast address*/ || (fnet_ip_addr_is_broadcast(destination_addr, netif)) || FNET_IP4_ADDR_IS_MULTICAST(destination_addr) /* Do not send error on datagram sent as a link-layer broadcast or multicast.*/ ||((nb->flags & FNET_NETBUF_FLAG_BROADCAST) != 0u) || ((nb->flags & FNET_NETBUF_FLAG_MULTICAST) != 0u) ) { goto FREE_NB; } /* Construct ICMP error header*/ if((nb_header = fnet_netbuf_new((sizeof(fnet_icmp_err_header_t) - sizeof(fnet_ip_header_t)), FNET_FALSE)) == 0) { goto FREE_NB; } icmpheader = (fnet_icmp_err_header_t *)nb_header->data_ptr; icmpheader->fields.unused = 0u; if(type == FNET_ICMP_PARAMPROB) { icmpheader->fields.ptr = fnet_htons((fnet_uint16_t)code); code = 0u; } else if((type == FNET_ICMP_PARAMPROB) && (code == FNET_ICMP_UNREACHABLE_NEEDFRAG) && netif) { icmpheader->fields.mtu = fnet_htons((fnet_uint16_t)netif->mtu); } else {} icmpheader->header.type = type; icmpheader->header.code = code; if((fnet_size_t)((FNET_IP_HEADER_GET_HEADER_LENGTH(ipheader) << 2) + 8u) < nb->total_length) { fnet_netbuf_trim(&nb, (fnet_int32_t)((fnet_size_t)((FNET_IP_HEADER_GET_HEADER_LENGTH(ipheader) << 2) + 8u) - nb->total_length)); } nb = fnet_netbuf_concat(nb_header, nb); fnet_icmp_output(netif, destination_addr, source_addr, nb); return; FREE_NB: fnet_netbuf_free_chain(nb); } }
/************************************************************************ * NAME: fnet_igmp_input * * DESCRIPTION: IGMP input function. *************************************************************************/ static void fnet_igmp_input( fnet_netif_t *netif, fnet_ip4_addr_t src_ip, fnet_ip4_addr_t dest_ip, fnet_netbuf_t *nb, fnet_netbuf_t *ip4_nb) { fnet_igmp_header_t *hdr; fnet_netbuf_t *tmp_nb; int i; FNET_COMP_UNUSED_ARG(dest_ip); FNET_COMP_UNUSED_ARG(src_ip); fnet_netbuf_free_chain(ip4_nb); if((netif != 0) && (nb != 0) ) { /* The header must reside in contiguous area of memory. */ if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_igmp_header_t))) == 0) { goto DISCARD; } nb = tmp_nb; hdr = nb->data_ptr; /* RFC2236 To be valid, the Query message * must be at least 8 octets long, have a correct IGMP * checksum. */ if(fnet_checksum(nb, (int)nb->total_length) ) { goto DISCARD; } fnet_igmp_trace("RX", hdr); /************************** * IGMP QUERY Processing **************************/ if(hdr->type == IGMP_HEADER_TYPE_QUERY) { /* RFC2236: The group address in the IGMP header must either be zero (a General * Query) or a valid multicast group address (a Group-Specific Query). * A General Query applies to all memberships on the interface from * which the Query is received. A Group-Specific Query applies to * membership in a single group on the interface from which the Query * is received. Queries are ignored for memberships in the Non-Member * state. */ if(hdr->group_addr == 0) /* General Query */ { /* Find all joined-groups for this interface.*/ for(i=0; i < FNET_CFG_MULTICAST_MAX; i++) { if((fnet_ip_multicast_list[i].user_counter > 0) && (fnet_ip_multicast_list[i].netif == netif)) { /* Send report.*/ fnet_igmp_join(netif, fnet_ip_multicast_list[i].group_addr ); } } } #if FNET_CFG_IGMP_VERSION == 2 else if(FNET_IP4_ADDR_IS_MULTICAST(hdr->group_addr)) /* A Group-Specific Query.*/ { /* Find specific group.*/ for(i=0; i < FNET_CFG_MULTICAST_MAX; i++) { if((fnet_ip_multicast_list[i].user_counter > 0) && (fnet_ip_multicast_list[i].netif == netif) && (fnet_ip_multicast_list[i].group_addr == hdr->group_addr)) { /* Send report.*/ fnet_igmp_join(netif, fnet_ip_multicast_list[i].group_addr ); break; } } } #endif /* FNET_CFG_IGMP_VERSION */ /* esle wrong */ } /************************ * Ignore others ************************/ } DISCARD: fnet_netbuf_free_chain(nb); }
/************************************************************************ * NAME: fapp_benchrx_cmd * * DESCRIPTION: Start RX Benchmark server. ************************************************************************/ void fapp_benchrx_cmd( fnet_shell_desc_t desc, int argc, char ** argv ) { fnet_address_family_t family; family = AF_SUPPORTED; /* TCP */ if((argc == 1)||(argc == 2 && fnet_strcasecmp("tcp", argv[1]) == 0)) { fapp_bench_tcp_rx(desc, family); } /* UDP */ else if(((argc == 2) || (argc == 3)) && fnet_strcasecmp("udp", argv[1]) == 0) { fnet_ip4_addr_t multicast_address = 0; if(argc == 3) /* Multicast group address.*/ { if((fnet_inet_aton(argv[2], (struct in_addr *) &multicast_address) == FNET_ERR) || !FNET_IP4_ADDR_IS_MULTICAST(multicast_address)) { fnet_shell_println(desc, FAPP_PARAM_ERR, argv[2]); return; } } fapp_bench_udp_rx(desc, family, multicast_address); } else { fnet_shell_println(desc, FAPP_PARAM_ERR, argv[1]); } }
/************************************************************************ * NAME: fnet_udp_output * * DESCRIPTION: UDP output function *************************************************************************/ static fnet_error_t fnet_udp_output( struct sockaddr *src_addr, const struct sockaddr *dest_addr, fnet_socket_option_t *sockoption, fnet_netbuf_t *nb ) { fnet_netbuf_t *nb_header; fnet_udp_header_t *udp_header; fnet_error_t error = FNET_ERR_OK; FNET_COMP_PACKED_VAR fnet_uint16_t *checksum_p; fnet_netif_t *netif = FNET_NULL; fnet_scope_id_t scope_id = 0u; /* Check Scope ID.*/ if(dest_addr->sa_scope_id) /* Take scope id from destination address.*/ { scope_id = dest_addr->sa_scope_id; } else /* Take scope id from source address.*/ { scope_id = src_addr->sa_scope_id; } netif = (fnet_netif_t *)fnet_netif_get_by_scope_id(scope_id); /* It can be FNET_NULL, in case scope_id is 0.*/ /* Construct UDP header.*/ if((nb_header = fnet_netbuf_new(sizeof(fnet_udp_header_t), FNET_TRUE)) == 0) { fnet_netbuf_free_chain(nb); return (FNET_ERR_NOMEM); } udp_header = (fnet_udp_header_t *)nb_header->data_ptr; udp_header->source_port = src_addr->sa_port; /* Source port number.*/ udp_header->destination_port = dest_addr->sa_port; /* Destination port number.*/ nb = fnet_netbuf_concat(nb_header, nb); udp_header->length = fnet_htons((fnet_uint16_t)nb->total_length); /* Length.*/ /* Checksum calculation.*/ udp_header->checksum = 0u; #if FNET_CFG_UDP_CHECKSUM #if FNET_CFG_CPU_ETH_HW_TX_IP_CHECKSUM if( 0 #if FNET_CFG_IP4 ||( (dest_addr->sa_family == AF_INET) && ((netif = fnet_ip_route(((struct sockaddr_in *)(dest_addr))->sin_addr.s_addr))!= FNET_NULL) && (netif->features & FNET_NETIF_FEATURE_HW_TX_PROTOCOL_CHECKSUM) && (fnet_ip_will_fragment(netif, nb->total_length) == FNET_FALSE) /* Fragmented packets are not inspected.*/ ) #endif #if FNET_CFG_IP6 ||( (dest_addr->sa_family == AF_INET6) && (netif || (((netif = fnet_ip6_route(&((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr, &((struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr)))!= FNET_NULL) ) && (netif->features & FNET_NETIF_FEATURE_HW_TX_PROTOCOL_CHECKSUM) && (fnet_ip6_will_fragment(netif, nb->total_length) == FNET_FALSE) /* Fragmented packets are not inspected.*/ ) #endif ) { nb->flags |= FNET_NETBUF_FLAG_HW_PROTOCOL_CHECKSUM; checksum_p = 0; } else #endif /* FNET_CFG_CPU_ETH_HW_TX_IP_CHECKSUM */ { udp_header->checksum = fnet_checksum_pseudo_start( nb, FNET_HTONS((fnet_uint16_t)FNET_IP_PROTOCOL_UDP), (fnet_uint16_t)nb->total_length ); checksum_p = &udp_header->checksum; } #endif /* FNET_CFG_UDP_CHECKSUM */ #if FNET_CFG_IP4 if(dest_addr->sa_family == AF_INET) { error = fnet_ip_output(netif, ((const struct sockaddr_in *)(src_addr))->sin_addr.s_addr, ((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr, FNET_IP_PROTOCOL_UDP, sockoption->ip_opt.tos, #if FNET_CFG_MULTICAST (fnet_uint8_t)((FNET_IP4_ADDR_IS_MULTICAST(((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr)?sockoption->ip_opt.ttl_multicast:sockoption->ip_opt.ttl)), #else sockoption->ip_opt.ttl, #endif /* FNET_CFG_MULTICAST */ nb, FNET_UDP_DF, sockoption->so_dontroute, checksum_p ); } else #endif #if FNET_CFG_IP6 if(dest_addr->sa_family == AF_INET6) { error = fnet_ip6_output( netif, fnet_socket_addr_is_unspecified(src_addr)? FNET_NULL : &((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr, &((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr, FNET_IP_PROTOCOL_UDP, FNET_IP6_ADDR_IS_MULTICAST(&((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr)?sockoption->ip6_opt.hops_multicast:sockoption->ip6_opt.hops_unicast, nb, checksum_p ); } else #endif {} return (error); }