/************************************************************************ * NAME: fnet_arp_request * * DESCRIPTION: Sends ARP request. *************************************************************************/ void fnet_arp_request( fnet_netif_t *netif, fnet_ip4_addr_t ipaddr ) { fnet_arp_header_t *arp_hdr; fnet_mac_addr_t sender_addr; fnet_netbuf_t *nb; if((nb = fnet_netbuf_new(sizeof(fnet_arp_header_t), FNET_TRUE)) != 0) { arp_hdr = nb->data_ptr; arp_hdr->hard_type = FNET_HTONS(FNET_ARP_HARD_TYPE); /* The type of hardware address (=1 for Ethernet).*/ arp_hdr->prot_type = FNET_HTONS(FNET_ETH_TYPE_IP4); /* The type of protocol address (=0x0800 for IP). */ arp_hdr->hard_size = FNET_ARP_HARD_SIZE; /* The size in bytes of the hardware address (=6). */ arp_hdr->prot_size = FNET_ARP_PROT_SIZE; /* The size in bytes of the protocol address (=4). */ arp_hdr->op = FNET_HTONS(FNET_ARP_OP_REQUEST); /* Opcode. */ fnet_netif_get_hw_addr(netif, sender_addr, sizeof(fnet_mac_addr_t)); fnet_memcpy(arp_hdr->target_hard_addr, fnet_eth_null_addr, sizeof(fnet_mac_addr_t)); fnet_memcpy(arp_hdr->sender_hard_addr, sender_addr, sizeof(fnet_mac_addr_t)); arp_hdr->targer_prot_addr = ipaddr; /* Protocol address of target of this packet.*/ arp_hdr->sender_prot_addr = netif->ip4_addr.address; /* Protocol address of sender of this packet.*/ fnet_arp_trace("TX", arp_hdr); /* Print ARP header. */ ((fnet_eth_if_t *)(netif->if_ptr))->output(netif, FNET_ETH_TYPE_ARP, fnet_eth_broadcast, nb); } }
/************************************************************************ * NAME: fnet_dns_init * * DESCRIPTION: Initializes DNS client service and starts the host * name reolving. ************************************************************************/ static unsigned int fnet_dns_add_question( char *message, unsigned short type, char *host_name) { unsigned int total_length = 0U; unsigned int label_length; fnet_dns_q_tail_t *q_tail; char *strtok_pos = FNET_NULL; /* Set Question section : 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / QNAME / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QTYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QCLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ /* QNAME */ /* a domain name represented as a sequence of labels, where * each label consists of a length octet followed by that * number of octets. The domain name terminates with the * zero length octet for the null label of the root. Note * that this field may be an odd number of octets; no * padding is used. */ /* Copy host_name string.*/ fnet_strcpy(&message[1], host_name); /* TBD PFI, use strtok_pos as pointer.*/ /* Replace '.' by zero.*/ fnet_strtok_r(&message[1], ".", &strtok_pos); while((label_length = fnet_strlen(&message[total_length]+1U)) > 0U) { message[total_length] = (char)label_length; /* Set length before (previous) label.*/ total_length += label_length + 1U; fnet_strtok_r(FNET_NULL,".", &strtok_pos); } q_tail = (fnet_dns_q_tail_t *)&message[total_length]; /* Skip 1 byte (zero). End of string. */ /* QTYPE */ q_tail->qtype = type; /* QCLASS */ q_tail->qclass = FNET_HTONS(FNET_DNS_HEADER_CLASS_IN); return (total_length+ sizeof(fnet_dns_q_tail_t)); }
/************************************************************************ * NAME: fnet_icmp6_output * * DESCRIPTION: ICMPv6 output function. *************************************************************************/ void fnet_icmp6_output( fnet_netif_t *netif, const fnet_ip6_addr_t *src_ip, const fnet_ip6_addr_t *dest_ip, unsigned char hop_limit, fnet_netbuf_t *nb ) { fnet_icmp6_header_t *hdr = nb->data_ptr; FNET_COMP_PACKED_VAR unsigned short *checksum_p; /* Checksum calculation.*/ hdr->checksum = 0; hdr->checksum = fnet_checksum_pseudo_start(nb, FNET_HTONS((unsigned short)FNET_IP_PROTOCOL_ICMP6), (unsigned short)nb->total_length); checksum_p = &hdr->checksum; fnet_ip6_output(netif, src_ip, dest_ip, FNET_IP_PROTOCOL_ICMP6, hop_limit, nb, checksum_p); }
/************************************************************************ * DESCRIPTION: ICMPv6 output function. *************************************************************************/ void fnet_icmp6_output( struct fnet_netif *netif, const fnet_ip6_addr_t *src_ip, const fnet_ip6_addr_t *dest_ip, fnet_uint8_t hop_limit, fnet_netbuf_t *nb ) { fnet_icmp6_header_t *hdr = (fnet_icmp6_header_t *)nb->data_ptr; FNET_COMP_PACKED_VAR fnet_uint16_t *checksum_p; /* Checksum calculation.*/ hdr->checksum = 0u; hdr->checksum = fnet_checksum_pseudo_start(nb, FNET_HTONS((fnet_uint16_t)FNET_IP_PROTOCOL_ICMP6), (fnet_uint16_t)nb->total_length); checksum_p = &hdr->checksum; fnet_ip6_output(netif, src_ip, dest_ip, FNET_IP_PROTOCOL_ICMP6, hop_limit, nb, checksum_p); }
/************************************************************************ * NAME: fnet_icmp6_input * * DESCRIPTION: ICMPv6 input function. *************************************************************************/ static void fnet_icmp6_input(fnet_netif_t *netif, struct sockaddr *src_addr, struct sockaddr *dest_addr, fnet_netbuf_t *nb, fnet_netbuf_t *ip6_nb) { fnet_icmp6_header_t *hdr; fnet_netbuf_t *tmp_nb; unsigned short sum; fnet_ip6_addr_t *src_ip; fnet_ip6_addr_t *dest_ip; fnet_prot_notify_t prot_cmd; if((netif != 0) && (nb != 0)) { /* The header must reside in contiguous area of memory. */ if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp6_header_t))) == 0) { goto DISCARD; } nb = tmp_nb; hdr = nb->data_ptr; dest_ip = &((struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr; src_ip = &((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr; /* Drop Multicast loopback.*/ #if FNET_CFG_LOOPBACK if ((netif == FNET_LOOP_IF) && FNET_IP6_ADDR_IS_MULTICAST(dest_ip)) { goto DISCARD; } #endif /* FNET_CFG_LOOPBACK */ /* Verify the checksum. */ sum = fnet_checksum_pseudo_start( nb, FNET_HTONS((unsigned short)FNET_IP_PROTOCOL_ICMP6), (unsigned short)nb->total_length ); sum = fnet_checksum_pseudo_end( sum, (char *)src_ip, (char *)dest_ip, sizeof(fnet_ip6_addr_t) ); if(sum) goto DISCARD; /************************************************************ * Process incoming ICMPv6 packets. *************************************************************/ switch (hdr->type) { /************************** * Neighbor Solicitation. **************************/ case FNET_ICMP6_TYPE_NEIGHBOR_SOLICITATION: fnet_nd6_neighbor_solicitation_receive(netif, src_ip, dest_ip, nb, ip6_nb); break; /************************** * Neighbor Advertisemnt. **************************/ case FNET_ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT: fnet_nd6_neighbor_advertisement_receive(netif, src_ip, dest_ip, nb, ip6_nb); break; /************************** * Router Advertisemnt. **************************/ case FNET_ICMP6_TYPE_ROUTER_ADVERTISEMENT: fnet_nd6_router_advertisement_receive(netif, src_ip, dest_ip, nb, ip6_nb); break; /************************** * Router Advertisemnt. **************************/ case FNET_ICMP6_TYPE_REDIRECT: fnet_nd6_redirect_receive(netif, src_ip, dest_ip, nb, ip6_nb); break; #if FNET_CFG_MLD /************************** * Multicast Listener Query. **************************/ case FNET_ICMP6_TYPE_MULTICAST_LISTENER_QUERY: fnet_mld_query_receive(netif, src_ip, dest_ip, nb, ip6_nb); break; #endif /************************** * Echo Request. * RFC4443 4.1: Every node MUST implement an ICMPv6 Echo responder function that * receives Echo Requests and originates corresponding Echo Replies. **************************/ case FNET_ICMP6_TYPE_ECHO_REQ: hdr->type = FNET_ICMP6_TYPE_ECHO_REPLY; /* RFC4443: the source address of the reply MUST be a unicast * address belonging to the interface on which * the Echo Request message was received.*/ if(FNET_IP6_ADDR_IS_MULTICAST(dest_ip)) dest_ip = FNET_NULL; fnet_icmp6_output(netif, dest_ip/*ipsrc*/, src_ip/*ipdest*/, 0, nb); fnet_netbuf_free_chain(ip6_nb); break; #if FNET_CFG_IP6_PMTU_DISCOVERY /************************** * Packet Too Big Message. **************************/ case FNET_ICMP6_TYPE_PACKET_TOOBIG: if(netif->pmtu) /* If PMTU is enabled for the interface.*/ { unsigned long pmtu; fnet_icmp6_err_header_t *icmp6_err = nb->data_ptr; /* The header must reside in contiguous area of memory. */ if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp6_err_header_t))) == 0) { goto DISCARD; } nb = tmp_nb; /* RFC 1981.Upon receipt of such a * message, the source node reduces its assumed PMTU for the path based * on the MTU of the constricting hop as reported in the Packet Too Big * message.*/ pmtu = fnet_ntohl(icmp6_err->data); /* A node MUST NOT increase its estimate of the Path MTU in response to * the contents of a Packet Too Big message. */ if(netif->pmtu > pmtu) { fnet_netif_set_pmtu(netif, pmtu); } } goto DISCARD; #endif /************************** * Destination Unreachable. **************************/ case FNET_ICMP6_TYPE_DEST_UNREACH: switch(hdr->code) { case FNET_ICMP6_CODE_DU_NO_ROUTE: /* No route to destination. */ case FNET_ICMP6_CODE_DU_BEYOND_SCOPE: /* Beyond scope of source address.*/ prot_cmd = FNET_PROT_NOTIFY_UNREACH_NET; break; case FNET_ICMP6_CODE_DU_ADMIN_PROHIBITED: /* Communication with destination administratively prohibited. */ case FNET_ICMP6_CODE_DU_ADDR_UNREACH: /* Address unreachable.*/ prot_cmd = FNET_PROT_NOTIFY_UNREACH_HOST; break; case FNET_ICMP6_CODE_DU_PORT_UNREACH: /* Port unreachable.*/ prot_cmd = FNET_PROT_NOTIFY_UNREACH_PORT; break; default: goto DISCARD; } /* Protocol notification.*/ { fnet_ip6_header_t *ip_header; fnet_prot_if_t *protocol; unsigned int hdr_err_length = sizeof(fnet_icmp6_err_header_t) + sizeof(fnet_ip6_header_t); unsigned int hdr_err_data_length = hdr_err_length + 8; /* 8 bytes is enough for transport protocol (port numbers).*/ if(nb->total_length < hdr_err_data_length) { goto DISCARD; } if(nb->total_length > hdr_err_data_length) { fnet_netbuf_trim(&nb, (int)(hdr_err_data_length - nb->total_length)); } if((tmp_nb = fnet_netbuf_pullup(nb, (int)nb->total_length)) == 0) /* The header must reside in contiguous area of memory.*/ { goto DISCARD; } nb = tmp_nb; ip_header = (fnet_ip6_header_t *)((char *)nb->data_ptr + sizeof(fnet_icmp6_err_header_t)); if((protocol = fnet_prot_find(AF_INET6, SOCK_UNSPEC, ip_header->next_header)) != 0) { if(protocol->prot_control_input) { struct sockaddr err_src_addr; struct sockaddr err_dest_addr; /* Prepare addreses for upper protocol.*/ fnet_ip6_set_socket_addr(netif, ip_header, &err_src_addr, &err_dest_addr ); fnet_netbuf_trim(&nb, (int)(hdr_err_length)); /* Cut the ICMP error header.*/ protocol->prot_control_input(prot_cmd, &err_src_addr, &err_dest_addr, nb); } } } goto DISCARD; default: goto DISCARD; } } else { DISCARD: fnet_netbuf_free_chain(ip6_nb); fnet_netbuf_free_chain(nb); } }
return (FNET_ERR); } #if (FNET_CFG_CPU_ETH0 ||FNET_CFG_CPU_ETH1) /* Number of initialised ethernet devices.*/ static fnet_index_t fnet_eth_number = 0U; /************************************************************************ * List of Network Layer Protocols used by Ethernet Interface. *************************************************************************/ static const fnet_eth_prot_if_t fnet_eth_prot_if_list[] = { #if FNET_CFG_IP4 { /* ARP */ FNET_HTONS(FNET_ETH_TYPE_ARP), /* Protocol number */ fnet_arp_input /* Protocol input function.*/ }, { /* IPv4 */ FNET_HTONS(FNET_ETH_TYPE_IP4), /* Protocol number */ fnet_ip_input /* Protocol input function.*/ } #endif /* FNET_CFG_IP4 */ #if FNET_CFG_IP6 #if FNET_CFG_IP4 , #endif /* FNET_CFG_IP4 */ { /* IPv4 */ FNET_HTONS(FNET_ETH_TYPE_IP6), /* Protocol number */ fnet_ip6_input /* Protocol input function.*/ }
/************************************************************************ * NAME: fnet_arp_input * * DESCRIPTION: ARP input function. *************************************************************************/ void fnet_arp_input( fnet_netif_t *netif, fnet_netbuf_t *nb ) { fnet_arp_if_t *arpif = &(((fnet_eth_if_t *)(netif->if_ptr))->arp_if); fnet_arp_header_t *arp_hdr = nb->data_ptr; fnet_mac_addr_t local_addr; fnet_arp_entry_t *entry; if(!((nb == 0) /* The packet is wrong. */ || (nb->total_length < sizeof(fnet_arp_header_t)) || (arp_hdr->hard_type != FNET_HTONS(FNET_ARP_HARD_TYPE)) || (arp_hdr->hard_size != FNET_ARP_HARD_SIZE) || (arp_hdr->prot_type != FNET_HTONS(FNET_ETH_TYPE_IP4)) || (arp_hdr->prot_size != FNET_ARP_PROT_SIZE))) { if(nb->total_length > sizeof(fnet_arp_header_t)) { /* Logical size and the physical size of the packet should be the same.*/ fnet_netbuf_trim(&nb, (int)(sizeof(fnet_arp_header_t) - nb->total_length)); } fnet_arp_trace("RX", arp_hdr); /* Print ARP header. */ fnet_netif_get_hw_addr(netif, local_addr, sizeof(fnet_mac_addr_t)); if(!(!fnet_memcmp(arp_hdr->sender_hard_addr, local_addr, sizeof(fnet_mac_addr_t)) /* It's from me => ignore it.*/ || !fnet_memcmp(arp_hdr->sender_hard_addr, fnet_eth_broadcast, sizeof(fnet_mac_addr_t))) /* It's broadcast=> error. */ ) { fnet_ip4_addr_t sender_prot_addr = arp_hdr->sender_prot_addr; fnet_ip4_addr_t targer_prot_addr = arp_hdr->targer_prot_addr; if(sender_prot_addr != netif->ip4_addr.address) /* Check Duplicate IP address.*/ { if(targer_prot_addr == netif->ip4_addr.address) /* It's for me.*/ { entry = fnet_arp_add_entry(netif, sender_prot_addr, arp_hdr->sender_hard_addr); } else { entry = fnet_arp_update_entry(netif, sender_prot_addr, arp_hdr->sender_hard_addr); } if(entry && entry->hold) { /* Send waiting data.*/ ((fnet_eth_if_t *)(netif->if_ptr))->output(netif, FNET_ETH_TYPE_IP4, entry->hard_addr, entry->hold); entry->hold = 0; entry->hold_time = 0; } } else { /* IP is duplicated. */ fnet_event_raise(arpif->arp_event); } /* ARP request. If it asked for our address, we send out a reply.*/ if((arp_hdr->op == FNET_HTONS(FNET_ARP_OP_REQUEST)) && (targer_prot_addr == netif->ip4_addr.address)) { arp_hdr->op = FNET_HTONS(FNET_ARP_OP_REPLY); /* Opcode */ fnet_memcpy(arp_hdr->target_hard_addr, arp_hdr->sender_hard_addr, sizeof(fnet_mac_addr_t)); fnet_memcpy(arp_hdr->sender_hard_addr, local_addr, sizeof(fnet_mac_addr_t)); arp_hdr->targer_prot_addr = arp_hdr->sender_prot_addr; arp_hdr->sender_prot_addr = netif->ip4_addr.address; fnet_arp_trace("TX Reply", arp_hdr); /* Print ARP header. */ ((fnet_eth_if_t *)(netif->if_ptr))->output(netif, FNET_ETH_TYPE_ARP, fnet_eth_broadcast, nb); return; } } } fnet_netbuf_free_chain(nb); }
/************************************************************************ * NAME: fnet_dns_state_machine * * DESCRIPTION: DNS-client state machine. ************************************************************************/ static void fnet_dns_state_machine( void *fnet_dns_if_p ) { int sent_size; int received; unsigned int i; fnet_dns_header_t *header; fnet_dns_rr_header_t *rr_header; fnet_dns_if_t *dns_if = (fnet_dns_if_t *)fnet_dns_if_p; switch(dns_if->state) { /*---- TX --------------------------------------------*/ case FNET_DNS_STATE_TX: FNET_DEBUG_DNS("Sending query..."); sent_size = send(dns_if->socket_cln, dns_if->message, dns_if->message_size, 0U); if (sent_size != (int)dns_if->message_size) { dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */ } else { dns_if->last_time = fnet_timer_ticks(); dns_if->state = FNET_DNS_STATE_RX; } break; /*---- RX -----------------------------------------------*/ case FNET_DNS_STATE_RX: /* Receive data */ received = recv(dns_if->socket_cln, dns_if->message, sizeof(dns_if->message), 0U); if(received > 0 ) { header = (fnet_dns_header_t *)fnet_dns_if.message; if((header->id == dns_if->id) && /* Check the ID.*/ ((header->flags & FNET_DNS_HEADER_FLAGS_QR)==FNET_DNS_HEADER_FLAGS_QR)) /* Is response.*/ { for (i=(sizeof(fnet_dns_header_t)-1U); i < (unsigned int)received; i++) { /* [RFC1035 4.1.4.] In order to reduce the size of messages, the domain system utilizes a * compression scheme which eliminates the repetition of domain names in a * message. In this scheme, an entire domain name or a list of labels at * the end of a domain name is replaced with a pointer to a prior occurance * of the same name. * The pointer takes the form of a two octet sequence: * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | 1 1| OFFSET | * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ /* => Check for 0xC0. */ if ((unsigned char)dns_if->message[i] == FNET_DNS_NAME_COMPRESSED_MASK) /* look for the beginnig of the response (Question Name == 192 (label compression))*/ { rr_header = (fnet_dns_rr_header_t *)&dns_if->message[i]; /* Check Question Type, Class and Resource Data Length. */ if ( (rr_header->type == dns_if->dns_type) && (rr_header->rr_class == FNET_HTONS(FNET_DNS_HEADER_CLASS_IN))) { /* Resolved.*/ if(rr_header->type == FNET_HTONS(FNET_DNS_TYPE_A)) { dns_if->resolved_ip4_addr[dns_if->addr_number].ip4_addr = *((fnet_ip4_addr_t*)(&rr_header->rdata)); dns_if->resolved_ip4_addr[dns_if->addr_number].ttl = rr_header->ttl; } else /* AF_INET6 */ { FNET_IP6_ADDR_COPY( (fnet_ip6_addr_t*)(&rr_header->rdata), &dns_if->resolved_ip6_addr[dns_if->addr_number].ip6_addr ); dns_if->resolved_ip6_addr[dns_if->addr_number].ttl = rr_header->ttl; } dns_if->addr_number++; } i+=(unsigned int)(sizeof(fnet_dns_rr_header_t)+fnet_ntohs(rr_header->rdlength)-4U-1U); } } } /* else = wrong message.*/ dns_if->state = FNET_DNS_STATE_RELEASE; } else if(received == SOCKET_ERROR) /* Check error.*/ { dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */ } else /* No data. Check timeout */ if(fnet_timer_get_interval(dns_if->last_time, fnet_timer_ticks()) > ((FNET_CFG_DNS_RETRANSMISSION_TIMEOUT*1000U)/FNET_TIMER_PERIOD_MS)) { dns_if->iteration++; if(dns_if->iteration > FNET_CFG_DNS_RETRANSMISSION_MAX) { dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */ } else { dns_if->state = FNET_DNS_STATE_TX; } } else {} break; /*---- RELEASE -------------------------------------------------*/ case FNET_DNS_STATE_RELEASE: { struct fnet_dns_resolved_addr *addr_list = FNET_NULL; fnet_dns_release(); /* Fill fnet_dns_resolved_addr */ if(dns_if->addr_number > 0) { if(dns_if->addr_family == AF_INET) { for(i=0; i<dns_if->addr_number; i++) { fnet_memset_zero(&dns_if->resolved_ip4_addr_sock[i].resolved_addr, sizeof(dns_if->resolved_ip4_addr_sock[i].resolved_addr)); dns_if->resolved_ip4_addr_sock[i].resolved_addr.sa_family = AF_INET; ((struct sockaddr_in*)(&dns_if->resolved_ip4_addr_sock[i].resolved_addr))->sin_addr.s_addr = dns_if->resolved_ip4_addr[i].ip4_addr; dns_if->resolved_ip4_addr_sock[i].resolved_addr_ttl = dns_if->resolved_ip4_addr[i].ttl; } addr_list = dns_if->resolved_ip4_addr_sock; } else if(dns_if->addr_family == AF_INET6) { for(i=0; i<dns_if->addr_number; i++) { fnet_memset_zero(&dns_if->resolved_ip6_addr_sock[i].resolved_addr, sizeof(dns_if->resolved_ip4_addr_sock[i].resolved_addr)); dns_if->resolved_ip6_addr_sock[i].resolved_addr.sa_family = AF_INET6; FNET_IP6_ADDR_COPY(&dns_if->resolved_ip6_addr[i].ip6_addr, &((struct sockaddr_in6*)(&dns_if->resolved_ip6_addr_sock[i].resolved_addr))->sin6_addr.s6_addr); dns_if->resolved_ip6_addr_sock[i].resolved_addr_ttl = dns_if->resolved_ip6_addr[i].ttl; } addr_list = dns_if->resolved_ip6_addr_sock; } else {} } dns_if->handler(addr_list, dns_if->addr_number, dns_if->handler_cookie); /* User Callback.*/ } break; default: break; } }
/************************************************************************ * NAME: fnet_dns_init * * DESCRIPTION: Initializes DNS client service and starts the host * name resolving. ************************************************************************/ int fnet_dns_init( struct fnet_dns_params *params ) { const unsigned long bufsize_option = FNET_DNS_MESSAGE_SIZE; unsigned int total_length; unsigned long host_name_length; struct sockaddr remote_addr; fnet_dns_header_t *header; /* Check input parameters. */ if((params == 0) || (params->dns_server_addr.sa_family == AF_UNSPEC) || fnet_socket_addr_is_unspecified(¶ms->dns_server_addr) || (params->handler == 0) /* Check length of host_name.*/ || ((host_name_length = fnet_strlen(params->host_name)) == 0U) || (host_name_length >= FNET_DNS_MAME_SIZE)) { FNET_DEBUG_DNS(FNET_DNS_ERR_PARAMS); goto ERROR; } /* Check if DNS service is free.*/ if(fnet_dns_if.state != FNET_DNS_STATE_DISABLED) { FNET_DEBUG_DNS(FNET_DNS_ERR_IS_INITIALIZED); goto ERROR; } /* Save input parmeters.*/ fnet_dns_if.handler = params->handler; fnet_dns_if.handler_cookie = params->cookie; fnet_dns_if.addr_family = params->addr_family; fnet_dns_if.addr_number = 0; if(params->addr_family == AF_INET) { fnet_dns_if.dns_type = FNET_HTONS(FNET_DNS_TYPE_A); } else if(params->addr_family == AF_INET6) { fnet_dns_if.dns_type = FNET_HTONS(FNET_DNS_TYPE_AAAA); } else { FNET_DEBUG_DNS(FNET_DNS_ERR_PARAMS); goto ERROR; } fnet_dns_if.iteration = 0U; /* Reset iteration counter.*/ fnet_dns_if.id++; /* Change query ID.*/ /* Create socket */ if((fnet_dns_if.socket_cln = socket(params->dns_server_addr.sa_family, SOCK_DGRAM, 0)) == SOCKET_INVALID) { FNET_DEBUG_DNS(FNET_DNS_ERR_SOCKET_CREATION); goto ERROR; } /* Set socket options */ setsockopt(fnet_dns_if.socket_cln, SOL_SOCKET, SO_RCVBUF, (const char *)&bufsize_option, sizeof(bufsize_option)); setsockopt(fnet_dns_if.socket_cln, SOL_SOCKET, SO_SNDBUF, (const char *)&bufsize_option, sizeof(bufsize_option)); /* Bind/connect to the server.*/ FNET_DEBUG_DNS("Connecting to DNS Server."); fnet_memset_zero(&remote_addr, sizeof(remote_addr)); remote_addr = params->dns_server_addr; if(remote_addr.sa_port == 0U) { remote_addr.sa_port = FNET_CFG_DNS_PORT; } if(connect(fnet_dns_if.socket_cln, &remote_addr, sizeof(remote_addr))== FNET_ERR) { FNET_DEBUG_DNS(FNET_DNS_ERR_SOCKET_CONNECT); goto ERROR_1; } /* ==== Build message. ==== */ fnet_memset_zero(fnet_dns_if.message, sizeof(fnet_dns_if.message)); /* Clear buffer.*/ /* Set header fields: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ID | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QDCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ANCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | NSCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ARCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ header = (fnet_dns_header_t *)fnet_dns_if.message; header->id = fnet_dns_if.id; /* Set ID. */ header->flags = FNET_HTONS(FNET_DNS_HEADER_FLAGS_RD); /* Recursion Desired.*/ header->qdcount = FNET_HTONS(1U); /* One Question. */ /* No Answer (ANCOUNT).*/ /* No Authority (NSCOUNT). */ /* No Additional (ARCOUNT). */ total_length = sizeof(fnet_dns_header_t); total_length += fnet_dns_add_question( &fnet_dns_if.message[total_length], fnet_dns_if.dns_type, params->host_name); fnet_dns_if.message_size = (unsigned long)(total_length); /* Register DNS service. */ fnet_dns_if.service_descriptor = fnet_poll_service_register(fnet_dns_state_machine, (void *) &fnet_dns_if); if(fnet_dns_if.service_descriptor == (fnet_poll_desc_t)FNET_ERR) { FNET_DEBUG_DNS(FNET_DNS_ERR_SERVICE); goto ERROR_1; } fnet_dns_if.state = FNET_DNS_STATE_TX; /* => Send request. */ return FNET_OK; ERROR_1: closesocket(fnet_dns_if.socket_cln); ERROR: return FNET_ERR; }
/************************************************************************ * NAME: fnet_icmp6_input * * DESCRIPTION: ICMPv6 input function. *************************************************************************/ static void fnet_icmp6_input(fnet_netif_t *netif, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t *nb, fnet_netbuf_t *ip6_nb) { fnet_icmp6_header_t *hdr; fnet_netbuf_t *tmp_nb; unsigned short sum; if((netif != 0) && (nb != 0)) { /* The header must reside in contiguous area of memory. */ if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp6_header_t))) == 0) { goto DISCARD; } nb = tmp_nb; hdr = nb->data_ptr; /* Drop Multicast loopback.*/ #if FNET_CFG_LOOPBACK if ((netif == FNET_LOOP_IF) && FNET_IP6_ADDR_IS_MULTICAST(dest_ip)) { goto DISCARD; } #endif /* FNET_CFG_LOOPBACK */ /* Verify the checksum. */ sum = fnet_checksum_pseudo_start( nb, FNET_HTONS((unsigned short)FNET_IP_PROTOCOL_ICMP6), (unsigned short)nb->total_length ); sum = fnet_checksum_pseudo_end( sum, (char *)src_ip, (char *)dest_ip, sizeof(fnet_ip6_addr_t) ); if(sum) goto DISCARD; /************************************************************ * Process incoming ICMPv6 packets. *************************************************************/ switch (hdr->type) { /************************** * Neighbor Solicitation. **************************/ case FNET_ICMP6_TYPE_NEIGHBOR_SOLICITATION: fnet_nd6_neighbor_solicitation_receive(netif, src_ip, dest_ip, nb, ip6_nb); break; /************************** * Neighbor Advertisemnt. **************************/ case FNET_ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT: fnet_nd6_neighbor_advertisement_receive(netif, src_ip, dest_ip, nb, ip6_nb); break; /************************** * Router Advertisemnt. **************************/ case FNET_ICMP6_TYPE_ROUTER_ADVERTISEMENT: fnet_nd6_router_advertisement_receive(netif, src_ip, dest_ip, nb, ip6_nb); break; /************************** * Router Advertisemnt. **************************/ case FNET_ICMP6_TYPE_REDIRECT: fnet_nd6_redirect_receive(netif, src_ip, dest_ip, nb, ip6_nb); break; #if FNET_CFG_MLD /************************** * Multicast Listener Query. **************************/ case FNET_ICMP6_TYPE_MULTICAST_LISTENER_QUERY: fnet_mld_query_receive(netif, src_ip, dest_ip, nb, ip6_nb); break; #endif /************************** * Echo Request. * RFC4443 4.1: Every node MUST implement an ICMPv6 Echo responder function that * receives Echo Requests and originates corresponding Echo Replies. **************************/ case FNET_ICMP6_TYPE_ECHO_REQ: hdr->type = FNET_ICMP6_TYPE_ECHO_REPLY; /* RFC4443: the source address of the reply MUST be a unicast * address belonging to the interface on which * the Echo Request message was received.*/ if(FNET_IP6_ADDR_IS_MULTICAST(dest_ip)) dest_ip = FNET_NULL; fnet_icmp6_output(netif, dest_ip/*ipsrc*/, src_ip/*ipdest*/, 0, nb); //MD fnet_netbuf_free_chain(ip6_nb); break; #if FNET_CFG_IP6_PMTU_DISCOVERY /************************** * Packet Too Big Message. **************************/ case FNET_ICMP6_TYPE_PACKET_TOOBIG: if(netif->pmtu) /* If PMTU is enabled for the interface.*/ { unsigned long pmtu; fnet_icmp6_err_header_t *icmp6_err = nb->data_ptr; /* The header must reside in contiguous area of memory. */ if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp6_err_header_t))) == 0) { goto DISCARD; } nb = tmp_nb; /* RFC 1981.Upon receipt of such a * message, the source node reduces its assumed PMTU for the path based * on the MTU of the constricting hop as reported in the Packet Too Big * message.*/ pmtu = fnet_ntohl(icmp6_err->data); /* A node MUST NOT increase its estimate of the Path MTU in response to * the contents of a Packet Too Big message. */ if(netif->pmtu > pmtu) { fnet_netif_set_pmtu(netif, pmtu); } } goto DISCARD; #endif default: goto DISCARD; } } else { DISCARD: fnet_netbuf_free_chain(ip6_nb); fnet_netbuf_free_chain(nb); } }
/************************************************************************ * NAME: fnet_mld_send * * DESCRIPTION: Sends MLD message defined by type: * FNET_ICMP6_TYPE_MULTICAST_LISTENER_REPORT or FNET_ICMP6_TYPE_MULTICAST_LISTENER_DONE *************************************************************************/ static void fnet_mld_send(fnet_netif_t *netif, fnet_ip6_addr_t *group_addr, fnet_uint8_t type) { fnet_netbuf_t *nb; fnet_netbuf_t *nb_option; fnet_mld_header_t *mld_header; fnet_mld_ra_option_header_t *ra_option_header; FNET_COMP_PACKED_VAR fnet_uint16_t *checksum_p; fnet_ip6_addr_t *ip_src; fnet_ip6_addr_t *ip_dst; /* [RFC2710] EXCLUDING the link-scope all-nodes address and any multicast * addresses of scope 0 (reserved) or 1(node-local).*/ if((FNET_IP6_ADDR_MULTICAST_SCOPE(group_addr) > FNET_IP6_ADDR_SCOPE_INTERFACELOCAL) && !FNET_IP6_ADDR_EQUAL(&fnet_ip6_addr_linklocal_allnodes, group_addr)) { /* Construct Router Alert option + MLD meassage */ if((nb = fnet_netbuf_new(sizeof(fnet_mld_header_t), FNET_FALSE)) != 0) { if((nb_option = fnet_netbuf_new(sizeof(fnet_mld_ra_option_header_t), FNET_FALSE)) != 0) { /* Fill Hop-by_Hop Options header.*/ ra_option_header = (fnet_mld_ra_option_header_t *)(nb_option->data_ptr); fnet_memcpy ((void *)ra_option_header, (void *)(&mld_ra_option), sizeof(mld_ra_option)); /* Fill MLD message. */ mld_header = (fnet_mld_header_t *)(nb->data_ptr); fnet_memset_zero(mld_header, sizeof(fnet_mld_header_t)); mld_header->icmp6_header.type = type; FNET_IP6_ADDR_COPY(group_addr, &mld_header->multicast_addr); /* Checksum calculation.*/ mld_header->icmp6_header.checksum = 0; mld_header->icmp6_header.checksum = fnet_checksum_pseudo_start(nb, FNET_HTONS((fnet_uint16_t)FNET_IP_PROTOCOL_ICMP6), (fnet_uint16_t)nb->total_length); checksum_p = &mld_header->icmp6_header.checksum; /* Concatanate Hop-by_Hop Options with MLD header. */ nb = fnet_netbuf_concat(nb_option, nb); /* Source Address Selection for MLD, by RFC3590.*/ /* [RFC3590] MLD Report and Done messages are sent with a link-local address as * the IPv6 source address, if a valid address is available on the interface.*/ ip_src = fnet_netif_get_ip6_addr_valid_link_local(netif); /* [RFC3590] If a valid link-local address is not available (e.g., one has not been configured), * the message is sent with the unspecified address. */ if(ip_src == FNET_NULL) { ip_src = (fnet_ip6_addr_t *)&fnet_ip6_addr_any; netif->mld_invalid = FNET_TRUE; } else { netif->mld_invalid = FNET_FALSE; } /* When a node ceases to listen to a multicast address on an interface, * it SHOULD send a single Done message to the link-scope all-routers * multicast address (FF02::2)*/ if(type == FNET_ICMP6_TYPE_MULTICAST_LISTENER_DONE) { ip_dst =(fnet_ip6_addr_t *)&fnet_ip6_addr_linklocal_allrouters; } else { ip_dst = group_addr; } /* Send via IPv6*/ fnet_ip6_output(netif, ip_src, ip_dst, FNET_IP6_TYPE_HOP_BY_HOP_OPTIONS, FNET_MLD_HOP_LIMIT, nb, checksum_p); } else { fnet_netbuf_free_chain(nb); } } } }
/************************************************************************ * NAME: fnet_ping_state_machine * * DESCRIPTION: PING service state machine. ************************************************************************/ static void fnet_ping_state_machine(void *fnet_ping_if_p) { fnet_int32_t received; fnet_icmp_echo_header_t *hdr; fnet_ping_if_t *ping_if = (fnet_ping_if_t *)fnet_ping_if_p; struct sockaddr addr; fnet_size_t addr_len = sizeof(addr); switch(ping_if->state) { /*===================================*/ case FNET_PING_STATE_SENDING_REQUEST: /* Build message.*/ hdr = (fnet_icmp_echo_header_t *)&fnet_ping_if.buffer[0]; /* Fill ICMP Echo request header.*/ fnet_memset_zero(hdr, sizeof(*hdr)); hdr->header.type = (fnet_uint8_t)((fnet_ping_if.family == AF_INET) ? FNET_ICMP_ECHO: FNET_ICMP6_TYPE_ECHO_REQ); hdr->identifier = FNET_CFG_PING_IDENTIFIER; fnet_ping_if.sequence_number++; hdr->sequence_number = fnet_htons(fnet_ping_if.sequence_number); /* Fill payload data by pattern.*/ fnet_memset(&fnet_ping_if.buffer[sizeof(*hdr)], ping_if->pattern, ping_if->packet_size); /* Checksum.*/ #if FNET_CFG_IP4 if(ping_if->family == AF_INET) { hdr->header.checksum = fnet_checksum_buf(&fnet_ping_if.buffer[0], (sizeof(*hdr) + ping_if->packet_size)); } else #endif #if FNET_CFG_IP6 if(ping_if->family == AF_INET6) { const fnet_ip6_addr_t *src_ip = fnet_ip6_select_src_addr(FNET_NULL, (fnet_ip6_addr_t *)ping_if->target_addr.sa_data); /*TBD Check result.*/ hdr->header.checksum = fnet_checksum_pseudo_buf(&fnet_ping_if.buffer[0], (fnet_uint16_t)(sizeof(*hdr) + ping_if->packet_size), FNET_HTONS((fnet_uint16_t)IPPROTO_ICMPV6), (const fnet_uint8_t *)src_ip, ping_if->target_addr.sa_data, sizeof(fnet_ip6_addr_t)); } else #endif {} /* Send request.*/ fnet_socket_sendto(fnet_ping_if.socket_foreign, (fnet_uint8_t*)(&fnet_ping_if.buffer[0]), (sizeof(*hdr) + ping_if->packet_size), 0u, &ping_if->target_addr, sizeof(ping_if->target_addr)); ping_if->packet_count--; fnet_ping_if.send_time = fnet_timer_ticks(); ping_if->state = FNET_PING_STATE_WAITING_REPLY; break; /*===================================*/ case FNET_PING_STATE_WAITING_REPLY: /* Receive data */ received = fnet_socket_recvfrom(ping_if->socket_foreign, (fnet_uint8_t*)(&ping_if->buffer[0]), FNET_PING_BUFFER_SIZE, 0u, &addr, &addr_len ); if(received > 0 ) { fnet_uint16_t checksum = 0u; hdr = (fnet_icmp_echo_header_t *)(ping_if->buffer); /* Check checksum.*/ #if FNET_CFG_IP4 if(ping_if->family == AF_INET) { checksum = fnet_checksum_buf(&fnet_ping_if.buffer[0], (fnet_size_t)received); } else #endif #if 0 /* #if FNET_CFG_IP6 */ /* TBD case to receive from multicast address ff02::1*/ if(ping_if->family == AF_INET6) { checksum = fnet_checksum_pseudo_buf(&fnet_ping_if.buffer[0], (fnet_uint16_t)(received), IPPROTO_ICMPV6, ping_if->local_addr.sa_data, ping_if->target_addr.sa_data, sizeof(fnet_ip6_addr_t)); } else #endif {} /* Check header.*/ if( checksum ||(hdr->header.type != ((addr.sa_family == AF_INET) ? FNET_ICMP_ECHOREPLY: FNET_ICMP6_TYPE_ECHO_REPLY)) ||(hdr->identifier != FNET_CFG_PING_IDENTIFIER) ||(hdr->sequence_number != fnet_htons(ping_if->sequence_number)) ) { goto NO_DATA; } /* Call handler.*/ if(ping_if->handler) { ping_if->handler(FNET_ERR_OK, ping_if->packet_count, &addr, ping_if->handler_cookie); } if(ping_if->packet_count) { ping_if->state = FNET_PING_STATE_WAITING_TIMEOUT; } else { fnet_ping_release(); } } else if(received == FNET_ERR) { /* Call handler.*/ if(ping_if->handler) { fnet_error_t sock_err ; fnet_size_t option_len; /* Get socket error.*/ option_len = sizeof(sock_err); fnet_socket_getopt(ping_if->socket_foreign, SOL_SOCKET, SO_ERROR, (fnet_uint8_t*)&sock_err, &option_len); ping_if->handler(sock_err, ping_if->packet_count, FNET_NULL, ping_if->handler_cookie); } if(ping_if->packet_count) { ping_if->state = FNET_PING_STATE_WAITING_TIMEOUT; } else { fnet_ping_release(); } } else /* No data. Check timeout */ { NO_DATA: if(fnet_timer_get_interval(fnet_ping_if.send_time, fnet_timer_ticks()) > fnet_ping_if.timeout_clk) { /* Call handler.*/ if(ping_if->handler) { ping_if->handler(FNET_ERR_TIMEDOUT, ping_if->packet_count, FNET_NULL, ping_if->handler_cookie); } if(ping_if->packet_count) { ping_if->state = FNET_PING_STATE_SENDING_REQUEST; } else { fnet_ping_release(); } } } break; /*===================================*/ case FNET_PING_STATE_WAITING_TIMEOUT: if(fnet_timer_get_interval(fnet_ping_if.send_time, fnet_timer_ticks()) > fnet_ping_if.timeout_clk) { ping_if->state = FNET_PING_STATE_SENDING_REQUEST; } break; default: break; /* do nothing, avoid compiler warning "enumeration value not handled in switch" */ } }
/************************************************************************ * NAME: fnet_udp_input * * DESCRIPTION: UDP input function. *************************************************************************/ static void fnet_udp_input(fnet_netif_t *netif, struct sockaddr *foreign_addr, struct sockaddr *local_addr, fnet_netbuf_t *nb, fnet_netbuf_t *ip_nb) { fnet_udp_header_t *udp_header = (fnet_udp_header_t *)nb->data_ptr; fnet_socket_if_t *sock; fnet_socket_if_t *last; fnet_size_t udp_length; fnet_netbuf_t *nb_tmp; if((netif != 0) && (nb != 0)) { /* The header must reside in contiguous area of memory.*/ if(fnet_netbuf_pullup(&nb, sizeof(fnet_udp_header_t)) == FNET_ERR) { goto BAD; } udp_length = fnet_ntohs(udp_header->length); if(nb->total_length >= udp_length) /* Check the amount of data.*/ { if(nb->total_length > udp_length) { /* Logical size and the physical size of the packet should be the same.*/ fnet_netbuf_trim(&nb, (fnet_int32_t)(udp_length - nb->total_length)); } #if FNET_CFG_UDP_CHECKSUM if((udp_header->checksum != 0u) #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_uint16_t sum; sum = fnet_checksum_pseudo_start( nb, FNET_HTONS((fnet_uint16_t)FNET_IP_PROTOCOL_UDP), (fnet_uint16_t)udp_length ); sum = fnet_checksum_pseudo_end( sum, &foreign_addr->sa_data[0], &local_addr->sa_data[0], (fnet_size_t)((local_addr->sa_family == AF_INET) ? sizeof(fnet_ip4_addr_t) : sizeof(fnet_ip6_addr_t))); if(sum) { goto BAD; } } #endif fnet_udp_trace("RX", udp_header); /* Trace UDP header.*/ local_addr->sa_port = udp_header->destination_port; foreign_addr->sa_port = udp_header->source_port; fnet_netbuf_trim(&nb, (fnet_int32_t)sizeof(fnet_udp_header_t)); /* Demultiplex broadcast & multicast datagrams.*/ if((fnet_socket_addr_is_broadcast(local_addr, netif)) || (fnet_socket_addr_is_multicast(local_addr))) { last = 0; for (sock = fnet_udp_prot_if.head; sock != 0; sock = sock->next) { /* Compare local port number.*/ if(sock->local_addr.sa_port != local_addr->sa_port) { continue; /* => ignore.*/ } #if FNET_CFG_MULTICAST if(fnet_socket_addr_is_multicast(local_addr)) { fnet_index_t m; fnet_bool_t for_us = FNET_FALSE; #if FNET_CFG_IP4 if(local_addr->sa_family == AF_INET) { for(m = 0u; m < FNET_CFG_MULTICAST_SOCKET_MAX; m++) { if(sock->ip4_multicast_entry[m]) { if((sock->ip4_multicast_entry[m]->group_addr == ((struct sockaddr_in *)(local_addr))->sin_addr.s_addr) && (sock->ip4_multicast_entry[m]->netif == netif )) { for_us = FNET_TRUE; } } } } else #endif #if FNET_CFG_IP6 if(local_addr->sa_family == AF_INET6) { for(m=0u; m < FNET_CFG_MULTICAST_SOCKET_MAX; m++) { if(sock->ip6_multicast_entry[m]) { if(FNET_IP6_ADDR_EQUAL(&sock->ip6_multicast_entry[m]->group_addr, &((struct sockaddr_in6 *)(local_addr))->sin6_addr.s6_addr) && (sock->ip6_multicast_entry[m]->netif == netif)) { for_us = FNET_TRUE; } } } } else #endif {} if(for_us == FNET_FALSE) { continue; } } else #endif /* FNET_CFG_MULTICAST */ { /* Compare local address.*/ if(!fnet_socket_addr_is_unspecified(&sock->local_addr)) { if(!fnet_socket_addr_are_equal(&sock->local_addr, local_addr)) { continue; } } /* Compare foreign address and port number.*/ if(!fnet_socket_addr_is_unspecified(&sock->foreign_addr)) { if((!fnet_socket_addr_are_equal(&sock->foreign_addr, foreign_addr)) || (sock->foreign_addr.sa_port != foreign_addr->sa_port)) { continue; } } } if((last != 0) && (last->receive_buffer.is_shutdown == FNET_FALSE)) { if((nb_tmp = fnet_netbuf_copy(nb, 0u, FNET_NETBUF_COPYALL, FNET_FALSE)) != 0) { if(fnet_socket_buffer_append_address(&(last->receive_buffer), nb_tmp, foreign_addr) == FNET_ERR) { fnet_netbuf_free_chain(nb_tmp); } } } last = sock; } if(last == 0) { goto BAD; } if(last->receive_buffer.is_shutdown) /* Is shutdown.*/ { goto BAD; } if(fnet_socket_buffer_append_address(&(last->receive_buffer), nb, foreign_addr) == FNET_ERR) { goto BAD; } fnet_netbuf_free_chain(ip_nb); } else /* For unicast datagram.*/ { sock = fnet_socket_lookup(fnet_udp_prot_if.head, local_addr, foreign_addr, FNET_IP_PROTOCOL_UDP); if(sock) { if(sock->receive_buffer.is_shutdown) /* Is shutdown.*/ { goto BAD; } if(fnet_socket_buffer_append_address(&(sock->receive_buffer), nb, foreign_addr) == FNET_ERR) { goto BAD; } fnet_netbuf_free_chain(ip_nb); } else { fnet_netbuf_free_chain(nb); /* No match was found, send ICMP destination port unreachable.*/ #if FNET_CFG_IP4 if(local_addr->sa_family == AF_INET) { fnet_icmp_error(netif, FNET_ICMP_UNREACHABLE, FNET_ICMP_UNREACHABLE_PORT, ip_nb); }else #endif #if FNET_CFG_IP6 if(local_addr->sa_family == AF_INET6) { fnet_icmp6_error(netif, FNET_ICMP6_TYPE_DEST_UNREACH, FNET_ICMP6_CODE_DU_PORT_UNREACH, 0u, ip_nb ); }else #endif {} } } } else { goto BAD; } } else { BAD: fnet_netbuf_free_chain(ip_nb); fnet_netbuf_free_chain(nb); } }
/************************************************************************ * 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); }