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 */
static void RIP_create_rt( RTCSPCB_PTR pcb, /* [IN] incoming packet */ RIP_ENTRY_PTR rte, uint8_t rip_vers ) { /* Body */ uint32_t nmetric= RIP_cpu_metric(pcb,mqx_ntohl(rte->METRIC)); RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP); IP_CFG_STRUCT_PTR IP_cfg_ptr = RTCS_getcfg(IP); IP_ROUTE_INDIRECT_PTR gate; _ip_address network, netmask; gate = RTCS_part_alloc(IP_cfg_ptr->GATE_PARTID); if (!gate) return; _mem_zero(gate, sizeof(*gate)); /* init the route */ RIP_adopt_rt(pcb, gate, rte, nmetric, &network, &netmask); /* insert it in the table */ ROUTE_insert(gate, network, netmask); /* flag it as changed */ ripcfg->RT_CHANGED_F = TRUE; } /* Endbody */
uint32_t IP_reasm ( RTCSPCB_PTR pcb, /* [IN] the packet to deliver */ RTCSPCB_PTR *outpcb /* [OUT] the reassembled packet or NULL */ ) { /* Body */ IP_HEADER_PTR iph = (IP_HEADER_PTR)RTCSPCB_DATA(pcb); _ip_address ipsrc = mqx_ntohl(iph->SOURCE); _ip_address ipdst = mqx_ntohl(iph->DEST); uint8_t proto = mqx_ntohc(iph->PROTOCOL); uint16_t id = mqx_ntohs(iph->ID); IP_DGRAM_PTR dgram; *outpcb = NULL; dgram = IPREASM_get_dgram(ipsrc, ipdst, proto, id); if (!dgram) { RTCSLOG_PCB_FREE(pcb, RTCSERR_OUT_OF_MEMORY); RTCSPCB_free(pcb); return RTCSERR_OUT_OF_MEMORY; } /* Endif */ IPREASM_add_frag(dgram, pcb); /* ** We're done when: ** 0 < TOTLEN = MAXLEN <= CURLEN ** ** Note: we can get TOTLEN < CURLEN because CURLEN is ** always a multiple of eight, but TOTLEN may not be. */ if (dgram->TOTLEN > 0 && dgram->MAXLEN == dgram->TOTLEN && dgram->CURLEN >= dgram->MAXLEN) { *outpcb = IPREASM_reasm_dgram(dgram); } /* Endif */ /* Free the old pcb */ RTCSLOG_PCB_FREE(pcb, RTCS_OK); RTCSPCB_free(pcb); return RTCS_OK; } /* Endbody */
static void RIP_adopt_rt( RTCSPCB_PTR pcb, /* [IN] incoming packet */ IP_ROUTE_INDIRECT_PTR gate, RIP_ENTRY_PTR rte, uint32_t metric, _ip_address *network_ptr, _ip_address *netmask_ptr ) { /* Body */ RIP_HEADER_PTR hd = (RIP_HEADER_PTR)RTCSPCB_DATA(pcb); uint16_t rip_vers = mqx_ntohc(hd->VERSION); _ip_address ipsrc = IP_source(pcb); /* init the common part */ *network_ptr = mqx_ntohl(rte->NETADDR); gate->GATEWAY = ipsrc; if (rip_vers == RIP_V2){ _ip_address nexthop = mqx_ntohl(rte->NEXTHOP); *netmask_ptr = mqx_ntohl(rte->NETMASK); /* incoming nexthop. rfc2453.4.4 */ if (nexthop && IP_is_direct(pcb->IFSRC, nexthop)) gate->GATEWAY = nexthop; }else{ *netmask_ptr = IN_DEFAULT_NET(*network_ptr); } /* if the metric is >= than the RIP_MAX_METRIC, the ourte is down */ if (metric < RIP_MAX_METRIC) { gate->FLAGS |= RTF_UP; } else { gate->FLAGS &= ~RTF_UP; } /* Endif */ /* init the RIP part */ gate->RIP.METRIC = metric; gate->RIP.RT_TAG = mqx_ntohs(rte->RT_TAG); gate->RIP.CHANGED_F = TRUE; gate->RIP.IPIFSRC = pcb->IFSRC; RIP_init_timer(gate, gate->RIP.METRIC); } /* Endbody */
static void RIP_update_rt( IP_ROUTE_INDIRECT_PTR gate, RTCSPCB_PTR pcb, /* [IN] incoming packet */ RIP_ENTRY_PTR rte ) { /* Body */ RIP_CFG_STRUCT_PTR ripcfg = RTCS_getcfg(RIP); uint32_t nmetric= RIP_cpu_metric(pcb,mqx_ntohl(rte->METRIC)); _ip_address ipsrc = IP_source(pcb); /* dont modify a static route */ if (gate->FLAGS & RTF_STATIC) return; /* ** if the source isnt "authoritative" (i.e. not the current ** gateway) and have a bigger metric, ignore the route. */ if (ipsrc != gate->GATEWAY && nmetric > gate->RIP.METRIC) return; /* ** if the source isnt "authoritative" (i.e. not the current ** gateway) and have a equal metric and will "soon" timed out, ** update the route entry. */ if (ipsrc != gate->GATEWAY && nmetric == gate->RIP.METRIC){ uint32_t timeout = TCPIP_Event_expire(&gate->RIP.TIMEOUT); /* if the both metrics are infinite, dont update the route. */ if (nmetric >= RIP_MAX_METRIC) return; if (timeout > RIP_ALMOST_EXPIRED_TIME) return; } /* cancel the timeout/gc timer */ TCPIP_Event_cancel(&gate->RIP.TIMEOUT); /* If the sources and the metrics are equal, just reinit the timer. */ if (ipsrc == gate->GATEWAY && gate->RIP.METRIC == nmetric){ if (nmetric < RIP_MAX_METRIC){ RIP_init_timer(gate, gate->RIP.METRIC); } return; } /* ** Reinit the route and the timer. ipsrc no longer needed, just used ** to fill all of the function parameters */ RIP_adopt_rt(pcb, gate, rte, nmetric, &ipsrc, &ipsrc); /* flag it as changed */ ripcfg->RT_CHANGED_F = TRUE; } /* Endbody */
static bool SNTP_valid_header ( SNTP_HEADER_PTR header_ptr /*[IN] pointer to a SNTP header struct */ ) { uint32_t t2[2]; uint32_t t3[2]; bool result; t2[0] = mqx_ntohl(header_ptr->RECEIVE_TIMESTAMP1); t2[1] = mqx_ntohl(header_ptr->RECEIVE_TIMESTAMP2); t3[0] = mqx_ntohl(header_ptr->TRANSMIT_TIMESTAMP1); t3[1] = mqx_ntohl(header_ptr->TRANSMIT_TIMESTAMP2); /* Reply shoud be in server mode */ /* Version should be same as in original message */ /* LI field should be between 0 and 2 */ /* Stratum should be between 1 and 14 */ /* Originate timestamp must be non zero */ /* Receive timestamp must be non zero */ /* Transmit timestamp must be non-zero */ if( ((mqx_ntohc(header_ptr->LI_VN_MODE) & SNTP_MASK_MODE) == SNTP_MODE_SERVER) && ((mqx_ntohc(header_ptr->LI_VN_MODE) & SNTP_MASK_VN) >> 3 >= SNTP_VER_MIN) && ((mqx_ntohc(header_ptr->LI_VN_MODE) & SNTP_MASK_LI) >> 6 != SNTP_LI_ALARM) && ( mqx_ntohc(header_ptr->STRATUM) >= SNTP_STRATUM_MIN) && ( mqx_ntohc(header_ptr->STRATUM) <= SNTP_STRATUM_MAX) && ((t2[0] != 0) || (t2[1] != 0)) && ((t3[0] != 0) || (t3[1] != 0)) && /* Correct behaviour requires that Transmit timestamp (t3) must be later than Recceive timestamp (t2) * Take into account the overflow case for seconds.*/ /* Some SNTP Servers can generate wrong Seconds Fraction of timestamp.*/ ((t3[0] != /* > */ t2[0]) || ((t3[0] == t2[0]) && (t3[1] >= t2[1]))) ) { result = TRUE; } else {
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_is_valid_rte( RIP_ENTRY_PTR rte ) { /* Body */ uint32_t metric = mqx_ntohl(rte->METRIC); _ip_address netaddr = mqx_ntohl(rte->NETADDR); if (mqx_ntohs(rte->FAMILY) != RIP_AF_INET) return 0; if (metric > RIP_MAX_METRIC || metric < RIP_MIN_METRIC) return 0; if (IN_MULTICAST(netaddr) || IN_EXPERIMENTAL(netaddr)) return 0; if (IN_LOOPBACK(netaddr)) return 0; { _ip_address nexthop = mqx_ntohl(rte->NEXTHOP); if (nexthop!= 0) { if (IP_is_local(NULL, nexthop)) { return 0; } } } return 1; } /* 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 */
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 */
static bool LCP_recvconfack ( PPPFSM_CFG_PTR fsm /* [IN] - State Machine */ ) { /* Body */ LCP_CFG_PTR lcp_ptr = fsm->PRIVATE; unsigned char *inp = fsm->DATA; uint32_t sizeleft = fsm->LENGTH; uint32_t aplen; PPP_OPT ack_opt = lcp_ptr->RECV_OPT; #define LCP_RACK(ci,len) \ if (sizeleft < len) goto badack; \ if (*inp++ != LCP_CI_ ## ci) goto badack; \ if (*inp++ != len) goto badack; \ sizeleft -= len /* ** The ack must be identical to the last ConfReq we sent */ /* ** This situation can happend when size of data in our request packet is "0" ** So, size of received data in "ack" packet will be "0" too. ** As example: We send "REQ" packet with field PFC an ACFC "ON", modem send "NAK" ** for that field. We turn of that field, but we have not what negotiate else, ** so we send "REQ" packed,it looks like "7E FF 03 C0 21 01 6D 00 04 3F 15 7E" ** As you see size of data field is "0". But modem agree and send us "ACK" looks like ** "7E FF 03 C0 21 02 6D 00 04 F2 30 7E" and will be ready to start next stage of communication. ** In received packet from modem you can se size of data field is "0" too. */ if(sizeleft ==0) { return TRUE; } if (lcp_ptr->RECV_NEG.NEG_MRU) { LCP_RACK(MRU,4); ack_opt.MRU = mqx_ntohs(inp); inp += 2; if (ack_opt.MRU != lcp_ptr->RECV_NEG.MRU) goto badack; } /* Endif */ if (lcp_ptr->RECV_NEG.NEG_ACCM) { LCP_RACK(ACCM,6); ack_opt.ACCM = mqx_ntohl(inp); inp += 4; if (ack_opt.ACCM != lcp_ptr->RECV_NEG.ACCM) goto badack; } /* Endif */ if (lcp_ptr->RECV_NEG.NEG_AP) { switch (lcp_ptr->RECV_NEG.AP) { case PPP_PROT_CHAP: aplen = 5; break; default: aplen = 4; break; } /* Endswitch */ LCP_RACK(AP,aplen); ack_opt.AP = mqx_ntohs(inp); inp += 2; if (ack_opt.AP != lcp_ptr->RECV_NEG.AP) goto badack; switch (ack_opt.AP) { case PPP_PROT_CHAP: if (mqx_ntohc(inp) != 5) goto badack; /* Only MD5 supported */ inp++; ack_opt.AP_Start = CHAP_challenge; break; case PPP_PROT_PAP: ack_opt.AP_Start = PAP_open; break; default: ack_opt.AP = 0; break; } /* Endswitch */ } /* Endif */ if (lcp_ptr->RECV_NEG.NEG_PFC) { LCP_RACK(PFC,2); ack_opt.PFC = TRUE; } /* Endif */ if (lcp_ptr->RECV_NEG.NEG_ACFC) { LCP_RACK(ACFC,2); ack_opt.ACFC = TRUE; } /* Endif */ if (sizeleft) goto badack; if (fsm->STATE < PPP_STATE_OPENED) { lcp_ptr->RECV_OPT = ack_opt; } /* Endif */ return TRUE; badack: return FALSE; } /* Endbody */
static bool LCP_recvconfnak ( PPPFSM_CFG_PTR fsm /* [IN] - State Machine */ ) { /* Body */ LCP_CFG_PTR lcp_ptr = fsm->PRIVATE; unsigned char *inp = fsm->DATA; uint32_t sizeleft = fsm->LENGTH; LCP_NEG req_neg = lcp_ptr->RECV_NEG; unsigned char code; /* Start CR 2207 */ #if PPP_SECRETS_NOT_SHARED PPP_CFG_PTR ppp_ptr = lcp_ptr->HANDLE; #endif /* End CR 2207 */ #define LCP_RNAK(len) \ if (sizeleft < len) goto badnak; \ if (*inp++ != len) goto badnak; \ sizeleft -= len /* ** Nak'd codes must be in the same order as they were in the ConfReq */ code = *inp++; if (sizeleft && req_neg.NEG_MRU && code == LCP_CI_MRU) { LCP_RNAK(4); /* We are prepared to accept maximum MRU of 1500 */ req_neg.MRU = mqx_ntohs(inp); inp += 2; if (req_neg.MRU > DEFAULT_MRU) { req_neg.MRU = DEFAULT_MRU; } /* Endif */ code = *inp++; } /* Endif */ if (sizeleft && req_neg.NEG_ACCM && code == LCP_CI_ACCM) { LCP_RNAK(6); /* Add any characters they want to our ACCM */ req_neg.ACCM |= mqx_ntohl(inp); inp += 4; code = *inp++; } /* Endif */ if (sizeleft && req_neg.NEG_AP && code == LCP_CI_AP) { if (sizeleft < *inp || *inp < 4) goto badnak; sizeleft -= *inp; /* ** If AP is nak'd, we don't care what they want -- ** we choose the next most desirable protocol. If there ** aren't any more to choose, we keep the last one we tried. */ inp += *inp - 1; if (PPP_SECRET(ppp_ptr,_PPP_CHAP_RSECRETS)) { req_neg.AP = PPP_PROT_CHAP; } else { switch (req_neg.AP) { case PPP_PROT_CHAP: /* CHAP was NAKed, try PAP */ if (PPP_SECRET(ppp_ptr,_PPP_PAP_RSECRETS)) { req_neg.AP = PPP_PROT_PAP; } /* Endif */ break; case PPP_PROT_PAP: /* no other authentication protocols known */ break; default: /* Unknown protocol NAKed, try CHAP */ if (PPP_SECRET(ppp_ptr,_PPP_CHAP_RSECRETS)) { req_neg.AP = PPP_PROT_CHAP; } break; } /* Endswitch */ } code = *inp++; } /* Endif */ /* ** If we advertised PFC and/or ACFC and the peer doesn't ** want it, they should send a ConfRej rather than a ConfNak, ** so we're not going to check for them here (if they are ** here, the switch statement below will catch it). */ #define LCP_RNAK_ADD(ci,len) \ if (req_neg.NEG_ ## ci || sizeleft < len || *inp++ != len) goto badnak; \ sizeleft -= len; \ req_neg.NEG_ ## ci = 1 /* ** There may be remaining codes if the peer wants us to ** negotiate an option we didn't include. */ while (sizeleft) { switch (code) { case LCP_CI_MRU: LCP_RNAK_ADD(MRU,4); req_neg.MRU = mqx_ntohs(inp); inp += 2; if (req_neg.MRU > DEFAULT_MRU) { req_neg.MRU = DEFAULT_MRU; } /* Endif */ break; case LCP_CI_ACCM: LCP_RNAK_ADD(ACCM,6); req_neg.ACCM |= mqx_ntohl(inp); inp += 4; break; case LCP_CI_AP: if (req_neg.NEG_AP || sizeleft < *inp || *inp < 4) goto badnak; sizeleft -= *inp; /* ** If AP is nak'd, we don't care what they want -- ** we still don't negotiate */ inp += *inp - 1; break; case LCP_CI_PFC: LCP_RNAK_ADD(PFC,2); break; case LCP_CI_ACFC: LCP_RNAK_ADD(ACFC,2); break; default: if (sizeleft < *inp || *inp < 2) goto badnak; sizeleft -= *inp; inp += *inp - 1; } /* Endswtich */ code = *inp++; } /* Endwhile */ if (fsm->STATE < PPP_STATE_OPENED) { lcp_ptr->RECV_NEG = req_neg; } /* Endif */ return TRUE; badnak: return FALSE; } /* Endbody */
static bool LCP_recvconfrej ( PPPFSM_CFG_PTR fsm /* [IN] - State Machine */ ) { /* Body */ LCP_CFG_PTR lcp_ptr = fsm->PRIVATE; unsigned char *inp = fsm->DATA; uint32_t sizeleft = fsm->LENGTH; uint32_t aplen; PPP_OPT req_opt = lcp_ptr->RECV_OPT; LCP_NEG req_neg = lcp_ptr->RECV_NEG; unsigned char code; #define LCP_RREJ(ci,len) \ if (sizeleft < len) goto badrej; \ if (*inp++ != len) goto badrej; \ sizeleft -= len; \ req_neg.NEG_ ## ci = 0; \ req_opt.ci = PPP_DEFAULT_OPTIONS.ci /* ** Rej'd codes must be in the same order as they were in the ConfReq */ code = *inp++; if (sizeleft && req_neg.NEG_MRU && (code == LCP_CI_MRU)) { LCP_RREJ(MRU,4); if (req_neg.MRU != mqx_ntohs(inp)) goto badrej; inp += 2; code = *inp++; } /* Endif */ if (sizeleft && req_neg.NEG_ACCM && (code == LCP_CI_ACCM)) { LCP_RREJ(ACCM,6); if (req_neg.ACCM != mqx_ntohl(inp)) goto badrej; inp += 4; code = *inp++; } /* Endif */ if (sizeleft && req_neg.NEG_AP && (code == LCP_CI_AP)) { switch (req_neg.AP) { case PPP_PROT_CHAP: aplen = 5; break; default: aplen = 4; break; } /* Endswitch */ LCP_RREJ(AP,aplen); if (req_neg.AP != mqx_ntohs(inp)) goto badrej; inp += 2; switch (req_neg.AP) { case PPP_PROT_CHAP: if (5 != mqx_ntohc(inp)) goto badrej; /* Only MD5 supported */ inp++; break; } /* Endswitch */ req_opt.AP_Start = PPP_DEFAULT_OPTIONS.AP_Start; code = *inp++; } /* Endif */ if (sizeleft && req_neg.NEG_PFC && (code == LCP_CI_PFC)) { LCP_RREJ(PFC,2); code = *inp++; } /* Endif */ if (sizeleft && req_neg.NEG_ACFC && (code == LCP_CI_ACFC)) { LCP_RREJ(ACFC,2); code = *inp++; } /* Endif */ if (sizeleft) goto badrej; if (fsm->STATE < PPP_STATE_OPENED) { lcp_ptr->RECV_OPT = req_opt; lcp_ptr->RECV_NEG = req_neg; } /* Endif */ return TRUE; badrej: return FALSE; } /* Endbody */
static uint32_t LCP_recvconfreq ( PPPFSM_CFG_PTR fsm, /* [IN] - State Machine */ bool reject /* [IN] - whether to ConfRej if we disagree */ ) { /* Body */ LCP_CFG_PTR lcp_ptr = fsm->PRIVATE; unsigned char *inp = fsm->DATA; unsigned char *nakp, *rejp; uint32_t sizeleft = fsm->LENGTH; uint32_t naklen, rejlen; bool apneg = FALSE; PPP_OPT req_opt = lcp_ptr->SEND_OPT; unsigned char code; unsigned char cicode, cilen; /* Start CR 2207 */ #if PPP_SECRETS_NOT_SHARED PPP_CFG_PTR ppp_ptr = lcp_ptr->HANDLE; #endif /* End CR 2207 */ #define CI_REJECT(n) \ inp -= n; \ code = CP_CODE_CONF_REJ; \ rejlen += cilen; \ while (cilen--) *rejp++ = *inp++ #define CI_NAK \ if (code != CP_CODE_CONF_REJ) { \ code = CP_CODE_CONF_NAK; \ if (reject) { \ inp -= cilen; \ naklen += cilen; \ while (cilen--) *nakp++ = *inp++; \ } else { \ apneg = FALSE; #define CI_ENDNAK \ } /* Endif */ \ } /* Endif */ #define CI_NAKAP(n) \ if (code != CP_CODE_CONF_REJ) { \ code = CP_CODE_CONF_NAK; \ if (reject) { \ inp -= n; \ naklen += cilen; \ while (cilen--) *nakp++ = *inp++; \ } else { \ apneg = TRUE; \ inp += cilen - n; \ } /* Endif */ \ } else { \ inp += cilen - n; \ } /* Endif */ /* ** Process all requested codes */ rejp = nakp = inp; rejlen = naklen = 0; code = CP_CODE_CONF_ACK; while (sizeleft) { /* check remaining length */ if (sizeleft < inp[1] || inp[1] < 2) { code = CP_CODE_CONF_REJ; rejlen += sizeleft; while (sizeleft--) *rejp++ = *inp++; break; } /* Endif */ cicode = *inp++; sizeleft -= cilen = *inp++; switch (cicode) { case LCP_CI_MRU: if (cilen != 4) { CI_REJECT(2); break; } /* Endif */ /* Accept any MRU no smaller than 68 bytes */ req_opt.MRU = mqx_ntohs(inp); inp += 2; if (req_opt.MRU > DEFAULT_MRU) { req_opt.MRU = DEFAULT_MRU; } else if (req_opt.MRU < MINIMUM_MRU) { CI_NAK { *nakp++ = LCP_CI_MRU; naklen += *nakp++ = 4; req_opt.MRU = MINIMUM_MRU; mqx_htons(nakp, req_opt.MRU); nakp += 2; } CI_ENDNAK; } /* Endif */ break; case LCP_CI_ACCM: if (cilen != 6) { CI_REJECT(2); break; } /* Endif */ /* If we want any characters not in their ACCM, nak it */ req_opt.ACCM = mqx_ntohl(inp); inp += 4; if ((req_opt.ACCM & _PPP_ACCM) != _PPP_ACCM) { CI_NAK { *nakp++ = LCP_CI_ACCM; naklen += *nakp++ = 6; req_opt.ACCM |= _PPP_ACCM; mqx_htonl(nakp, req_opt.ACCM); nakp += 4; } CI_ENDNAK; } /* Endif */ break; /* ** AP is unusual in that it is a variable length ** option. Thus it is possible that we may want ** to nak AP and make a suggestion longer than ** the peer's request. ** ** This is bad. ** ** It's bad because this function wants to reuse ** the incoming ConfReq to build the reply, and ** in this case, it is possible for nakp to ** overtake inp, thus overwriting an option not ** yet parsed. ** ** So we do the following: If we decide to nak ** the requested AP, we just set apneg=TRUE and ** append the nak'd AP at the end of our ConfNak ** after we've completed parsing the ConfReq. ** ** Note that we won't nak AP if we generate ** nak's for other options afterward, because ** the RFC states that nak'd options MUST be in ** the same order that they were in the ConfReq. */ case LCP_CI_AP: if (cilen < 4) { CI_REJECT(2); break; } /* Endif */ /* If we don't have any secrets, reject AP */ /* Start CR 2207 */ if (!(PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET) || PPP_SECRET(ppp_ptr,_PPP_CHAP_LSECRETS))) { /* End CR 2207 */ CI_REJECT(2); break; } /* Endif */ /* Check the desired authentication protocol */ req_opt.AP = mqx_ntohs(inp); inp += 2; switch (req_opt.AP) { /* Accept PAP only if we have a secret */ case PPP_PROT_PAP: if (cilen != 4) { CI_REJECT(4); break; /* Start CR 2207 */ } else if (PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET) == NULL) { /* End CR 2207 */ CI_NAKAP(4); break; } /* Endif */ req_opt.AP_Start = PAP_send; break; /* Accept CHAP only if we have a secrets table */ case PPP_PROT_CHAP: if (cilen != 5) { CI_REJECT(4); break; /* Start CR 2207 */ } else if (PPP_SECRET(ppp_ptr,_PPP_CHAP_LSECRETS) == NULL) { /* End CR 2207 */ CI_NAKAP(4); break; } else if (*inp++ != 5) { /* Only MD5 supported */ CI_NAKAP(5); break; } /* Endif */ req_opt.AP_Start = CHAP_open; break; default: CI_NAKAP(4); break; } /* Endswitch */ break; case LCP_CI_MAGIC: if (cilen != 6) { CI_REJECT(2); break; } /* Endif */ inp += 4; break; case LCP_CI_PFC: if (cilen != 2) { CI_REJECT(2); break; } /* Endif */ req_opt.PFC = TRUE; break; case LCP_CI_ACFC: if (cilen != 2) { CI_REJECT(2); break; } /* Endif */ req_opt.ACFC = TRUE; break; default: CI_REJECT(2); break; } /* Endswitch */
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 */
DNAT_RULE_STRUCT_PTR DNAT_lookup_rule ( NAT_CFG_STRUCT_PTR nat_cfg_ptr, IP_HEADER_PTR ip_header_ptr, bool pub_to_prv ) { /* Body */ TRANSPORT_UNION transport; DNAT_ELEMENT_STRUCT_PTR element_ptr; _ip_address source_ip = mqx_ntohl(ip_header_ptr->SOURCE); uint32_t ip_protocol; uint16_t source_port, destination_port; /* source port and destination port */ transport.PTR = TRANSPORT_PTR(ip_header_ptr); ip_protocol = mqx_ntohc(ip_header_ptr->PROTOCOL); /* NAT spports ICMP, UDP and TCP transport layer protocols */ switch (ip_protocol) { case IPPROTO_TCP: destination_port = mqx_ntohs(transport.TCP_PTR->dest_port); source_port = mqx_ntohs(transport.TCP_PTR->source_port); break; case IPPROTO_UDP: destination_port = mqx_ntohs(transport.UDP_PTR->DEST_PORT); source_port = mqx_ntohs(transport.UDP_PTR->SRC_PORT); break; case IPPROTO_ICMP: /* Allow all ICMP request/reply */ return NULL; } /* Endswitch */ element_ptr = (DNAT_ELEMENT_STRUCT_PTR) _queue_head(&nat_cfg_ptr->RULE_QUEUE); /* ** Check for the target port and then forward the packet to the corresponding ** DNAT rule target ip. */ while (element_ptr != NULL) { if (element_ptr->RULE.IP_PROTOCOL == ip_protocol) { if (pub_to_prv) { if ((destination_port >= element_ptr->RULE.PUBLIC_START_PORT) && (destination_port <= element_ptr->RULE.PUBLIC_END_PORT)) { break; } } else { if ((source_ip == element_ptr->RULE.PRIVATE_IP) && (source_port >= element_ptr->RULE.PRIVATE_START_PORT) && (source_port <= element_ptr->RULE.PRIVATE_END_PORT)) { break; } } } element_ptr = (DNAT_ELEMENT_STRUCT_PTR) _queue_next(&nat_cfg_ptr->RULE_QUEUE, &element_ptr->ELEMENT); } /* Endwhile */ if (element_ptr!=NULL) { return &element_ptr->RULE; } else { return NULL; } }/* Endbody */
HOSTENT_STRUCT *DNS_parse_UDP_response ( unsigned char *buffer_ptr, unsigned char *name_ptr, uint16_t query_type ) { /* Body */ DNS_MESSAGE_HEADER_STRUCT *message_head_ptr = NULL; DNS_RESPONSE_RR_MIDDLE_STRUCT *answer_middle; INTERNAL_HOSTENT_STRUCT *host_ptr = &RTCS_HOST; unsigned char *answer_ptr; unsigned char *answer_tail; unsigned char *temp_ptr; uint16_t response_length, answer_type, name_size, number_of_answers, num_queries; uint32_t i, name_index = 0; uint32_t j = 0; uint32_t k = 0; uint32_t buffer_size; uint32_t *addr_ptr; bool unknown_answer_type = FALSE; message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT *)buffer_ptr; buffer_size = sizeof(DNS_MESSAGE_HEADER_STRUCT); temp_ptr = buffer_ptr + sizeof( DNS_MESSAGE_HEADER_STRUCT ); /* Zero the global HOSTENT_STRUCT */ _mem_zero((char *)host_ptr, sizeof(INTERNAL_HOSTENT_STRUCT)); /* Get the number of queries. */ num_queries = mqx_ntohs(message_head_ptr->QDCOUNT); for (i = 0; i < num_queries; i++) { name_size = 0; while( (mqx_ntohc(temp_ptr) != '\0') && name_size < DNS_MAX_CHARS_IN_NAME ) { name_size = name_size + mqx_ntohc(temp_ptr) + 1; temp_ptr = temp_ptr + mqx_ntohc(temp_ptr) + 1; } /* Endwhile */ /* To include the terminating NULL char */ name_size++; buffer_size += (name_size + sizeof(DNS_MESSAGE_TAIL_STRUCT)); temp_ptr += (1 + sizeof(DNS_MESSAGE_TAIL_STRUCT)); } /* Endfor */ number_of_answers = mqx_ntohs(message_head_ptr->ANCOUNT); if (number_of_answers > DNS_MAX_NAMES ) { number_of_answers = DNS_MAX_NAMES; } /* Endif */ host_ptr->HOSTENT.h_aliases = &host_ptr->ALIASES[0]; host_ptr->HOSTENT.h_addr_list = (char **)&host_ptr->ADDRESSES[0]; host_ptr->ADDRESSES[0] = NULL; host_ptr->HOSTENT.h_name = NULL; host_ptr->HOSTENT.h_length = sizeof( _ip_address ); for (i = 0; (i < number_of_answers) && (j < DNS_MAX_ADDRS) && (k < DNS_MAX_NAMES); i++ ) { answer_ptr = temp_ptr; name_size = 0; while( (mqx_ntohc(temp_ptr) != '\0') && name_size < DNS_MAX_CHARS_IN_NAME && !(mqx_ntohc(temp_ptr) & DNS_COMPRESSED_NAME_MASK)) { name_size += mqx_ntohc(temp_ptr); temp_ptr += mqx_ntohc(temp_ptr) + 1; } /* Endwhile */ if ( mqx_ntohc(temp_ptr) & DNS_COMPRESSED_NAME_MASK ) { temp_ptr++; }/* Endif */ temp_ptr++; answer_middle = (DNS_RESPONSE_RR_MIDDLE_STRUCT *)temp_ptr; response_length = mqx_ntohs(answer_middle->RDLENGTH); answer_type = mqx_ntohs(answer_middle->TYPE); temp_ptr += sizeof(DNS_RESPONSE_RR_MIDDLE_STRUCT); answer_tail = temp_ptr; temp_ptr += response_length; switch ( answer_type ) { case DNS_A: if ( host_ptr->HOSTENT.h_name == NULL ) { host_ptr->HOSTENT.h_name = (char *)DNS_parse_answer_name_to_dotted_form( buffer_ptr, answer_ptr, name_index ); name_index++; } /* Endif */ RTCS_HOST_ADDRS[j] = mqx_ntohl((unsigned char *)answer_tail); /* ** j is used in case BOTH CNAME and A data is received. If CNAME ** answer is first, will write into wrong address space if using ** i. */ host_ptr->ADDRESSES[j] = &RTCS_HOST_ADDRS[j]; j++; /* ** This is to assure that the first IP address used is the first ** one that was given */ host_ptr->IP_address = *host_ptr->ADDRESSES[0]; break; case DNS_PTR: if (query_type == DNS_PTR) { if (host_ptr->HOSTENT.h_name != NULL) { host_ptr->ALIASES[k] = host_ptr->HOSTENT.h_name; k++; } /* Endif */ host_ptr->HOSTENT.h_name = (char *)DNS_parse_answer_name_to_dotted_form( buffer_ptr, answer_tail, name_index ); name_index++; addr_ptr = RTCS_mem_alloc_zero( sizeof( _ip_address )); if ( addr_ptr == NULL ) { RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_ALLOCATE_MEMORY, 0, 0, 0); return( NULL ); }/* Endif */ *addr_ptr = *((_ip_address *)name_ptr); host_ptr->ADDRESSES[j] = addr_ptr; j++; host_ptr->IP_address = *host_ptr->ADDRESSES[0]; } else { host_ptr->ALIASES[k] = (char *) DNS_parse_answer_name_to_dotted_form( buffer_ptr, answer_tail, name_index ); name_index++; k++; } /* Endif */ break; case DNS_CNAME: /* the k is used for ALIASES as the j is used for ADDRESSES */ host_ptr->ALIASES[k] = (char *) DNS_parse_answer_name_to_dotted_form( buffer_ptr, answer_tail, name_index ); name_index++; k++; break; default: unknown_answer_type = TRUE; } /* Endswitch */ if ( unknown_answer_type == TRUE ) { break; }/* Endif */ host_ptr->ADDRESSES[j] = NULL; host_ptr->ALIASES[k] = NULL; host_ptr->HOSTENT.h_addrtype = mqx_ntohs(answer_middle->CLASS); } /* Endfor */ if ( number_of_answers == 0 ) { return( NULL ); } /* Endif */ return( &RTCS_HOST.HOSTENT ); } /* Endbody */
/************************************************************************ * NAME: add_ip * RETURNS: 0 if OK. * DESCRIPTION: Try to Resolve IP address using DNS Client. *************************************************************************/ static int add_ip(int family, const char *hostname, int flags, struct addrinfo **aip, int socktype, int port) { struct addrinfo *ai; int result; char *ip_loop; _mem_size ip_length; DNSCLN_TYPE dns_type; DNSCLN_RECORD_STRUCT *dns_record_list = NULL; DNSCLN_PARAM_STRUCT dns_params; int i; #if RTCSCFG_ENABLE_IP4 if(family == AF_INET) { ip_loop = v4_loop; ip_length = sizeof(in_addr); dns_type = DNSCLN_TYPE_A; } else #endif #if RTCSCFG_ENABLE_IP6 if(family == AF_INET6) { ip_loop = v6_loop; ip_length = sizeof(in6_addr); dns_type = DNSCLN_TYPE_AAAA; } else #endif {}; if (hostname == NULL && (flags & AI_PASSIVE) == 0) { /* In this case to get connection * inside host using LOOPBACK interface . */ ai = ai_clone(*aip, AF_INET); if (ai == NULL) { freeaddrinfo(*aip); GAI_EXIT(EAI_MEMORY); } *aip = ai; ai->ai_socktype = socktype; SIN(ai->ai_addr)->sin_port = port; _mem_copy(ip_loop, &SIN(ai->ai_addr)->sin_addr, ip_length); result = EAI_OK; } else { /* If the hostname is not NULL,lets try to resolve it * here we are using RTCS DNS Client to get addr by name. */ for(i=0; (DNSCLN_get_dns_addr(NULL, i, &dns_params.dns_server) == TRUE); i++) { dns_params.name_to_resolve = (char*)hostname; /* Host name to resolve (null-terminated string). */ dns_params.type = dns_type; /* DNS Resource Record Type that is queried. */ /* Send DNS Query.*/ dns_record_list = DNSCLN_query(&dns_params); /* Process DNS result.*/ if(dns_record_list) { /* Resolved.*/ DNSCLN_RECORD_STRUCT *dns_record = dns_record_list; do { ai = ai_clone(*aip, family); if (ai == NULL) { freeaddrinfo(*aip); GAI_EXIT(EAI_MEMORY); } *aip = ai; ai->ai_socktype = socktype; ((struct sockaddr_in *)(ai->ai_addr))->sin_port = port; /* Special case for AF_INET. From network to host endian.*/ if(family == AF_INET) { ((struct sockaddr_in *)(ai->ai_addr))->sin_addr.s_addr = mqx_ntohl(dns_record->data); } else _mem_copy(dns_record->data, &((struct sockaddr_in *)(ai->ai_addr))->sin_addr, ip_length); if (flags & AI_CANONNAME) { if(dns_record->name) { ai->ai_canonname = strdup(dns_record->name); if (ai->ai_canonname == NULL) { GAI_EXIT(EAI_NONAME); } } } dns_record = dns_record->next; } while(dns_record); GAI_EXIT(EAI_OK); } } /* Not resolved.*/ GAI_EXIT(EAI_FAIL); }/* end of (hostname == NULL && (flags & AI_PASSIVE) == 0) */ cleanup: if(dns_record_list) DNSCLN_record_list_free(dns_record_list); return (result); }
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 *parms = (TCPIP_PARM_BOOTP *)if_ptr->BOOT; BOOTP_CFG_PTR bootp = (BOOTP_CFG_PTR) &parms->config; BOOTP_PACKET_PTR bootreply; IPIF_PARM parms_bind; uint32_t error; unsigned char *opt; unsigned char 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 (mqx_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 = mqx_ntohl(bootreply->HEAD.YIADDR); parms_bind.locmask = 0xFFFFFFFFL; parms_bind.netmask = IN_DEFAULT_NET(parms_bind.address); parms_bind.probe = FALSE; parms->data->SADDR = mqx_ntohl(bootreply->HEAD.SIADDR); #if RTCSCFG_BOOTP_RETURN_YIADDR parms->data->CLIENTADDR = mqx_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 (mqx_ntohl(opt) == BOOTP_MAGIC) { opt += 4; len -= 4; #define BOOTP_NEXTOPT opt += optlen; \ break while (len) { /* Get the next option code */ optval = mqx_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 = mqx_ntohc(opt); opt++; len--; if (len < optlen) break; len -= optlen; switch (optval) { case BOOTPOPT_MASK: if (optlen != 4) {BOOTP_NEXTOPT;} parms_bind.netmask = mqx_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 */