static void IPREASM_add_frag ( IP_DGRAM_PTR dgram, /* [IN] the dgram */ RTCSPCB_PTR inpcb /* [IN] the received PCB */ ) { /* Body */ IP_HEADER_PTR iph = (IP_HEADER_PTR)RTCSPCB_DATA(inpcb); uint32_t iphlen = (mqx_ntohc(iph->VERSLEN) & 0xF) << 2; uint32_t totlen = mqx_ntohs(iph->LENGTH); int32_t offset = mqx_ntohs(iph->FRAGMENT); int32_t first = (offset & IP_FRAG_MASK) << IP_FRAG_SHIFT; uint32_t datalen = totlen - iphlen; unsigned char *data = (unsigned char *)iph + iphlen; IPREASM_BLK_PTR blk; uint32_t len; if (offset & IP_FRAG_MF) { /* Fragments (except the last) must be multiples of 8 bytes */ if ((datalen & 0x07) != 0) { return; } /* Endif */ } else { /* If this fragment is the last one, record the total length */ dgram->TOTLEN = first + datalen; } /* Endif */ /* Once we get the first fragment, record the IP header and 8 data bytes */ if (first == 0) { _mem_copy(iph, &dgram->header.IP4.IPH, iphlen + 8); dgram->TYPE = inpcb->TYPE; dgram->IFSRC = inpcb->IFSRC; dgram->LINKOPT = inpcb->LINK_OPTIONS.RX; } /* Endif */ while (datalen) { blk = IPREASM_blk_get(dgram, first); if (!blk) { return; } /* Endif */ len = IPREASM_blk_write(dgram, blk, first, data, datalen); first += len; data += len; datalen -= len; } /* Endwhile */ } /* Endbody */
void NAT_ALG_TCP_checksum ( IP_HEADER_PTR ip_header_ptr /* [IN] pointer to IP header */ ) { /* Body */ TRANSPORT_UNION transport; uint16_t checksum; uint16_t protocol; uint16_t iplen = IPH_LEN(ip_header_ptr); uint16_t len = mqx_ntohs(ip_header_ptr->LENGTH) - iplen; /* Get TCP header */ transport.PTR = TRANSPORT_PTR(ip_header_ptr); mqx_htons(transport.TCP_PTR->checksum, 0); /* Clear checksum field */ protocol = mqx_ntohc(ip_header_ptr->PROTOCOL); /* PROTOCOL */ checksum = (uint16_t) _mem_sum_ip(protocol, 8, ip_header_ptr->SOURCE); /* IP SRC and DST ADDR */ checksum = (uint16_t) _mem_sum_ip(checksum, len, transport.PTR); /* TCP LENGTH */ checksum = IP_Sum_immediate(checksum, len); checksum = IP_Sum_invert(checksum); mqx_htons(transport.TCP_PTR->checksum, checksum); } /* Endbody */
static unsigned char *DNS_parse_answer_name_to_dotted_form ( unsigned char *buffer_ptr, unsigned char *name, uint32_t loc ) { /* Body */ unsigned char *compressed_name; unsigned char *fill_ptr; unsigned char label_size; uint32_t i; uint16_t new_location; fill_ptr = RTCS_HOST_NAMES[loc]; _mem_zero(fill_ptr, DNS_MAX_CHARS_IN_NAME); compressed_name = name; while ( mqx_ntohc(compressed_name) != '\0' ) { if ( mqx_ntohc(compressed_name) & DNS_COMPRESSED_NAME_MASK ) { new_location = mqx_ntohs(compressed_name) & DNS_COMPRESSED_LOCATION_MASK; compressed_name = buffer_ptr + new_location; }/* Endif */ label_size = mqx_ntohc(compressed_name); compressed_name++; for ( i = 0; i < label_size; i++ ) { *fill_ptr++ = mqx_ntohc(compressed_name); compressed_name++; } /* Endfor */ if ( mqx_ntohc(compressed_name) != '\0' ) { *fill_ptr++ = '.'; }/* Endif */ } /* Endwhile */ *fill_ptr = '\0'; return( RTCS_HOST_NAMES[loc] ); } /* 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 */
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 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_recvextcode ( PPPFSM_CFG_PTR fsm /* [IN] - State Machine */ ) { /* Body */ PPP_CFG_PTR ppp_ptr = fsm->HANDLE; LCP_CFG_PTR lcp_ptr = fsm->PRIVATE; PPP_CALL_INTERNAL_PTR call_ptr = &ppp_ptr->LCP_CALL[PPP_CALL_ECHO_REPLY]; switch (fsm->CODE) { case LCP_CODE_PROT_REJ: lcp_ptr->ST_LCP_RX_REJECT++; /* ** We should notify the rejected protocol, but there ** currently isn't any way to do this. What we'll do ** instead is to send a STOP message to the Tx task on ** behalf of the protocol. ** ** This will usually be sufficient, since the rejected ** protocol isn't likely to send another packet until ** either it receives a packet (in which case it's OK to ** reply) or the retransmission timer kicks in (which ** we're about to disable). ** ** Thus, this will effectively stop the rejected protocol. */ if (fsm->LENGTH >= 2) { uint16_t protocol = mqx_ntohs(fsm->DATA); PPP_send_stop(ppp_ptr, protocol); } /* Endif */ PCB_free(fsm->PACKET); break; case LCP_CODE_ECHO_REQ: lcp_ptr->ST_LCP_RX_ECHO++; if (fsm->STATE < PPP_STATE_OPENED) { PCB_free(fsm->PACKET); } else { mqx_htonc(fsm->DATA - CP_HDR_LEN, LCP_CODE_ECHO_REP); mqx_htonl(fsm->DATA, 0); /* Set magic field to 0 */ lcp_ptr->ST_LCP_TX_REPLY++; PPP_send_one(ppp_ptr, PPP_PROT_LCP, fsm->PACKET); } /* Endif */ break; case LCP_CODE_ECHO_REP: lcp_ptr->ST_LCP_RX_REPLY++; if (call_ptr->CALLBACK) { call_ptr->CALLBACK(call_ptr->PARAM, fsm->ID, fsm->PACKET); } /* Endif */ PCB_free(fsm->PACKET); break; case LCP_CODE_DISC_REQ: lcp_ptr->ST_LCP_RX_DISCARD++; PCB_free(fsm->PACKET); break; default: return FALSE; } /* Endswitch */ return TRUE; } /* Endbody */
void TFTPSRV_service_transaction ( TFTPSRV_STATE_STRUCT_PTR tftpsrv_ptr, /* [IN/OUT] The TFTP Server state */ TFTP_TRANS_STRUCT_PTR trans_ptr /* [IN/OUT] The transaction state */ ) { /* Body */ sockaddr_in sockaddr_tftp; uint32_t block_num; int32_t pkt_len, write_len; uint16_t sockaddrlen, pkt_op; /* receive the datagram */ sockaddrlen = sizeof(sockaddr_tftp); pkt_len = recvfrom(trans_ptr->SOCK, tftpsrv_ptr->BUFFER, TFTP_MAX_MESSAGE_SIZE, 0,(sockaddr *)&sockaddr_tftp, &sockaddrlen); if (pkt_len == RTCS_ERROR) { return; } /* Endif */ /* verify the sender's address and port */ if ((trans_ptr->ADDR.sin_port != sockaddr_tftp.sin_port) || (trans_ptr->ADDR.sin_addr.s_addr != sockaddr_tftp.sin_addr.s_addr)) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_tid, sockaddr_tftp); return; } /* Endif */ /* get op and block number */ if (pkt_len < sizeof(TFTP_HEADER)) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_tid, sockaddr_tftp); return; } /* Endif */ pkt_op = mqx_ntohs(tftpsrv_ptr->BUFFER); block_num = mqx_ntohs(tftpsrv_ptr->BUFFER + 2); /* verify the requested operation */ if (pkt_op != trans_ptr->RECV_OP) { if (pkt_op != TFTPOP_ERROR) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_op, sockaddr_tftp); } /* Endif */ TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ switch (pkt_op) { case TFTPOP_DATA: /* We are servicing a write request from a TFTP Client here */ if (block_num == trans_ptr->BLOCK) { pkt_len -= sizeof(TFTP_HEADER); write_len = RTCS_io_write(trans_ptr->TRANS_FILE_PTR, tftpsrv_ptr->BUFFER + sizeof(TFTP_HEADER), pkt_len); fflush(trans_ptr->TRANS_FILE_PTR); if (write_len != pkt_len) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_srv, trans_ptr->ADDR); TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ TFTPSRV_build_ACK(trans_ptr); trans_ptr->EXIT = (write_len < sizeof(TFTP_PACKET) - sizeof(TFTP_HEADER)); TFTPSRV_timer_cancel(tftpsrv_ptr, trans_ptr); TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_update(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); } else if (block_num == trans_ptr->BLOCK - 1) { TFTPSRV_timer_cancel(tftpsrv_ptr, trans_ptr); TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_restart(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); } /* Endif */ break; case TFTPOP_ACK: /* We are servicing a read request */ if (block_num == trans_ptr->BLOCK) { if (trans_ptr->EXIT) { /* We've received the last ACK, exit */ TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ TFTPSRV_build_DATA(trans_ptr); if (trans_ptr->SEND_SIZE < sizeof(TFTP_HEADER)) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_srv, sockaddr_tftp); TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ TFTPSRV_timer_cancel(tftpsrv_ptr, trans_ptr); TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_update(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); } /* Endif */ break; } /* Endswitch */ } /* Endbody */
void TFTPSRV_service_request ( TFTPSRV_STATE_STRUCT_PTR tftpsrv_ptr /* [IN/OUT] The TFTP Server state */ ) { /* Body */ TFTP_TRANS_STRUCT_PTR trans_ptr; sockaddr_in sockaddr_t; int32_t pkt_len, i; uint32_t error; char *filename, *filemode; uint16_t sockaddrlen, pkt_op; /* receive the datagram */ sockaddrlen = sizeof(sockaddr_t); pkt_len = recvfrom(tftpsrv_ptr->SRV_SOCK, tftpsrv_ptr->BUFFER, TFTP_MAX_MESSAGE_SIZE, 0, (sockaddr *)&sockaddr_t, &sockaddrlen); if (pkt_len == RTCS_ERROR) { return; } /* Endif */ /* limit the number of concurrent transactions */ if (tftpsrv_ptr->NUM_TRANSACTIONS >= TFTPSRV_MAX_TRANSACTIONS) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_busy, sockaddr_t); return; } /* Endif */ /* parse the request; extract op, filename and filemode */ i = 2; filename = (char *)tftpsrv_ptr->BUFFER + i; for (; i<pkt_len; i++) { if (tftpsrv_ptr->BUFFER[i] == '\0') break; } /* Endfor */ i++; filemode = (char *)tftpsrv_ptr->BUFFER + i; for (; i<pkt_len; i++) { if (tftpsrv_ptr->BUFFER[i] == '\0') break; } /* Endfor */ if (i >= pkt_len) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_op, sockaddr_t); return; } /* Endif */ pkt_op = mqx_ntohs(tftpsrv_ptr->BUFFER); /* allocate state for the new transaction */ trans_ptr = RTCS_mem_alloc_zero(sizeof(TFTP_TRANS_STRUCT)); if (trans_ptr == NULL) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); return; } /* Endif */ _mem_set_type(trans_ptr, MEM_TYPE_TFTP_TRANS_STRUCT); /* validate the requested operation */ switch (pkt_op) { case TFTPOP_RRQ: trans_ptr->RECV_OP = TFTPOP_ACK; trans_ptr->SEND_OP = TFTPOP_DATA; break; case TFTPOP_WRQ: trans_ptr->RECV_OP = TFTPOP_DATA; trans_ptr->SEND_OP = TFTPOP_ACK; break; default: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_op, sockaddr_t); _mem_free(trans_ptr); return; } /* Endswitch */ /* open the requested file */ error = TFTPSRV_open_device(pkt_op, filename, filemode, &trans_ptr->TRANS_FILE_PTR); if (error) { switch (error) { case RTCS_EACCES: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_accvio, sockaddr_t); break; case RTCS_ENOENT: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_nofile, sockaddr_t); break; case RTCS_EEXIST: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_exists, sockaddr_t); break; default: TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); break; } /* Endswitch */ _mem_free(trans_ptr); return; } /* Endif */ /* create a socket for the new transaction */ trans_ptr->SOCK = socket(PF_INET, SOCK_DGRAM, 0); if (trans_ptr->SOCK == RTCS_SOCKET_ERROR) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); RTCS_io_close(trans_ptr->TRANS_FILE_PTR); _mem_free(trans_ptr); return; } /* Endif */ trans_ptr->ADDR.sin_family = sockaddr_t.sin_family; trans_ptr->ADDR.sin_port = sockaddr_t.sin_port; trans_ptr->ADDR.sin_addr.s_addr = sockaddr_t.sin_addr.s_addr; sockaddr_t.sin_family = AF_INET; sockaddr_t.sin_port = 0; sockaddr_t.sin_addr.s_addr = INADDR_ANY; error = bind(trans_ptr->SOCK, (const sockaddr *)&sockaddr_t, sizeof(sockaddr_t)); if (error != RTCS_OK) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); shutdown(trans_ptr->SOCK, 0); RTCS_io_close(trans_ptr->TRANS_FILE_PTR); _mem_free(trans_ptr); return; } /* Endif */ /* build the first packet */ trans_ptr->BLOCK = 0; switch (trans_ptr->SEND_OP) { case TFTPOP_DATA: TFTPSRV_build_DATA(trans_ptr); break; case TFTPOP_ACK: TFTPSRV_build_ACK(trans_ptr); trans_ptr->EXIT = FALSE; break; } /* Endswitch */ if (trans_ptr->SEND_SIZE < sizeof(TFTP_HEADER)) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_srv, sockaddr_t); shutdown(trans_ptr->SOCK, 0); RTCS_io_close(trans_ptr->TRANS_FILE_PTR); _mem_free(trans_ptr); return; } /* Endif */ /* send the first packet */ TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_init(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); tftpsrv_ptr->SOCKETS[tftpsrv_ptr->NUM_TRANSACTIONS] = trans_ptr->SOCK; tftpsrv_ptr->TRANS_PTRS[tftpsrv_ptr->NUM_TRANSACTIONS] = trans_ptr; tftpsrv_ptr->NUM_TRANSACTIONS++; } /* 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 */
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 */
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 */
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 */
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 */
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 */
unsigned char *TFTP_read ( uint32_t *size /* [OUT] number of bytes read, or error code */ ) { /* Body */ uint32_t sock; sockaddr_in remote_addr; uint16_t remote_size; uint16_t ack_block; uint16_t pkt_op, pkt_block; uint32_t pkt_size; uint32_t time_left; bool expired; #if TFTP_TIMEOUT_RETRIES uint32_t retries = 0; #endif ack_block = mqx_ntohs(TFTP_config.ACK.BLOCK); TFTP_timeout_restart(&TFTP_config.TIMEOUT); for (;;) { /* Check for timeout */ time_left = TFTP_timeout_left(&TFTP_config.TIMEOUT, &expired); if (expired) { #if TFTP_TIMEOUT_RETRIES retries++; if (retries > TFTP_TIMEOUT_RETRIES) { *size = RTCSERR_TFTP_TIMEOUT; TFTP_close(); return NULL; } /* Endif */ #endif /* Retransmit the last packet */ TFTP_RESEND(); } /* Endif */ /* Wait for a packet */ sock = TFTP_WAIT(time_left); /* Timeout -- retransmit last packet */ if (sock != TFTP_config.SOCK) { continue; } /* Endif */ remote_size = sizeof(remote_addr); pkt_size = TFTP_RECV(TFTP_config.PACKET); pkt_op = mqx_ntohs(TFTP_config.PACKET.HEAD.OP); pkt_block = mqx_ntohs(TFTP_config.PACKET.HEAD.BLOCK); /* Check source address of received packet */ if (remote_addr.sin_addr.s_addr != TFTP_config.SADDR.sin_addr.s_addr) { continue; } /* Endif */ /* Validate source port */ if (ack_block && remote_addr.sin_port != TFTP_config.SADDR.sin_port) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_tid, remote_addr); continue; } /* Endif */ /* Check size of received packet */ if (pkt_size < sizeof(TFTP_HEADER)) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr); *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP; TFTP_close(); return NULL; } /* Endif */ /* Check for error packet */ if (pkt_op == TFTPOP_ERROR) { *size = RTCSERR_TFTP_ERROR + pkt_block; TFTP_close(); return NULL; } /* Endif */ /* Check for data packet */ if ((pkt_op != TFTPOP_DATA) || (pkt_size > sizeof(TFTP_PACKET))) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr); *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP; TFTP_close(); return NULL; } /* Endif */ /* Check for retransmitted packet */ if (pkt_block == ack_block) { TFTP_timeout_restart(&TFTP_config.TIMEOUT); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); continue; } /* Endif */ /* Aknowledge also packets with lower id, some servers do retransmit them until they get an ack */ if (pkt_block < ack_block) { TFTP_timeout_restart(&TFTP_config.TIMEOUT); mqx_htons(TFTP_config.ACK.BLOCK, pkt_block); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); mqx_htons(TFTP_config.ACK.BLOCK, ack_block); /* Restore id of last acknowledged packet */ continue; } /* Endif */ /* Drop unexpected packets */ if (pkt_block > ack_block+1) { /* Some server do send more than one packet at a time, these will eventually retransmitted */ continue; } /* We have the next packet */ break; } /* Endfor */ /* Update the adaptive timeout */ TFTP_timeout_update(&TFTP_config.TIMEOUT); /* Free the original RRQ */ if (!ack_block) { TFTP_config.SADDR.sin_port = remote_addr.sin_port; _mem_free(TFTP_config.RRQ_PTR); TFTP_config.RRQ_PTR = NULL; } /* Endif */ /* ACK it */ ack_block++; mqx_htons(TFTP_config.ACK.BLOCK, ack_block); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); TFTP_config.LAST = (pkt_size < sizeof(TFTP_PACKET)); /* Return the data */ *size = pkt_size - sizeof(TFTP_HEADER); return TFTP_config.PACKET.DATA; } /* Endbody */