static uint32_t RIP_send_pkt( IP_IF_PTR ipif, /* [IN] the outgoing interface */ _ip_address ipdst, /* [IN] the destination ip */ uint16_t portdst,/* [IN] the destination port */ unsigned char *data, /* [IN] the data to send */ uint32_t len /* [IN] the length of data to send */ ) { /* Body */ RTCSPCB_PTR pcb; RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP); RIP_HEADER_PTR hd = (RIP_HEADER_PTR)data; uint32_t err; _ip_address ipsrc = IP_get_ipif_addr(ipif); if (ipsrc == INADDR_ANY) { _mem_free(data); return RTCS_OK; } /* Endif */ /* Allocate a PCB */ pcb = RTCSPCB_alloc_send(); if (pcb == NULL) { _mem_free(data); return RTCSERR_PCB_ALLOC; } /* Endif */ //RTCSLOG_PCB_ALLOC(pcb); /* add my data in the pcb */ err = RTCSPCB_append_fragment_autofree(pcb, len, data); if (err) { _mem_free(data); RTCSLOG_PCB_FREE(pcb, err); RTCSPCB_free(pcb); return err; } /* Endif */ RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PORT(IPPORT_RIP), mqx_ntohc(hd->VERSION)); /* dont advertize in limited broadcast but in ip broadcast */ if (ipdst == INADDR_BROADCAST){ _ip_address netmask; ipdst = IP_get_ipif_addr(ipif); /* Get IP address of interface */ IP_get_netmask(ipif, ipdst, &netmask); /* Get netmask */ ipdst = ipdst | ~netmask; } /* Endif */ /* send it */ /* use a flag to prevent the broadcast/multicast packet from ** looping back to us. */ return UDP_send_internal(ripcfg->UCB, ipsrc, ipdst, portdst, pcb, RTCS_MSG_NOLOOP); } /* Endbody */
boolean BOOTP_send ( TCPIP_EVENT_PTR event /* [IN/OUT] the resend event */ ) { /* Body */ IP_IF_PTR if_ptr = (IP_IF_PTR)event->PRIVATE; TCPIP_PARM_BOOTP _PTR_ parms = (TCPIP_PARM_BOOTP _PTR_)if_ptr->BOOT; BOOTP_CFG_PTR bootp = (BOOTP_CFG_PTR) &parms->config; RTCSPCB_PTR pcb_ptr; /* Set the event to trigger for the next retransmission (+/- 1 sec) */ bootp->RESEND.TIME = bootp->TIMEOUT + (RTCS_rand() & 0x7FF) - 0x400; /* Allocate a PCB */ pcb_ptr = RTCSPCB_alloc_send(); if (pcb_ptr == NULL) { return TRUE; } /* Endif */ //RTCSLOG_PCB_ALLOC(pcb_ptr); /* The only field that changes in BOOTREQUEST packets is 'secs' */ htons(bootp->PACKET.SECS, bootp->SECS); bootp->SECS += bootp->RESEND.TIME >> 10; /* approx. divide by 1000 */ /* Double the timeout */ bootp->TIMEOUT <<= 1; if (bootp->TIMEOUT > BOOTP_TIMEOUT_MAX) { bootp->TIMEOUT = BOOTP_TIMEOUT_MAX; } /* Endif */ /* Put the BOOTREQUEST in the PCB */ RTCSPCB_append_fragment(pcb_ptr, sizeof(BOOTP_HEADER), (uchar_ptr)&bootp->PACKET); RTCSPCB_append_fragment(pcb_ptr, sizeof(BOOTP_DATA), parms->data->SNAME); RTCSLOG_PCB_WRITE(pcb_ptr, RTCS_LOGCTRL_PORT(IPPORT_BOOTPC), 0); /* Send the datagram */ BOOT_send(pcb_ptr, if_ptr); /* Always retransmit */ return TRUE; } /* Endbody */
bool IGMP_send_report ( ip_mreq *igrp, uint16_t type ) { /* Body */ IGMP_CFG_STRUCT_PTR IGMP_cfg_ptr = RTCS_getcfg(IGMP); uint32_t error; uint16_t checksum; RTCSPCB_PTR pcb; IGMP_HEADER_PTR header; IP_IF_PTR ipif; _ip_address ipdst; IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++); /* never send a report for the local groups */ if (IN_LOCAL_MULTICAST(igrp->imr_multiaddr.s_addr)) { return TRUE; } /* Endif */ /* get the interface with its ip address */ ipif = IP_find_if(igrp->imr_interface.s_addr); if (ipif == NULL) { IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); return FALSE; } /* Endif */ pcb = RTCSPCB_alloc_send(); if (pcb == NULL) { IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); return FALSE; } /* Endif */ //RTCSLOG_PCB_ALLOC(pcb); error = RTCSPCB_insert_header(pcb, sizeof(IGMP_HEADER)); if (error) { RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); return FALSE; } /* Endif */ RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_IGMP), 1); #ifdef IGMP_V2 /* check if routers igmpv1 are present or not */ if (type == IGMPTYPE_V2_REPORT && ipif->IGMP_V1_ROUTER_FLAG) { uint32_t curTime = RTCS_time_get(); /* WORK: handle the overflow (see tcp seq) */ if (curTime < ipif->IGMP_V1_ROUTER_TIMEOUT) { type = IGMPTYPE_V1_REPORT; } else { /* if the timeout expired, clear the flag */ ipif->IGMP_V1_ROUTER_FLAG = 0; } /* Endif */ } /* Endif */ #endif /* IGMP_V2 */ /* build the igmp packet */ header = (IGMP_HEADER_PTR)RTCSPCB_DATA(pcb); mqx_htonc(header->TYPE, type); mqx_htonc(header->MAX_RESP_TIME, 0); mqx_htons(header->CHECKSUM, 0); mqx_htonl(header->GROUP_ADDRESS, igrp->imr_multiaddr.s_addr); checksum = _mem_sum_ip(0, sizeof(IGMP_HEADER), header); checksum = IP_Sum_invert(checksum); mqx_htons(header->CHECKSUM, checksum); /* WORK: for IGMP_V2, add a router alert option but currently ip layer doesnt support ip options */ /* send the igmp packet */ ipdst = igrp->imr_multiaddr.s_addr; #ifdef IGMP_V2 if (type == IGMPTYPE_LEAVE) { ipdst = INADDR_ALLROUTERS_GROUP; } /* Endif */ #endif IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_TX_REPORT++); /* WORK: not always true for IGMP_V2 */ error = IP_send(pcb, IPPROTO_IGMP | IPTTL(1), igrp->imr_interface.s_addr, ipdst, RTCS_MSG_NOLOOP); return TRUE; } /* Endbody */
/*FUNCTION*------------------------------------------------------------- * * Function Name : ICMP6_send_echo * Parameters : * * _ip_address ipaddress [IN] destination IP address * uint_32 timeout [IN/OUT] timeout/rtt * uint_16 id [IN] identification for echo message. * uint_16 seq not used * * Comments : * Send an ICMP Echo Request packet. * *END*-----------------------------------------------------------------*/ void ICMP6_send_echo(ICMP_ECHO_PARAM_PTR parms) { #if RTCSCFG_ENABLE_IP6 ICMP6_CFG_STRUCT_PTR ICMP6_cfg_ptr = RTCS_getcfg(ICMP6); RTCSPCB_PTR pcb; ICMP6_ECHO_HEADER_PTR packet; _rtcs_if_handle ihandle_dest = NULL; uint_32 error; IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++); parms->seq = ICMP6_cfg_ptr->ECHO_SEQ++; pcb = RTCSPCB_alloc_send(); if (pcb == NULL) { IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); RTCSCMD_complete(parms, RTCSERR_PCB_ALLOC); return; } if(parms->ping_param->data_buffer && parms->ping_param->data_buffer_size) { error = RTCSPCB_append_fragment(pcb, parms->ping_param->data_buffer_size, parms->ping_param->data_buffer); if (error) { IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.COMMON.ST_TX_ERRORS++); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); RTCSCMD_complete(parms, error); return; } } error = RTCSPCB_insert_header(pcb, sizeof(ICMP6_ECHO_HEADER)); if (error) { IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.COMMON.ST_TX_ERRORS++); IF_ICMP6_STATS_ENABLED(RTCS_seterror(&ICMP6_cfg_ptr->STATS.ERR_TX, error, (uint_32)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); RTCSCMD_complete(parms, error); return; } RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMPV6), 0); packet = (ICMP6_ECHO_HEADER_PTR)RTCSPCB_DATA(pcb); pcb->TRANSPORT_LAYER = (uchar_ptr)packet; htonc(packet->HEAD.TYPE, ICMP6_TYPE_ECHO_REQ); htonc(packet->HEAD.CODE, 0); htons(packet->HEAD.CHECKSUM, 0); htons(packet->ID, parms->ping_param->id); htons(packet->SEQ, parms->seq); pcb->IP_SUM = IP_Sum_PCB(RTCSPCB_SIZE(pcb), pcb); pcb->IP_SUM_PTR = packet->HEAD.CHECKSUM; if(((sockaddr_in6 *)(&parms->ping_param->addr))->sin6_scope_id) { ihandle_dest = ip6_if_get_by_scope_id(((sockaddr_in6 *)(&parms->ping_param->addr))->sin6_scope_id); } parms->EXPIRE.TIME = parms->ping_param->timeout; parms->EXPIRE.EVENT = ICMP6_expire_echo; parms->EXPIRE.PRIVATE = parms; parms->start_time = RTCS_time_get(); /* get timestamp */ error = IP6_send(pcb, IPPROTO_ICMPV6|IPTTL(parms->ping_param->hop_limit), NULL/*ipsrc*/, &((sockaddr_in6 *)(&parms->ping_param->addr))->sin6_addr/*ipdest*/, ihandle_dest, 0); if (error != RTCS_OK) { IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); RTCSCMD_complete(parms, error); return; } /* ** If there is no error add the parm struct to config struct ** and initiate the event timer */ IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.ST_TX_ECHO_REQ++); /* add the prameter structure to ICMP cfg */ parms->NEXT = ICMP6_cfg_ptr->ECHO_PARAM_HEAD; if (parms->NEXT) { parms->NEXT->PREV = &parms->NEXT; } /* Endif */ ICMP6_cfg_ptr->ECHO_PARAM_HEAD = parms; parms->PREV = &ICMP6_cfg_ptr->ECHO_PARAM_HEAD; TCPIP_Event_add(&parms->EXPIRE); #else RTCSCMD_complete(parms, RTCSERR_IP_IS_DISABLED); #endif /* RTCSCFG_ENABLE_IP6 */ }
void ICMP_send_error_internal ( uint8_t type, /* [IN] the type to send */ uint8_t code, /* [IN] the code to send */ uint32_t param, /* [IN] a parameter */ IP_HEADER_PTR iph, /* [IN] the IP header */ RTCSPCB_PTR origpcb, /* [IN] pcb with bad packet */ uint32_t maxlen /* [IN] the max data len to send, 0 = default */ ) { /* Body */ ICMP_CFG_STRUCT_PTR ICMP_cfg_ptr = RTCS_getcfg(ICMP); RTCSPCB_PTR pcb; ICMP_ERR_HEADER_PTR icmph; _ip_address ipsrc = mqx_ntohl(iph->SOURCE); _ip_address ipdst = mqx_ntohl(iph->DEST); uint16_t iphdrlen = (mqx_ntohc(iph->VERSLEN) & 0x0F) << 2; uint16_t ippktlen = mqx_ntohs(iph->LENGTH) - iphdrlen; uint16_t checksum; _ip_address icmpsrc = IP_is_local(NULL,ipdst) ? ipdst : INADDR_ANY; uint32_t error; unsigned char *buffer; uint32_t temp; #if RTCSCFG_ENABLE_NAT TCP_HEADER_PTR tcp_hdr; UDP_HEADER_PTR udp_hdr; IP_HEADER_PTR ip_hdr; uint32_t protocol; uint16_t src_port, dest_port; uint32_t (_CODE_PTR_ *nat_exec)(RTCSPCB_PTR *); #endif #if BSPCFG_ENET_HW_TX_PROTOCOL_CHECKSUM _ip_address if_addr; IP_IF_PTR if_ptr; #endif /* ** Only include up to a maximum of maxlen bytes of data from the ** original IP datagram */ if (!maxlen) { maxlen = IP_DEFAULT_MTU - sizeof(IP_HEADER) - sizeof(ICMP_HEADER) - 4; } /* Endif */ if (origpcb) { temp = RTCSPCB_DATA(origpcb) - RTCSPCB_DATA_NETWORK(origpcb); if (maxlen > origpcb->HEADER_FRAG_USED + temp) { maxlen = origpcb->HEADER_FRAG_USED + temp; } /* Endif */ } /* Endif */ if (ippktlen + iphdrlen > maxlen) { ippktlen = maxlen - iphdrlen; } /* Endif */ /* Don't send an error in response to an ICMP error */ if (mqx_ntohc(iph->PROTOCOL) == IPPROTO_ICMP) { /* Make sure the packet has at least a 'TYPE' field */ if (ippktlen == 0) { return; } /* Endif */ icmph = (ICMP_ERR_HEADER_PTR)((unsigned char *)iph + iphdrlen); if (!ICMPTYPE_ISQUERY(mqx_ntohc(icmph->HEAD.TYPE))) { return; } /* Endif */ } /* Endif */ IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++); /* Allocate a PCB */ pcb = RTCSPCB_alloc_send(); if (pcb == NULL) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); return; } /* Endif */ //RTCSLOG_PCB_ALLOC(pcb); if (origpcb) { /* Add a dependency and a pointer to the ICMP data */ RTCSPCB_depend(pcb, origpcb); error = RTCSPCB_append_fragment(pcb, iphdrlen + ippktlen, (unsigned char *)iph); } else { /* Reserve space for the ICMP data */ buffer = RTCS_mem_alloc_system(iphdrlen + ippktlen); if (!buffer) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_TX, RTCSERR_OUT_OF_MEMORY, (uint32_t)pcb)); RTCSLOG_PCB_FREE(pcb, RTCSERR_OUT_OF_MEMORY); RTCSPCB_free(pcb); return; } /* Endif */ _mem_set_type(buffer, MEM_TYPE_ICMP_DATA); _mem_copy(iph, buffer, iphdrlen + ippktlen); error = RTCSPCB_append_fragment_autofree(pcb, iphdrlen + ippktlen, buffer); if (error) { _mem_free(buffer); } /* Endif */ } /* Endif */ if (!error) { error = RTCSPCB_insert_header(pcb, sizeof(ICMP_HEADER) + 4); } /* Endif */ if (error) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_TX, error, (uint32_t)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); return; } /* Endif */ RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0); /* Build the header */ icmph = (ICMP_ERR_HEADER_PTR)RTCSPCB_DATA(pcb); mqx_htonc(icmph->HEAD.TYPE, type); mqx_htonc(icmph->HEAD.CODE, code); mqx_htons(icmph->HEAD.CHECKSUM, 0); mqx_htonl(icmph->DATA, param); #if BSPCFG_ENET_HW_TX_PROTOCOL_CHECKSUM /* HW-offload.*/ if_addr = IP_route_find(ipsrc /* Destination*/, 1); if_ptr = IP_find_if(if_addr); if( (if_ptr && (if_ptr->FEATURES & IP_IF_FEATURE_HW_TX_PROTOCOL_CHECKSUM) && (IP_will_fragment(if_ptr, RTCSPCB_SIZE(pcb)) == FALSE)) #if RTCSCFG_LINKOPT_8023 && (pcb->LINK_OPTIONS.TX.OPT_8023 == 0) #endif ) { pcb->TYPE |= RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM; } else #endif { checksum = IP_Sum_PCB (0, pcb); checksum = IP_Sum_invert(checksum); mqx_htons(icmph->HEAD.CHECKSUM, checksum); pcb->TYPE &= ~RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM; } #if RTCSCFG_ENABLE_ICMP_STATS /* Update the statistics */ switch (type) { case ICMPTYPE_DESTUNREACH: ICMP_cfg_ptr->STATS.ST_TX_DESTUNREACH++; break; case ICMPTYPE_TIMEEXCEED: ICMP_cfg_ptr->STATS.ST_TX_TIMEEXCEED++; break; case ICMPTYPE_PARMPROB: ICMP_cfg_ptr->STATS.ST_TX_PARMPROB++; break; case ICMPTYPE_SRCQUENCH: ICMP_cfg_ptr->STATS.ST_TX_SRCQUENCH++; break; case ICMPTYPE_REDIRECT: ICMP_cfg_ptr->STATS.ST_TX_REDIRECT++; break; case ICMPTYPE_ECHO_REQ: ICMP_cfg_ptr->STATS.ST_TX_ECHO_REQ++; break; case ICMPTYPE_ECHO_REPLY: ICMP_cfg_ptr->STATS.ST_TX_ECHO_REPLY++; break; case ICMPTYPE_TIME_REQ: ICMP_cfg_ptr->STATS.ST_TX_TIME_REQ++; break; case ICMPTYPE_TIME_REPLY: ICMP_cfg_ptr->STATS.ST_TX_TIME_REPLY++; break; case ICMPTYPE_INFO_REQ: ICMP_cfg_ptr->STATS.ST_TX_INFO_REQ++; break; case ICMPTYPE_INFO_REPLY: ICMP_cfg_ptr->STATS.ST_TX_INFO_REPLY++; break; default: ICMP_cfg_ptr->STATS.ST_TX_OTHER++; break; } /* Endswitch */ #endif #if RTCSCFG_ENABLE_NAT /* Reverse NAT (if it is installed) on the origpcb, otherwise the icmp error will not get sent to the original src */ nat_exec = RTCS_getcfg(NAT); if (origpcb && nat_exec && *nat_exec) { // swap src and dst IPs and ports so NAT_apply // will process the pcb ip_hdr = (IP_HEADER_PTR)RTCSPCB_DATA(origpcb); protocol = mqx_ntohc(ip_hdr->PROTOCOL); // Swap ports if it is udp or tcp if ((protocol == IPPROTO_TCP) || (protocol == IPPROTO_UDP)) { switch(protocol) { case IPPROTO_TCP: tcp_hdr = (TCP_HEADER_PTR)((unsigned char *)ip_hdr + IPH_LEN(ip_hdr)); dest_port = mqx_ntohs(tcp_hdr->dest_port); src_port = mqx_ntohs(tcp_hdr->source_port); mqx_htons(tcp_hdr->dest_port, src_port); mqx_htons(tcp_hdr->source_port, dest_port); break; case IPPROTO_UDP: udp_hdr = (UDP_HEADER_PTR)((unsigned char *)ip_hdr + IPH_LEN(ip_hdr)); dest_port = mqx_ntohs(udp_hdr->DEST_PORT); src_port = mqx_ntohs(udp_hdr->SRC_PORT); mqx_htons(udp_hdr->DEST_PORT, src_port); mqx_htons(udp_hdr->SRC_PORT, dest_port); break; default: // should not get here break; } } // swap IPs ipsrc = mqx_ntohl(ip_hdr->SOURCE); ipdst = mqx_ntohl(ip_hdr->DEST); mqx_htonl(ip_hdr->SOURCE, ipdst); mqx_htonl(ip_hdr->DEST,ipsrc); // call NAT error = (*nat_exec)(&origpcb); if (!error) { // swap IPs and ports back ip_hdr = (IP_HEADER_PTR)RTCSPCB_DATA(origpcb); protocol = mqx_ntohc(ip_hdr->PROTOCOL); // swap ports if it is udp or tcp if ((protocol == IPPROTO_TCP) || (protocol == IPPROTO_UDP)) { switch(protocol) { case IPPROTO_TCP: tcp_hdr = (TCP_HEADER_PTR)((unsigned char *)ip_hdr + IPH_LEN(ip_hdr)); dest_port = mqx_ntohs(tcp_hdr->dest_port); src_port = mqx_ntohs(tcp_hdr->source_port); mqx_htons(tcp_hdr->dest_port, src_port); mqx_htons(tcp_hdr->source_port, dest_port); break; case IPPROTO_UDP: udp_hdr = (UDP_HEADER_PTR)((unsigned char *)ip_hdr + IPH_LEN(ip_hdr)); dest_port = mqx_ntohs(udp_hdr->DEST_PORT); src_port = mqx_ntohs(udp_hdr->SRC_PORT); mqx_htons(udp_hdr->DEST_PORT, src_port); mqx_htons(udp_hdr->SRC_PORT, dest_port); break; default: // should not get here break; } } // swap IPs ipsrc = mqx_ntohl(ip_hdr->SOURCE); ipdst = mqx_ntohl(ip_hdr->DEST); mqx_htonl(ip_hdr->SOURCE, ipdst); mqx_htonl(ip_hdr->DEST,ipsrc); // Recalculate the cksum mqx_htons(icmph->HEAD.CHECKSUM, 0); checksum = IP_Sum_PCB (0, pcb); checksum = IP_Sum_invert(checksum); mqx_htons(icmph->HEAD.CHECKSUM, checksum); // recalculate icmpsrc, and use new ipsrc. ipdst = mqx_ntohl(ip_hdr->DEST); ipsrc = mqx_ntohl(ip_hdr->SOURCE); icmpsrc = IP_is_local(NULL,ipdst) ? ipdst : INADDR_ANY; } } #endif /* Send it */ IP_send(pcb, IPPROTO_ICMP, icmpsrc, ipsrc, 0); } /* Endbody */