/************************************************************************ * NAME: fnet_igmp_leave * * DESCRIPTION: Sends a Leave Group message. *************************************************************************/ void fnet_igmp_leave( fnet_netif_t *netif, fnet_ip4_addr_t group_addr ) { #if FNET_CFG_IGMP_VERSION == 2 fnet_netbuf_t *nb_header; fnet_igmp_header_t *igmp_header; fnet_ip4_addr_t dest_ip = FNET_IP4_ADDR_INIT(224, 0, 0, 2); /* All-routers multicast group.*/ /* Construct IGMP header*/ if((nb_header = fnet_netbuf_new(sizeof(fnet_igmp_header_t), FNET_FALSE)) != 0) { /* * When a host leaves a multicast group, if it was the last host to * reply to a Query with a Membership Report for that group, it SHOULD * send a Leave Group message to the all-routers multicast group (224.0.0.2). */ igmp_header = nb_header->data_ptr; igmp_header->type = IGMP_HEADER_TYPE_LEAVE_GROUP; /* Type.*/ igmp_header->max_resp_time = 0; /* Unused field, zeroed when sent, ignored when received.*/ igmp_header->group_addr = group_addr ; /* Group address field.*/ igmp_header->checksum = 0; igmp_header->checksum = fnet_checksum(nb_header, (int)nb_header->total_length); /* RFC 1112: A Report is sent with an IP destination address equal to the * host group address being reported, and with an IP time-to-live of 1. */ fnet_ip_output(netif, INADDR_ANY, dest_ip /*dest_addr*/, FNET_IP_PROTOCOL_IGMP, FNET_IGMP_TOS, FNET_IGMP_TTL, nb_header, 0, 0, 0); } #endif /* FNET_CFG_IGMP_VERSION */ }
/************************************************************************ * NAME: fnet_igmp_join * * DESCRIPTION: Sends Host Membership Reports. *************************************************************************/ void fnet_igmp_join( fnet_netif_t *netif, fnet_ip4_addr_t group_addr ) { fnet_netbuf_t *nb_header; fnet_igmp_header_t *igmp_header; /* Construct IGMP header*/ if((nb_header = fnet_netbuf_new(sizeof(fnet_igmp_header_t), FNET_FALSE)) != 0) { igmp_header = nb_header->data_ptr; /* Type.*/ #if FNET_CFG_IGMP_VERSION == 1 igmp_header->type = IGMP_HEADER_TYPE_REPORT_V1; #else /* FNET_CFG_IGMP_VERSION == 2 */ igmp_header->type = IGMP_HEADER_TYPE_REPORT_V2; #endif igmp_header->max_resp_time = 0; /* Unused field, zeroed when sent, ignored when received.*/ igmp_header->group_addr = group_addr ; /* Group address field.*/ igmp_header->checksum = 0; igmp_header->checksum = fnet_checksum(nb_header, (int)nb_header->total_length); /* RFC 1112: A Report is sent with an IP destination address equal to the * host group address being reported, and with an IP time-to-live of 1. */ fnet_ip_output(netif, INADDR_ANY, group_addr /*dest_addr*/, FNET_IP_PROTOCOL_IGMP, FNET_IGMP_TOS, FNET_IGMP_TTL, nb_header, 0, 0, 0); } }
/************************************************************************ * NAME: fnet_icmp_output * * DESCRIPTION: ICMP output function. *************************************************************************/ static void fnet_icmp_output( fnet_netif_t *netif, fnet_ip4_addr_t src_ip, fnet_ip4_addr_t dest_ip, fnet_netbuf_t *nb ) { fnet_icmp_header_t *hdr = (fnet_icmp_header_t *)nb->data_ptr; hdr->checksum = 0u; #if FNET_CFG_CPU_ETH_HW_TX_PROTOCOL_CHECKSUM if( netif && (netif->features & FNET_NETIF_FEATURE_HW_TX_PROTOCOL_CHECKSUM) && (fnet_ip_will_fragment(netif, nb->total_length) == FNET_FALSE) /* Fragmented packets are not inspected.*/ ) { nb->flags |= FNET_NETBUF_FLAG_HW_PROTOCOL_CHECKSUM; } else #endif hdr->checksum = fnet_checksum(nb, nb->total_length); fnet_ip_output(netif, src_ip, dest_ip, FNET_IP_PROTOCOL_ICMP, FNET_ICMP_TOS, FNET_ICMP_TTL, nb, FNET_FALSE, FNET_FALSE, 0); }
/************************************************************************ * 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); }
/************************************************************************ * 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_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); }