uint32_t RTCSPCB_insert_header ( RTCSPCB_PTR rtcs_pcb, /* [IN] packet to change */ uint32_t size /* [IN] size of new header */ ) { unsigned char *data_ptr; if (size > rtcs_pcb->HEADER_FRAG_FREE) { PCBLOG(("\nPCB: Insert: out of space in %p (%d/%d)", rtcs_pcb, size, rtcs_pcb->FRAGFREE)); return RTCSERR_PCB_BUFFER; } rtcs_pcb->HEADER_FRAG_FREE -= size; rtcs_pcb->HEADER_FRAG_USED += size; RTCSPCB_SIZE(rtcs_pcb) += size; data_ptr = RTCSPCB_DATA(rtcs_pcb); data_ptr -= size; RTCSPCB_DATA(rtcs_pcb) = data_ptr; PCBLOG(("\nPCB: Insert: inserted %d bytes in %p", size, rtcs_pcb)); return RTCS_OK; }
uint32_t RTCSPCB_append_fragment ( RTCSPCB_PTR rtcs_pcb, /* [IN] packet to change */ uint32_t size, /* [IN] size of new fragment */ unsigned char *frag /* [IN] pointer to new fragment */ ) { if (rtcs_pcb->NUM_FRAGS == 0) { PCBLOG(("\nPCB: Frag: must fork %p", rtcs_pcb)); return RTCSERR_PCB_NOFRAG; } if (rtcs_pcb->NUM_FRAGS >= RTCSPCB_FRAG_MAX) { PCBLOG(("\nPCB: Frag: out of fragments in %p", rtcs_pcb)); return RTCSERR_PCB_FRAG; } rtcs_pcb->PCBPTR->FRAG[rtcs_pcb->NUM_FRAGS].LENGTH = size; rtcs_pcb->PCBPTR->FRAG[rtcs_pcb->NUM_FRAGS].FRAGMENT = frag; RTCSPCB_SIZE(rtcs_pcb) += size; rtcs_pcb->NUM_FRAGS++; rtcs_pcb->PCBPTR->FRAG[rtcs_pcb->NUM_FRAGS].LENGTH = 0; rtcs_pcb->PCBPTR->FRAG[rtcs_pcb->NUM_FRAGS].FRAGMENT = NULL; PCBLOG(("\nPCB: Frag: added %d bytes to %p", size, rtcs_pcb)); return RTCS_OK; }
uint32_t RTCSPCB_next ( RTCSPCB_PTR rtcs_pcb, /* [IN] packet to change */ uint32_t size /* [IN] size of last header */ ) { unsigned char *data_ptr; if (size > rtcs_pcb->HEADER_FRAG_USED) { PCBLOG(("\nPCB: Next: out of space in %p (%d/%d)", rtcs_pcb, size, rtcs_pcb->FRAGUSED)); return RTCSERR_PCB_BUFFER; } rtcs_pcb->HEADER_FRAG_FREE += size; rtcs_pcb->HEADER_FRAG_USED -= size; RTCSPCB_SIZE(rtcs_pcb) -= size; data_ptr = RTCSPCB_DATA(rtcs_pcb); data_ptr += size; RTCSPCB_DATA(rtcs_pcb) = data_ptr; PCBLOG(("\nPCB: Next: skipped %d bytes in %p", size, rtcs_pcb)); return RTCS_OK; }
static void IGMP_service ( RTCSPCB_PTR pcb, /* [IN/OUT] incoming packet */ void *dummy /* [IN] not used */ ) { /* Body */ IGMP_HEADER_PTR header; IGMP_CFG_STRUCT_PTR IGMP_cfg_ptr; IGMP_cfg_ptr = RTCS_getcfg(IGMP); IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_RX_TOTAL++); header = (IGMP_HEADER_PTR)RTCSPCB_DATA(pcb); /* check if length >= sizeof(IGMP_HEADER) */ if (RTCSPCB_SIZE(pcb) < sizeof(IGMP_HEADER)) { IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_IGMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ /* Verify the checksum */ if (IP_Sum_PCB(0, pcb) != 0xFFFF) { IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_RX_BAD_CHECKSUM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_IGMP_BAD_CHECKSUM); RTCSPCB_free(pcb); return; } /* Endif */ if (mqx_ntohc(header->TYPE) == IGMPTYPE_V2_REPORT) { RTCSLOG_PCB_READ(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_IGMP), 2); } else { RTCSLOG_PCB_READ(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_IGMP), 1); } /* Endif */ switch (mqx_ntohc(header->TYPE)) { case IGMPTYPE_QUERY: IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_RX_QUERY++); IGMP_rcv_query(pcb->IFSRC, mqx_ntohl(header->GROUP_ADDRESS), mqx_ntohc(header->MAX_RESP_TIME)); break; case IGMPTYPE_V1_REPORT: case IGMPTYPE_V2_REPORT: IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_RX_REPORT++); IGMP_rcv_report(pcb->IFSRC, mqx_ntohl(header->GROUP_ADDRESS)); break; default: IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_RX_BAD_TYPE++); } /* Endswitch */ RTCSLOG_PCB_FREE(pcb, RTCS_OK); RTCSPCB_free(pcb); } /* Endbody */
RTCSPCB_PTR RTCSPCB_alloc_recv ( PCB_PTR inpcb /* [IN] received packet */ ) { RTCSPCB_PTR rtcs_pcb; PCB_FRAGMENT_PTR frag; rtcs_pcb = RTCSPCB_alloc(); if (rtcs_pcb != NULL) { rtcs_pcb->PCBPTR = inpcb; rtcs_pcb->HEADER_FRAG_USED = inpcb->FRAG[0].LENGTH; rtcs_pcb->HEADER_FRAG_FREE = 0; // We are not using the PCB contained in the RTCS_PCB, so // NUM_FRAGS is set to 0 to indicate this. rtcs_pcb->NUM_FRAGS = 0; RTCSPCB_SIZE(rtcs_pcb) = 0; RTCSPCB_DATA(rtcs_pcb) = inpcb->FRAG[0].FRAGMENT; for (frag = inpcb->FRAG; frag->LENGTH; frag++) { RTCSPCB_SIZE(rtcs_pcb) += frag->LENGTH; } rtcs_pcb->PCB_FREE = inpcb->FREE; rtcs_pcb->PCB_PRIVATE = inpcb->PRIVATE; rtcs_pcb->PCB_BUFFER = inpcb->FRAG[0]; inpcb->FREE = RTCSPCB_free_internal; inpcb->PRIVATE = rtcs_pcb; } return rtcs_pcb; }
uint_32 IPCP_send ( IP_IF_PTR if_ptr, /* [IN] the IP interface structure */ RTCSPCB_PTR pcb, /* [IN] the packet to send */ _ip_address src, /* [IN] the next-hop source address */ _ip_address dest, /* [IN] the next-hop destination address */ pointer data /* [IN] unused */ ) { /* Body */ IPCP_CFG_STRUCT_PTR ipcp_ptr = if_ptr->HANDLE; _ppp_handle handle = ipcp_ptr->HANDLE; uint_32 error; IF_IPIF_STATS_ENABLED(if_ptr->STATS.COMMON.ST_TX_TOTAL++); IF_IPIF_STATS_ENABLED(if_ptr->STATS.ST_TX_OCTETS += RTCSPCB_SIZE(pcb)); IF_IPIF_STATS_ENABLED(if_ptr->STATS.ST_TX_UNICAST++); RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_IFTYPE(IPIFTYPE_PPP), 0); error = RTCSPCB_insert_header(pcb, 2); if (error) { IF_IPIF_STATS_ENABLED(if_ptr->STATS.COMMON.ST_TX_ERRORS++); IF_IPIF_STATS_ENABLED(RTCS_seterror(&if_ptr->STATS.ERR_TX, error, (uint_32)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); return error; } /* Endif */ pcb->PCBPTR->FRAG[0].LENGTH = pcb->HEADER_FRAG_USED; pcb->PCBPTR->FRAG[0].FRAGMENT = RTCSPCB_DATA(pcb); error = PPP_send(handle, PPP_PROT_IP, pcb->PCBPTR); RTCSLOG_PCB_FREE(pcb, error); if (error) { IF_IPIF_STATS_ENABLED(if_ptr->STATS.COMMON.ST_TX_ERRORS++); IF_IPIF_STATS_ENABLED(RTCS_seterror(&if_ptr->STATS.ERR_TX, error, (uint_32)pcb)); } /* Endif */ return error; } /* Endbody */
RTCSPCB_PTR RTCSPCB_alloc_send ( void ) { RTCSPCB_PTR rtcs_pcb; PCB_FRAGMENT *pcb_frag_ptr; rtcs_pcb = RTCSPCB_alloc(); if (rtcs_pcb != NULL) { rtcs_pcb->PCBPTR = &rtcs_pcb->PCB; pcb_frag_ptr = rtcs_pcb->PCB.FRAG; pcb_frag_ptr->LENGTH = 0; // grows down from end of buffer pcb_frag_ptr->FRAGMENT = &rtcs_pcb->HEADER_FRAG_BUFFER[RTCSPCB_DATA_MAX]; // The following code assumed that PCB immediately followed BUFFER in RTCS_PCB data structure /* grows down into BUFFER */ // pcb_frag_ptr->FRAGMENT = (unsigned char *)&pcb->PCB; pcb_frag_ptr++; pcb_frag_ptr->LENGTH = 0; pcb_frag_ptr->FRAGMENT = NULL; rtcs_pcb->HEADER_FRAG_USED = 0; rtcs_pcb->HEADER_FRAG_FREE = RTCSPCB_DATA_MAX; rtcs_pcb->NUM_FRAGS = 1; RTCSPCB_SIZE(rtcs_pcb) = 0; RTCSPCB_DATA(rtcs_pcb) = rtcs_pcb->PCB.FRAG[0].FRAGMENT; rtcs_pcb->TYPE = RTCSPCB_TYPE_ONLYCAST; rtcs_pcb->PCB_FREE = NULL; } return rtcs_pcb; }
uint32_t RTCSPCB_shrink ( RTCSPCB_PTR rtcs_pcb, /* [IN] packet to change */ uint32_t size /* [IN] size to remove */ ) { if (size > rtcs_pcb->HEADER_FRAG_USED) { PCBLOG(("\nPCB: Shrink: out of space in %p (%d/%d)", rtcs_pcb, size, rtcs_pcb->HEADER_FRAG_USED)); return RTCSERR_PCB_BUFFER; } rtcs_pcb->HEADER_FRAG_USED -= size; RTCSPCB_SIZE(rtcs_pcb) -= size; PCBLOG(("\nPCB: Shrink: shrunk %d bytes in %p", size, rtcs_pcb)); return RTCS_OK; }
static void RIP_process_inresp( RTCSPCB_PTR pcb /* [IN/OUT] incoming packet */ ) { /* Body */ RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP); unsigned char *pkt = RTCSPCB_DATA(pcb); RIP_HEADER_PTR hd = (RIP_HEADER_PTR)RTCSPCB_DATA(pcb); RIP_ENTRY_PTR rte = (RIP_ENTRY_PTR)(pkt + sizeof(RIP_HEADER)); uint32_t pktlen = RTCSPCB_SIZE(pcb); uint16_t rip_vers = mqx_ntohc(hd->VERSION); IP_ROUTE_INDIRECT_PTR gate; _ip_address netaddr, netmask; if (pktlen < sizeof(RIP_HEADER)) { return; } /* Endif */ pktlen -= sizeof(RIP_HEADER); if (RIP_is_valid_resp(pcb) == FALSE){ return; } /* Endif */ for (; pktlen >= sizeof(RIP_ENTRY); pktlen -= sizeof(RIP_ENTRY), rte++){ if (!RIP_is_valid_rte(rte)) continue; netaddr = mqx_ntohl(rte->NETADDR); if (rip_vers == RIP_V2) netmask = mqx_ntohl(rte->NETMASK); else netmask = IN_DEFAULT_NET(netaddr); gate = ROUTE_get(netaddr, netmask); if (!gate) RIP_create_rt(pcb, rte, rip_vers); else RIP_update_rt(gate, pcb, rte); } /* if this incoming response has changed routes, do a triggered update*/ if (ripcfg->RT_CHANGED_F) RIP_trig_upd(); } /* Endbody */
static uint32_t RIP_process_inreq( RTCSPCB_PTR pcb /* [IN/OUT] incoming packet */ ) { /* Body */ RIP_HEADER_PTR hd = (RIP_HEADER_PTR)RTCSPCB_DATA(pcb); RIP_ENTRY_PTR rte = (RIP_ENTRY_PTR)((unsigned char *)hd + sizeof(RIP_HEADER)); uint32_t pktlen = RTCSPCB_SIZE(pcb); uint32_t err = RTCS_OK; /* handle the general query. rfc2453.3.9.1 */ if (pktlen == sizeof(RIP_ENTRY) + sizeof(RIP_HEADER) && mqx_ntohs(rte->FAMILY) == 0 && mqx_ntohl(rte->METRIC) == RIP_MAX_METRIC){ _ip_address ipsrc = IP_source(pcb); uint16_t srcport = UDP_source(pcb); uint8_t version = mqx_ntohc(hd->VERSION); return RIP_send_resp_ipif (pcb->IFSRC,ipsrc,srcport,version,0); } /* WORK: here handle particular routes request */ return err; } /* 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_service ( RTCSPCB_PTR pcb, /* [IN/OUT] incoming packet */ void *dummy /* [IN] not used */ ) { /* Body */ ICMP_CFG_STRUCT_PTR ICMP_cfg_ptr; ICMP_HEADER_PTR packet; _ip_address source, dest; uint32_t error; uint16_t chksum; unsigned char type; #if BSPCFG_ENET_HW_TX_PROTOCOL_CHECKSUM _ip_address if_addr; IP_IF_PTR if_ptr; #endif ICMP_cfg_ptr = RTCS_getcfg(ICMP); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_TOTAL++); packet = (ICMP_HEADER_PTR)RTCSPCB_DATA(pcb); source = IP_source(pcb); dest = IP_dest(pcb); type = mqx_ntohc(packet->TYPE); /* ** Make sure that ** sizeof(ICMP_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ #if BSPCFG_ENET_HW_RX_PROTOCOL_CHECKSUM /* HW-offload.*/ if( ((pcb->TYPE & RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM)==0) #if RTCSCFG_LINKOPT_8023 ||(pcb->LINK_OPTIONS.RX.OPT_8023 == 1) #endif ) #endif { /* Verify the checksum */ if (IP_Sum_PCB(0, pcb) != 0xFFFF) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_BAD_CHECKSUM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_CHECKSUM); RTCSPCB_free(pcb); return; } } RTCSLOG_PCB_READ(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0); switch (type) { case ICMPTYPE_REDIRECT: #if RTCSCFG_ENABLE_GATEWAYS { /* Scope */ _ip_address origdest, gateway; ICMP_ERR_HEADER_PTR rdpacket = (ICMP_ERR_HEADER_PTR)packet; IPIF_PARM parms; /* ** Make sure that ** sizeof(ICMP_ERR_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_ERR_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ gateway = mqx_ntohl(rdpacket->DATA); origdest = mqx_ntohl(rdpacket->IP.DEST); /* If we receive a redirect to ourselves, silently discard it.*/ /* Ignore unasigned address.*/ if( IP_is_local(NULL, gateway) || (gateway == INADDR_ANY)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); } else if(IP_is_gate(source, origdest)) { parms.address = gateway; parms.network = origdest; parms.netmask = 0xFFFFFFFFL; parms.locmask = 0; RTCSCMD_internal(parms, IPIF_gate_add_redirect); } else { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_RD_NOTGATE++); } /* Endif */ } /* Endscope */ #else IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); #endif break; case ICMPTYPE_ECHO_REQ: /* RFC1122: An ICMP Echo Request destined to an IP broadcast or IP * multicast address MAY be silently discarded.*/ if((dest == INADDR_BROADCAST) || (IN_MULTICAST(dest) && (ip_if_is_joined(pcb->IFSRC, dest) == false)) ) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); } else { error = RTCSPCB_next(pcb, sizeof(ICMP_HEADER)); if (error) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_ERRORS++); IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_RX, error, (uint32_t)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); return; } /* Endif */ /* ** RTCSPCB_fork() failing isn't a serious error, so we don't check ** the error code */ RTCSPCB_fork(pcb); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++); RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0); error = RTCSPCB_insert_header(pcb, sizeof(ICMP_HEADER)); if (error) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_ECHO_REQ++); 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; } /* Change type from Echo to Echo Reply and recalculate checksum */ packet = (ICMP_HEADER_PTR)RTCSPCB_DATA(pcb); mqx_htonc(packet->TYPE, ICMPTYPE_ECHO_REPLY); mqx_htonc(packet->CODE, 0); mqx_htons(packet->CHECKSUM, 0); pcb->IP_SUM_PTR = NULL; #if BSPCFG_ENET_HW_TX_PROTOCOL_CHECKSUM /* HW-offload.*/ if_addr = IP_route_find(source /* 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 { chksum = IP_Sum_PCB(0, pcb); chksum = IP_Sum_invert(chksum); mqx_htons(packet->CHECKSUM, chksum); pcb->TYPE &= ~RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM; } if(IN_MULTICAST(dest) || IP_addr_is_broadcast(pcb, dest) ) { dest = IP_get_ipif_addr(pcb->IFSRC); } /* Send the Echo Reply whence came the Echo */ IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_TX_ECHO_REPLY++); IP_send(pcb, IPPROTO_ICMP, dest /* Source*/, source /* Destination*/, 0); pcb = NULL; } break; case ICMPTYPE_ECHO_REPLY: { /* Scope */ ICMP_ECHO_HEADER_PTR echopacket = (ICMP_ECHO_HEADER_PTR)packet; ICMP_ECHO_PARAM_PTR parms; uint16_t id, seq; /* ** Make sure that ** sizeof(ICMP_ECHO_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_ECHO_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ /* ** get the ID and Sequence number from the packet */ id = mqx_ntohs(echopacket->ID); seq = mqx_ntohs(echopacket->SEQ); /* ** Find a match for the ID and sequence number */ for (parms=ICMP_cfg_ptr->ECHO_PARAM_HEAD; parms; parms=parms->NEXT) { if ((parms->ping_param->id == id) && (parms->seq == seq)) { /* received reply for the ping request */ if (parms->NEXT) { parms->NEXT->PREV = parms->PREV; } *parms->PREV = parms->NEXT; TCPIP_Event_cancel(&parms->EXPIRE); /* Calculate round trip time */ parms->ping_param->round_trip_time = RTCS_timer_get_interval(parms->start_time, RTCS_time_get()); /* IP address of echo-reply message.*/ { IP_HEADER_PTR iphead = (IP_HEADER_PTR)RTCSPCB_DATA_NETWORK(pcb); memset(&parms->ping_param->addr, 0, sizeof(parms->ping_param->addr)); parms->ping_param->addr.sa_family = AF_INET; ((sockaddr_in*)(&parms->ping_param->addr))->sin_addr.s_addr = mqx_ntohl(iphead->SOURCE); } RTCSCMD_complete(parms, RTCS_OK); break; } /* Endif */ } /* Endfor */ } /* Endscope */ break; case ICMPTYPE_DESTUNREACH: case ICMPTYPE_TIMEEXCEED: { /* Scope */ IP_HEADER_PTR ip; ICMP_ERR_HEADER_PTR icmp_err = (ICMP_ERR_HEADER_PTR)packet; uint32_t len, remain; bool discard = TRUE; unsigned char code; /* ** Check if the attached IP header is IP over IP, and if so, strip IP ** headers until we find one whose source address is not local. Then we ** forward the ICMP error to that IP address */ remain = RTCSPCB_SIZE(pcb); /* Make sure we have at least a full IP header */ if (remain >= sizeof(ICMP_HEADER) + 4 + sizeof(IP_HEADER)) { ip = (IP_HEADER_PTR)((unsigned char *)packet + sizeof(ICMP_HEADER) + 4); remain -= sizeof(ICMP_HEADER) + 4; do { /* Make sure the IP header is IP over IP */ if (mqx_ntohc(ip->PROTOCOL) != IPPROTO_IPIP) { break; } /* Endif */ /* Make sure we have a full IP header + 8 bytes */ len = (mqx_ntohc(ip->VERSLEN) & 0x0F) << 2; if (remain < len + sizeof(IP_HEADER)) { break; } /* Endif */ /* Get next header */ ip = (IP_HEADER_PTR)((unsigned char *)(ip) + len); remain -= len; source = mqx_ntohl(ip->SOURCE); discard = IP_is_local(NULL, source); } while(discard); len = (mqx_ntohc(ip->VERSLEN) & 0x0F) << 2; /* ** discard is true if we are the originator of the IP packet ** in error, or if there was not enough information to find the ** originator. We make sure discard is false, and there is at ** least a full IP header + 8 bytes of data left */ if (!discard && (len + 8 <= remain)) { if (type == ICMPTYPE_DESTUNREACH) { code = mqx_ntohc(packet->CODE); switch (code) { case ICMPCODE_DU_PROTO_UNREACH: /* ** If we are sending back to the originator, and the ** originator did not use IP over IP, the protocol ** unreachable error is useless. */ code = ICMPCODE_DU_NET_UNREACH; break; case ICMPCODE_DU_PORT_UNREACH: /* It doesn't make sense to receive this */ discard = TRUE; break; case ICMPCODE_DU_SRCROUTE: discard = TRUE; break; } /* Endswitch */ } else { /* ** Type is ICMPTYPE_TIMEEXCEED ** ** Problem with routing loops within tunnel. Originator ** does not need to know about tunnel. */ type = ICMPTYPE_DESTUNREACH; code = ICMPCODE_DU_HOST_UNREACH; } /* Endif */ if (!discard) { ICMP_send_error_internal(type, code, mqx_ntohl(icmp_err->DATA), ip, NULL, remain); } /* Endif */ } /* Endif */ } /* Endif */ } /* Endscope */ break; } /* End Switch */ #if RTCSCFG_ENABLE_ICMP_STATS /* Update the statistics */ switch (type) { case ICMPTYPE_DESTUNREACH: ICMP_cfg_ptr->STATS.ST_RX_DESTUNREACH++; break; case ICMPTYPE_TIMEEXCEED: ICMP_cfg_ptr->STATS.ST_RX_TIMEEXCEED++; break; case ICMPTYPE_PARMPROB: ICMP_cfg_ptr->STATS.ST_RX_PARMPROB++; break; case ICMPTYPE_SRCQUENCH: ICMP_cfg_ptr->STATS.ST_RX_SRCQUENCH++; break; case ICMPTYPE_REDIRECT: ICMP_cfg_ptr->STATS.ST_RX_REDIRECT++; break; case ICMPTYPE_ECHO_REQ: ICMP_cfg_ptr->STATS.ST_RX_ECHO_REQ++; break; case ICMPTYPE_ECHO_REPLY: ICMP_cfg_ptr->STATS.ST_RX_ECHO_REPLY++; break; case ICMPTYPE_TIME_REQ: ICMP_cfg_ptr->STATS.ST_RX_TIME_REQ++; break; case ICMPTYPE_TIME_REPLY: ICMP_cfg_ptr->STATS.ST_RX_TIME_REPLY++; break; case ICMPTYPE_INFO_REQ: ICMP_cfg_ptr->STATS.ST_RX_INFO_REQ++; break; case ICMPTYPE_INFO_REPLY: ICMP_cfg_ptr->STATS.ST_RX_INFO_REPLY++; break; default: ICMP_cfg_ptr->STATS.ST_RX_OTHER++; ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++; break; } /* Endswitch */ #endif if (pcb) { RTCSLOG_PCB_FREE(pcb, RTCS_OK); RTCSPCB_free(pcb); } /* Endif */ } /* Endbody */
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 */
void BOOTP_service ( RTCSPCB_PTR rtcs_pcb /* [IN] BOOTREPLY packet */ ) { /* Body */ IP_IF_PTR if_ptr = (IP_IF_PTR)rtcs_pcb->IFSRC; TCPIP_PARM_BOOTP _PTR_ parms = (TCPIP_PARM_BOOTP _PTR_)if_ptr->BOOT; BOOTP_CFG_PTR bootp = (BOOTP_CFG_PTR) &parms->config; BOOTP_PACKET_PTR bootreply; IPIF_PARM parms_bind; uint_32 error; uchar_ptr opt; uchar len, optval, optlen; /* Make sure the datagram is large enough */ bootreply = (BOOTP_PACKET_PTR)RTCSPCB_DATA(rtcs_pcb); if (RTCSPCB_SIZE(rtcs_pcb) < sizeof(BOOTP_PACKET)) { RTCSLOG_PCB_FREE(rtcs_pcb, RTCS_OK); RTCSPCB_free(rtcs_pcb); return; } /* Endif */ /* Make sure the XID matches */ if (ntohl(bootreply->HEAD.XID) != bootp->XID) { RTCSLOG_PCB_FREE(rtcs_pcb, RTCS_OK); RTCSPCB_free(rtcs_pcb); return; } /* Endif */ RTCSLOG_PCB_READ(rtcs_pcb, RTCS_LOGCTRL_PORT(IPPORT_BOOTPC), 0); /* OK, assume this reply is for us */ BOOTP_close(if_ptr); /* Get our IP address, and pick the default netmask */ parms_bind.ihandle = if_ptr; parms_bind.address = ntohl(bootreply->HEAD.YIADDR); parms_bind.locmask = 0xFFFFFFFFL; parms_bind.netmask = IN_DEFAULT_NET(parms_bind.address); parms_bind.probe = FALSE; parms->data->SADDR = ntohl(bootreply->HEAD.SIADDR); #if RTCSCFG_BOOTP_RETURN_YIADDR parms->data->CLIENTADDR = ntohl(bootreply->HEAD.YIADDR); #endif _mem_copy(bootreply->DATA.SNAME, parms->data->SNAME, sizeof(BOOTP_DATA)); RTCSLOG_PCB_FREE(rtcs_pcb, RTCS_OK); RTCSPCB_free(rtcs_pcb); /* Parse the vend field for recognized options */ opt = parms->data->OPTIONS; len = sizeof(parms->data->OPTIONS); if (ntohl(opt) == BOOTP_MAGIC) { opt += 4; len -= 4; #define BOOTP_NEXTOPT opt += optlen; \ break while (len) { /* Get the next option code */ optval = ntohc(opt); opt++; len--; /* Interpret the pad and end options */ if (optval == BOOTPOPT_END) break; if (optval == BOOTPOPT_PAD) continue; /* All other codes have a length byte */ if (len == 0) break; optlen = ntohc(opt); opt++; len--; if (len < optlen) break; len -= optlen; switch (optval) { case BOOTPOPT_MASK: if (optlen != 4) {BOOTP_NEXTOPT;} parms_bind.netmask = ntohl(opt); opt += 4; break; default: BOOTP_NEXTOPT; } /* Endswitch */ } /* Endwhile */ } /* Endif */ /* Bind the received IP address to this interface */ error = RTCSCMD_internal(parms_bind, IPIF_bind); /* Done -- unblock the application */ RTCSCMD_complete(parms, error); } /* Endbody */
void ICMP_service ( RTCSPCB_PTR pcb, /* [IN/OUT] incoming packet */ pointer dummy /* [IN] not used */ ) { /* Body */ ICMP_CFG_STRUCT_PTR ICMP_cfg_ptr; ICMP_HEADER_PTR packet; _ip_address source, dest; uint_32 error; uint_16 chksum; uchar type; ICMP_cfg_ptr = RTCS_getcfg(ICMP); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_TOTAL++); packet = (ICMP_HEADER_PTR)RTCSPCB_DATA(pcb); source = IP_source(pcb); dest = IP_dest(pcb); type = ntohc(packet->TYPE); /* ** Make sure that ** sizeof(ICMP_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ /* ** Verify the checksum */ if (IP_Sum_PCB(0, pcb) != 0xFFFF) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_BAD_CHECKSUM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_CHECKSUM); RTCSPCB_free(pcb); return; } /* Endif */ RTCSLOG_PCB_READ(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0); switch (type) { case ICMPTYPE_REDIRECT: #if RTCSCFG_ENABLE_GATEWAYS { /* Scope */ _ip_address origdest, gateway; ICMP_ERR_HEADER_PTR rdpacket = (ICMP_ERR_HEADER_PTR)packet; IPIF_PARM parms; /* ** Make sure that ** sizeof(ICMP_ERR_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_ERR_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ gateway = ntohl(rdpacket->DATA); origdest = ntohl(rdpacket->IP.DEST); // If we receive a redirect to ourselves, silently discard it if (IP_is_local(NULL, gateway)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); // Might want to add a counter here } else if (IP_is_gate(source, origdest)) { parms.address = gateway; parms.network = origdest; parms.netmask = 0xFFFFFFFFL; parms.locmask = 0; RTCSCMD_internal(parms, IPIF_gate_add_redirect); } else { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_RD_NOTGATE++); } /* Endif */ } /* Endscope */ #else IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); #endif break; case ICMPTYPE_ECHO_REQ: error = RTCSPCB_next(pcb, sizeof(ICMP_HEADER)); if (error) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_ERRORS++); IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_RX, error, (uint_32)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); return; } /* Endif */ /* ** RTCSPCB_fork() failing isn't a serious error, so we don't check ** the error code */ RTCSPCB_fork(pcb); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++); RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0); error = RTCSPCB_insert_header(pcb, sizeof(ICMP_HEADER)); if (error) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_ECHO_REQ++); 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, (uint_32)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); return; } /* Endif */ /* Change type from Echo to Echo Reply and recalculate checksum */ packet = (ICMP_HEADER_PTR)RTCSPCB_DATA(pcb); htonc(packet->TYPE, ICMPTYPE_ECHO_REPLY); htonc(packet->CODE, 0); htons(packet->CHECKSUM, 0); chksum = IP_Sum_PCB(0, pcb); chksum = IP_Sum_invert(chksum); htons(packet->CHECKSUM, chksum); pcb->IP_SUM_PTR = NULL; /* Send the Echo Reply whence came the Echo */ IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_TX_ECHO_REPLY++); IP_send(pcb, IPPROTO_ICMP, dest, source, 0); pcb = NULL; break; case ICMPTYPE_ECHO_REPLY: { /* Scope */ ICMP_ECHO_HEADER_PTR echopacket = (ICMP_ECHO_HEADER_PTR)packet; ICMP_PARM_PTR parms; uint_16 id, seq; /* ** Make sure that ** sizeof(ICMP_ECHO_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_ECHO_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ /* ** get the ID and Sequence number from the packet */ id = ntohs(echopacket->ID); seq = ntohs(echopacket->SEQ); /* ** Find a match for the ID and sequence number */ for (parms=ICMP_cfg_ptr->ECHO_PARM_HEAD; parms; parms=parms->NEXT) { if ((parms->id == id) && (parms->seq == seq)) { /* received reply for the ping request */ if (parms->NEXT) { parms->NEXT->PREV = parms->PREV; } /* Endif */ *parms->PREV = parms->NEXT; TCPIP_Event_cancel(&parms->EXPIRE); /* calculate round trip time */ parms->timeout = RTCS_timer_get_interval(parms->timeout, RTCS_time_get()); RTCSCMD_complete(parms, RTCS_OK); break; } /* Endif */ } /* Endfor */ } /* Endscope */ break; case ICMPTYPE_DESTUNREACH: case ICMPTYPE_TIMEEXCEED: { /* Scope */ IP_HEADER_PTR ip; ICMP_ERR_HEADER_PTR icmp_err = (ICMP_ERR_HEADER_PTR)packet; uint_32 len, remain; boolean discard = TRUE; uchar code; /* ** Check if the attached IP header is IP over IP, and if so, strip IP ** headers until we find one whose source address is not local. Then we ** forward the ICMP error to that IP address */ remain = RTCSPCB_SIZE(pcb); /* Make sure we have at least a full IP header */ if (remain >= sizeof(ICMP_HEADER) + 4 + sizeof(IP_HEADER)) { ip = (IP_HEADER_PTR)((uchar_ptr)packet + sizeof(ICMP_HEADER) + 4); remain -= sizeof(ICMP_HEADER) + 4; do { /* Make sure the IP header is IP over IP */ if (ntohc(ip->PROTOCOL) != IPPROTO_IPIP) { break; } /* Endif */ /* Make sure we have a full IP header + 8 bytes */ len = (ntohc(ip->VERSLEN) & 0x0F) << 2; if (remain < len + sizeof(IP_HEADER)) { break; } /* Endif */ /* Get next header */ ip = (IP_HEADER_PTR)((uchar_ptr)(ip) + len); remain -= len; source = ntohl(ip->SOURCE); discard = IP_is_local(NULL, source); } while(discard); len = (ntohc(ip->VERSLEN) & 0x0F) << 2; /* ** discard is true if we are the originator of the IP packet ** in error, or if there was not enough information to find the ** originator. We make sure discard is false, and there is at ** least a full IP header + 8 bytes of data left */ if (!discard && (len + 8 <= remain)) { if (type == ICMPTYPE_DESTUNREACH) { code = ntohc(packet->CODE); switch (code) { case ICMPCODE_DU_PROTO_UNREACH: /* ** If we are sending back to the originator, and the ** originator did not use IP over IP, the protocol ** unreachable error is useless. */ code = ICMPCODE_DU_NET_UNREACH; break; case ICMPCODE_DU_PORT_UNREACH: /* It doesn't make sense to receive this */ discard = TRUE; break; case ICMPCODE_DU_SRCROUTE: discard = TRUE; break; } /* Endswitch */ } else { /* ** Type is ICMPTYPE_TIMEEXCEED ** ** Problem with routing loops within tunnel. Originator ** does not need to know about tunnel. */ type = ICMPTYPE_DESTUNREACH; code = ICMPCODE_DU_HOST_UNREACH; } /* Endif */ if (!discard) { ICMP_send_error_internal(type, code, ntohl(icmp_err->DATA), ip, NULL, remain); } /* Endif */ } /* Endif */ } /* Endif */ } /* Endscope */ break; } /* End Switch */ #if RTCSCFG_ENABLE_ICMP_STATS /* Update the statistics */ switch (type) { case ICMPTYPE_DESTUNREACH: ICMP_cfg_ptr->STATS.ST_RX_DESTUNREACH++; break; case ICMPTYPE_TIMEEXCEED: ICMP_cfg_ptr->STATS.ST_RX_TIMEEXCEED++; break; case ICMPTYPE_PARMPROB: ICMP_cfg_ptr->STATS.ST_RX_PARMPROB++; break; case ICMPTYPE_SRCQUENCH: ICMP_cfg_ptr->STATS.ST_RX_SRCQUENCH++; break; case ICMPTYPE_REDIRECT: ICMP_cfg_ptr->STATS.ST_RX_REDIRECT++; break; case ICMPTYPE_ECHO_REQ: ICMP_cfg_ptr->STATS.ST_RX_ECHO_REQ++; break; case ICMPTYPE_ECHO_REPLY: ICMP_cfg_ptr->STATS.ST_RX_ECHO_REPLY++; break; case ICMPTYPE_TIME_REQ: ICMP_cfg_ptr->STATS.ST_RX_TIME_REQ++; break; case ICMPTYPE_TIME_REPLY: ICMP_cfg_ptr->STATS.ST_RX_TIME_REPLY++; break; case ICMPTYPE_INFO_REQ: ICMP_cfg_ptr->STATS.ST_RX_INFO_REQ++; break; case ICMPTYPE_INFO_REPLY: ICMP_cfg_ptr->STATS.ST_RX_INFO_REPLY++; break; default: ICMP_cfg_ptr->STATS.ST_RX_OTHER++; ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++; break; } /* Endswitch */ #endif if (pcb) { RTCSLOG_PCB_FREE(pcb, RTCS_OK); RTCSPCB_free(pcb); } /* Endif */ } /* Endbody */