void DNAT_get_next_rule_internal ( DNAT_PARM_PTR dparm_ptr /* [IN] */ ) { /* Body */ NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT); DNAT_ELEMENT_STRUCT_PTR prev_element_ptr, next_element_ptr; if (nat_cfg_ptr == NULL) { RTCSCMD_complete(dparm_ptr, RTCSERR_NAT_NOT_INITIALIZED); return; } prev_element_ptr = NULL; next_element_ptr = (DNAT_ELEMENT_STRUCT_PTR) _queue_head(&nat_cfg_ptr->RULE_QUEUE); while ((next_element_ptr != NULL) && (next_element_ptr->RULE.PRIORITY >= dparm_ptr->RULE.PRIORITY)) { prev_element_ptr = next_element_ptr; next_element_ptr = (DNAT_ELEMENT_STRUCT_PTR) _queue_next(&nat_cfg_ptr->RULE_QUEUE, &prev_element_ptr->ELEMENT); } if (next_element_ptr == NULL) { RTCSCMD_complete(dparm_ptr, RTCSERR_NAT_END_OF_RULES); } else { dparm_ptr->RULE = next_element_ptr->RULE; RTCSCMD_complete(dparm_ptr, RTCS_OK); } }/* Endbody */
void RTCS_remove_trap_receiver_internal ( TRAP_PARM *parm ) { /* Body */ volatile SNMP_PARSE_PTR snmpcfg = SNMP_get_data(); _ip_address ip_addr = parm->address; _mqx_uint i; /* Traverse the receivers list looking for our entry */ for (i = 0; i < SNMPCFG_MAX_TRAP_RECEIVERS; i++) { if (snmpcfg->trap_receiver_list[i] == ip_addr) { /* Found it */ snmpcfg->trap_receiver_list[i] = 0; break; } /* Endif */ } /* Endfor */ if (i < SNMPCFG_MAX_TRAP_RECEIVERS) { RTCSCMD_complete(parm, RTCS_OK); } else { RTCSCMD_complete(parm, RTCSERR_TRAP_REMOVE_FAILED); } /* Endif */ } /* Endbody */
void DNAT_delete_rule_internal ( DNAT_PARM_PTR dparm_ptr /* [IN] */ ) { /* Body */ NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT); DNAT_ELEMENT_STRUCT_PTR element_ptr; uint32_t priority = dparm_ptr->RULE.PRIORITY; if (nat_cfg_ptr == NULL) { RTCSCMD_complete(dparm_ptr, RTCSERR_NAT_NOT_INITIALIZED); return; } element_ptr = (DNAT_ELEMENT_STRUCT_PTR) _queue_head(&nat_cfg_ptr->RULE_QUEUE); while (element_ptr != NULL) { if (element_ptr->RULE.PRIORITY == priority) { _queue_unlink(&nat_cfg_ptr->RULE_QUEUE, &element_ptr->ELEMENT); _mem_free((void *)element_ptr); RTCSCMD_complete(dparm_ptr, RTCS_OK); return; } element_ptr = (DNAT_ELEMENT_STRUCT_PTR) _queue_next(&nat_cfg_ptr->RULE_QUEUE, &element_ptr->ELEMENT); } RTCSCMD_complete(dparm_ptr, RTCSERR_NAT_INVALID_RULE); } /* Endbody */
void RTCS_insert_trap_receiver_internal ( TRAP_PARM *parm ) { /* Body */ volatile SNMP_PARSE_PTR snmpcfg = SNMP_get_data(); _ip_address ip_addr = parm->address; _mqx_uint i; /* Find an empty entry in the receivers list */ for (i = 0; i < SNMPCFG_MAX_TRAP_RECEIVERS; i++) { if (snmpcfg->trap_receiver_list[i] == 0) { /* Found a space */ snmpcfg->trap_receiver_list[i] = ip_addr; break; } /* Endif */ } /* Endfor */ if (i < SNMPCFG_MAX_TRAP_RECEIVERS) { RTCSCMD_complete(parm, RTCS_OK); } else { RTCSCMD_complete(parm, RTCSERR_TRAP_INSERT_FAILED); } /* Endif */ } /* Endbody */
void NAT_remove_network_internal ( NAT_PARM_PTR parm_ptr /* [IN] Initialization parameters */ ) { /* Body */ NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT); uint_32 error; // Make sure NAT is already up if (nat_cfg_ptr == NULL) { error = RTCSERR_NAT_NOT_INITIALIZED; /* ** Make sure the netmask is valid. We use the fact that ** (x & x+1) == 0 <=> x = 2^n-1. */ } else if (~parm_ptr->IP_MASK & (~parm_ptr->IP_MASK + 1)) { error = RTCSERR_INVALID_PARAMETER; /* Make sure other parameters have been supplied */ } else if (!parm_ptr->IP_PRV) { error = RTCSERR_INVALID_PARAMETER; } else { // Try to remove the private network error=NAT_remove_private_network(&nat_cfg_ptr->PRIVATE_NETWORKS, parm_ptr->IP_PRV, parm_ptr->IP_MASK); } RTCSCMD_complete(parm_ptr, error); } /* Endbody */
void NAT_init_internal ( NAT_PARM_PTR parm_ptr /* [IN] Initialization parameters */ ) { RTCSCMD_complete(parm_ptr, NAT_init_internal2(parm_ptr)); }
/*FUNCTION*------------------------------------------------------------- * * Function Name : ICMP_expire_echo * Returned Values : * Comments : * Called by the Timer. Expire a ICMP echo request. * *END*-----------------------------------------------------------------*/ boolean ICMP6_expire_echo(TCPIP_EVENT_PTR event) { ICMP_ECHO_PARAM_PTR parms = event->PRIVATE; RTCSCMD_complete(parms, RTCSERR_ICMP_ECHO_TIMEOUT); return FALSE; }
void IPCP_bind ( TCPIP_PARM_IPCP _PTR_ parms ) { /* Body */ IP_IF_PTR if_ptr = parms->handle; IPCP_CFG_STRUCT_PTR ipcp_ptr = if_ptr->HANDLE; _ppp_handle handle = ipcp_ptr->HANDLE; uint_32 error; ipcp_ptr->CALLUP = IPCP_lowerup; ipcp_ptr->PARAMUP = &ipcp_ptr->FSM; ipcp_ptr->CALLDOWN = IPCP_lowerdown; ipcp_ptr->PARAMDOWN = &ipcp_ptr->FSM; error = PPP_setcall(handle, PPP_CALL_LINK_UP, &ipcp_ptr->CALLUP, &ipcp_ptr->PARAMUP); if (!error) { error = PPP_setcall(handle, PPP_CALL_LINK_DOWN, &ipcp_ptr->CALLDOWN, &ipcp_ptr->PARAMDOWN); if (error) { PPP_setcall(handle, PPP_CALL_LINK_UP, &ipcp_ptr->CALLUP, &ipcp_ptr->PARAMUP); } /* Endif */ } /* Endif */ if (!error) { ipcp_ptr->IP_UP = parms->data->IP_UP; ipcp_ptr->IP_DOWN = parms->data->IP_DOWN; ipcp_ptr->IP_PARAM = parms->data->IP_PARAM; ipcp_ptr->INIT.ACCEPT_LOCAL_ADDR = parms->data->ACCEPT_LOCAL_ADDR; ipcp_ptr->INIT.LOCAL_ADDR = parms->data->LOCAL_ADDR; ipcp_ptr->INIT.ACCEPT_REMOTE_ADDR = parms->data->ACCEPT_REMOTE_ADDR; ipcp_ptr->INIT.REMOTE_ADDR = parms->data->REMOTE_ADDR; ipcp_ptr->INIT.DEFAULT_NETMASK = parms->data->DEFAULT_NETMASK; ipcp_ptr->INIT.NETMASK = parms->data->NETMASK; ipcp_ptr->INIT.DEFAULT_ROUTE = parms->data->DEFAULT_ROUTE; ipcp_ptr->INIT.NEG_LOCAL_DNS = parms->data->NEG_LOCAL_DNS; ipcp_ptr->INIT.ACCEPT_LOCAL_DNS = parms->data->ACCEPT_LOCAL_DNS; ipcp_ptr->INIT.LOCAL_DNS = parms->data->LOCAL_DNS; ipcp_ptr->INIT.NEG_REMOTE_DNS = parms->data->NEG_REMOTE_DNS; ipcp_ptr->INIT.ACCEPT_REMOTE_DNS = parms->data->ACCEPT_REMOTE_DNS; ipcp_ptr->INIT.REMOTE_DNS = parms->data->REMOTE_DNS; /* Start IPCP */ PPPFSM_open(&ipcp_ptr->FSM, 0); /* Open the link */ error = PPP_open(handle, 0); } /* Endif */ RTCSCMD_complete(parms, PPP_TO_RTCS_ERROR(error)); } /* Endbody */
void BOOTP_open ( TCPIP_PARM_BOOTP _PTR_ parms ) { /* Body */ IP_IF_PTR if_ptr = (IP_IF_PTR)parms->handle; BOOTP_CFG_PTR bootp = (BOOTP_CFG_PTR) &parms->config; uint_32 error; error = BOOT_open(BOOT_service); if (error) { RTCSCMD_complete(parms, error); return; } /* Endif */ if_ptr->BOOTFN = BOOTP_service; /* Pick a random transaction ID */ bootp->XID = RTCS_rand(); /* Set initial timeout */ bootp->TIMEOUT = BOOTP_TIMEOUT_MIN; bootp->SECS = 0; /* Build a BOOTREQUEST packet */ htonc(bootp->PACKET.OP, BOOTPOP_BOOTREQUEST); htonc(bootp->PACKET.HTYPE, if_ptr->DEV_TYPE); htonc(bootp->PACKET.HLEN, if_ptr->DEV_ADDRLEN); htonc(bootp->PACKET.HOPS, 0); htonl(bootp->PACKET.XID, bootp->XID); htons(bootp->PACKET.FLAGS, 0x8000); htonl(bootp->PACKET.CIADDR, INADDR_ANY); htonl(bootp->PACKET.YIADDR, INADDR_ANY); htonl(bootp->PACKET.SIADDR, INADDR_ANY); htonl(bootp->PACKET.GIADDR, INADDR_ANY); _mem_zero(bootp->PACKET.CHADDR, sizeof(bootp->PACKET.CHADDR)); _mem_copy(if_ptr->DEV_ADDR, bootp->PACKET.CHADDR, if_ptr->DEV_ADDRLEN); /* Start the retransmission timer to start sending immediately */ bootp->RESEND.TIME = 0; bootp->RESEND.EVENT = BOOTP_send; bootp->RESEND.PRIVATE = if_ptr; TCPIP_Event_add(&bootp->RESEND); if_ptr->BOOT = (pointer)parms; } /* Endbody */
void NAT_close_internal ( NAT_PARM_PTR parm_ptr /* [IN] Unused */ ) { /* Body */ NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT); uint_32 error; if (nat_cfg_ptr == NULL) { error = RTCSERR_NAT_NOT_INITIALIZED; } else { nat_cfg_ptr->NAT_EXEC = NULL; error = RTCS_OK; } RTCSCMD_complete(parm_ptr, error); } /* Endbody */
void DNAT_add_rule_internal ( DNAT_PARM_PTR dparm_ptr /* [IN] */ ) { /* Body */ NAT_CFG_STRUCT_PTR nat_cfg_ptr = RTCS_getcfg(NAT); DNAT_ELEMENT_STRUCT_PTR new_element_ptr, prev_element_ptr, next_element_ptr; if (nat_cfg_ptr == NULL) { RTCSCMD_complete(dparm_ptr, RTCSERR_NAT_NOT_INITIALIZED); return; } if (! NAT_is_private_addr(&nat_cfg_ptr->PRIVATE_NETWORKS,dparm_ptr->RULE.PRIVATE_IP)) { RTCSCMD_complete(dparm_ptr, RTCSERR_NAT_INVALID_PRIVATE_ADDRESS); return; } if (IP_is_local(NULL, dparm_ptr->RULE.PRIVATE_IP)) { RTCSCMD_complete(dparm_ptr, RTCSERR_NAT_INVALID_PRIVATE_ADDRESS); return; } prev_element_ptr = NULL; next_element_ptr = (DNAT_ELEMENT_STRUCT_PTR) _queue_head(&nat_cfg_ptr->RULE_QUEUE); while ((next_element_ptr != NULL) && (next_element_ptr->RULE.PRIORITY > dparm_ptr->RULE.PRIORITY)) { prev_element_ptr = next_element_ptr; next_element_ptr = (DNAT_ELEMENT_STRUCT_PTR) _queue_next(&nat_cfg_ptr->RULE_QUEUE, &prev_element_ptr->ELEMENT); } if (next_element_ptr != NULL) { if (next_element_ptr->RULE.PRIORITY == dparm_ptr->RULE.PRIORITY) { // A rule of the given priority exist RTCSCMD_complete(dparm_ptr, RTCSERR_NAT_DUPLICATE_PRIORITY); return; } } new_element_ptr = (DNAT_ELEMENT_STRUCT_PTR)_mem_alloc_system_zero(sizeof(DNAT_ELEMENT_STRUCT)); if (new_element_ptr == NULL) { RTCSCMD_complete(dparm_ptr, RTCSERR_OUT_OF_MEMORY); return; } /* Endif */ new_element_ptr->RULE = dparm_ptr->RULE; _queue_insert(&nat_cfg_ptr->RULE_QUEUE, &prev_element_ptr->ELEMENT, &new_element_ptr->ELEMENT); RTCSCMD_complete(dparm_ptr, RTCS_OK); }/* Endbody */
void TCP_Close_TCB ( TCB_STRUCT_PTR tcb, /* IN/OUT - TCP context */ int_32 errnum, /* IN - error code to return */ TCP_CFG_STRUCT_PTR tcp_cfg /* IN/OUT - TCP layer data */ ) { /* Body */ TCP_PARM_PTR req; SbufNode _PTR_ buf; boolean first = TRUE; /* for returning Sends */ boolean not_syn_recv = (tcb->state != SYN_RECEIVED); /* ** This prevents new packets from being queued on this TCB; ** however there might still be some queued (but only if ** there are no outstanding Receive requests). */ tcb->state = CLOSED; /* ** Cancel timers... */ (void)TCP_Timer_stop(&tcb->sndxmittq.t, tcp_cfg->qhead); (void)TCP_Timer_stop(&tcb->sndacktq.t, tcp_cfg->qhead); (void)TCP_Timer_stop(&tcb->sndtq.t, tcp_cfg->qhead); (void)TCP_Timer_stop(&tcb->rcvtq.t, tcp_cfg->qhead); /* ** Return open request if there is one. This should ** only happen if we are closing on error. */ if ( errnum != RTCS_OK && not_syn_recv) { TCP_Return_open(tcb, errnum, tcp_cfg); } /* Endif */ /* ** Terminate any Receive requests. We can't receive any more ** packets in the CLOSED state, and presence of any Receives ** means that all data that could be (contiguously) in the ** first Receive is already there (see TCP_Process_data). ** ** In this case the TCB could actually be released, but wait for ** user to close it. Don't have to delete all of the RcvChunks ** or indicate no data left in ring since a TCP_Process_close or ** TCP_Process_receive will do this. */ while ( tcb->rcvHead != NULL ) { TCP_Reply_receive(tcb, tcp_cfg, errnum); if ( tcb->rcvHead != NULL ) { TCP_Setup_receive(tcb->rcvHead, tcb, tcp_cfg); } /* Endif */ } /* Endwhile */ /* ** Terminate any Send requests */ buf = tcb->sndbuf; while ( buf != NULL ) { tcb->sndbuf = buf->next; if ( tcb->sndbuf == NULL ) { tcb->sndbuftail = NULL; } /* Endif */ req = buf->req; if ( req != NULL ) { /* report actual amount sent */ if ( first ) { req->BUFF_LENG = tcb->snduna - tcb->sndbufseq; } else { req->BUFF_LENG = 0; } /* Endif */ RTCSCMD_complete(req, errnum); } /* Endif */ first = FALSE; _mem_free(buf); buf = tcb->sndbuf; } /* Endwhile */ /* Terminate any wait request */ #if 0 req = tcb->oclient; if ( req != NULL ) { req->STATUS = tcb->status; req->SOFTERROR = tcb->lasterror; RTCSCMD_complete(req, errnum); tcb->oclient = NULL; } /* Endif */ #endif /* ** Notify socket layer in case some task is blocked on select() ** waiting for data on this socket. */ SOCK_select_signal(tcb->SOCKET, tcb->state); /* Delete send buffers (keep receive buffer in case there is * pending data) */ if ( tcb->sndringbuf != NULL ) { _mem_free(tcb->sndringbuf); } /* Endif */ tcb->sndringbuf = NULL; if ( tcb->sndclk != NULL ) { _mem_free(tcb->sndclk); /* xmit timestamps buffer */ } /* Endif */ tcb->sndclk = NULL; } /* Endbody */
// Start CR 2316 static boolean RTCSMIB_request_internal ( RTCSMIB_WALK_PTR mib ) { /* Body */ uchar_ptr inbuffer, nextvar,checkbuffer; uint_32 inbuf_length, nextlength,check_length; uint_32 varlen; boolean ok = FALSE; uint_32 index =0; uint_32 errstat =0; uint_32 error_index; mib->errstat = SNMP_ERROR_noError; switch (mib->pdutype) { case ASN1_TYPE_PDU_GET: ok = RTCSMIB_get(mib); break; case ASN1_TYPE_PDU_GETNEXT: ok = RTCSMIB_powerful_getnext(mib); break; case ASN1_TYPE_PDU_SET: inbuffer = mib->inbuf; inbuf_length = mib->inlen; checkbuffer = inbuffer; check_length = inbuf_length; error_index =0; //check first to ensure all variables in set request are valid if (check_length >= 5) /* Minmum length for a set operation is 5 */ { ASN1_READ_TYPELEN_EXPECT(mib, ASN1_TYPE_SEQUENCE, varlen); nextvar = (uchar_ptr) (mib->inbuf + varlen); nextlength = check_length - ((uint_32)(nextvar - checkbuffer)); mib->inbuf = checkbuffer; mib->inlen = check_length; mib->errstat = SNMP_ERROR_noError; ok = RTCSMIB_check(mib); index++; if(mib->errstat) { errstat = mib->errstat; error_index = index; } mib->inbuf = nextvar; checkbuffer = nextvar; mib->inlen = nextlength; check_length = nextlength; } if(error_index) //invalid variable in set request,stop set operation to all variables { mib->errstat = errstat; break; } mib->inbuf = inbuffer; mib->inlen = inbuf_length; //all variables are valid, so set beginning if (inbuf_length >= 5) /* Minmum length for a set operation is 5 */ { ASN1_READ_TYPELEN_EXPECT(mib, ASN1_TYPE_SEQUENCE, varlen); nextvar = (uchar_ptr) (mib->inbuf + varlen); nextlength = inbuf_length - ((uint_32)(nextvar - inbuffer)); mib->inbuf = inbuffer; mib->inlen = inbuf_length; ok = RTCSMIB_set(mib); mib->inbuf = nextvar; inbuffer = nextvar; mib->inlen = nextlength; inbuf_length = nextlength; } /* Endwhile */ break; } /* Endswitch */ if (!ok && !mib->errstat) { mib->errstat = SNMP_ERROR_PARSE; } /* Endif */ /* Start CR 2162 */ #ifndef TRAVERSE_MIB_IN_SNMP_TASK RTCSCMD_complete(mib, RTCS_OK); #endif /* End CR 2162 */ return (ok); } /* Endbody */
void SOCK_select ( SOCKSELECT_PARM_PTR parms ) { /* Body */ uint_32 _PTR_ socket_array; int i, i2; uint_32 fds[RTCS_SELECT_MAX_FDS]; int active = FALSE; // param check if ((parms->sock_count != 0 && parms->sock_ptr == NULL) || (parms->writesock_count != 0 && parms->writesock_ptr == NULL)) { RTCSCMD_complete(parms, RTCSERR_INVALID_PARAMETER); return; } // read fds - check every socket in the supplied array if (parms->sock_count) { _mem_zero(fds, parms->sock_count * sizeof(uint_32)); for (i = 0, i2 = 0; i < parms->sock_count; i++) { if (SOCK_select_activity((SOCKET_STRUCT_PTR)parms->sock_ptr[i], 0)) { fds[i2++] = parms->sock_ptr[i]; } } // update socket array - only active sockets if (i2) { _mem_zero(parms->sock_ptr, parms->sock_count * sizeof(uint_32)); _mem_copy(fds, parms->sock_ptr, i2 * sizeof(uint_32)); parms->sock_count = i2; parms->sock = fds[0]; active = TRUE; } } // write fds - check every socket in the supplied array if (parms->writesock_count) { _mem_zero(fds, parms->writesock_count * sizeof(uint_32)); for (i = 0, i2 = 0; i < parms->writesock_count; i++) { if (SOCK_select_activity((SOCKET_STRUCT_PTR)parms->writesock_ptr[i], 1)) { fds[i2++] = parms->writesock_ptr[i]; } } // update socket array - only active sockets if (i2) { _mem_zero(parms->writesock_ptr, parms->writesock_count * sizeof(uint_32)); _mem_copy(fds, parms->writesock_ptr, i2 * sizeof(uint_32)); parms->writesock_count = i2; if (active == FALSE) { // write fds active but read fds no - set read fds to zero _mem_zero(parms->sock_ptr, parms->sock_count * sizeof(uint_32)); parms->sock_count = 0; parms->sock = fds[0]; } active = TRUE; } else if (active == TRUE) { // read fds active but write fds no - set write fds to zero _mem_zero(parms->writesock_ptr, parms->writesock_count * sizeof(uint_32)); parms->writesock_count = 0; } } if (active == TRUE) { // some fds active RTCSCMD_complete(parms, RTCS_OK); return; } if (parms->timeout == (uint_32)-1) { parms->sock = 0; RTCSCMD_complete(parms, RTCS_OK); return; } /* Endif */ parms->owner = 0; SOCK_select_block(parms); } /* Endbody */
/*FUNCTION*------------------------------------------------------------- * * Function Name : ICMP6_send_echo * Parameters : * * _ip_address ipaddress [IN] destination IP address * uint_32 timeout [IN/OUT] timeout/rtt * uint_16 id [IN] identification for echo message. * uint_16 seq not used * * Comments : * Send an ICMP Echo Request packet. * *END*-----------------------------------------------------------------*/ void ICMP6_send_echo(ICMP_ECHO_PARAM_PTR parms) { #if RTCSCFG_ENABLE_IP6 ICMP6_CFG_STRUCT_PTR ICMP6_cfg_ptr = RTCS_getcfg(ICMP6); RTCSPCB_PTR pcb; ICMP6_ECHO_HEADER_PTR packet; _rtcs_if_handle ihandle_dest = NULL; uint_32 error; IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++); parms->seq = ICMP6_cfg_ptr->ECHO_SEQ++; pcb = RTCSPCB_alloc_send(); if (pcb == NULL) { IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); RTCSCMD_complete(parms, RTCSERR_PCB_ALLOC); return; } if(parms->ping_param->data_buffer && parms->ping_param->data_buffer_size) { error = RTCSPCB_append_fragment(pcb, parms->ping_param->data_buffer_size, parms->ping_param->data_buffer); if (error) { IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.COMMON.ST_TX_ERRORS++); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); RTCSCMD_complete(parms, error); return; } } error = RTCSPCB_insert_header(pcb, sizeof(ICMP6_ECHO_HEADER)); if (error) { IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.COMMON.ST_TX_ERRORS++); IF_ICMP6_STATS_ENABLED(RTCS_seterror(&ICMP6_cfg_ptr->STATS.ERR_TX, error, (uint_32)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); RTCSCMD_complete(parms, error); return; } RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMPV6), 0); packet = (ICMP6_ECHO_HEADER_PTR)RTCSPCB_DATA(pcb); pcb->TRANSPORT_LAYER = (uchar_ptr)packet; htonc(packet->HEAD.TYPE, ICMP6_TYPE_ECHO_REQ); htonc(packet->HEAD.CODE, 0); htons(packet->HEAD.CHECKSUM, 0); htons(packet->ID, parms->ping_param->id); htons(packet->SEQ, parms->seq); pcb->IP_SUM = IP_Sum_PCB(RTCSPCB_SIZE(pcb), pcb); pcb->IP_SUM_PTR = packet->HEAD.CHECKSUM; if(((sockaddr_in6 *)(&parms->ping_param->addr))->sin6_scope_id) { ihandle_dest = ip6_if_get_by_scope_id(((sockaddr_in6 *)(&parms->ping_param->addr))->sin6_scope_id); } parms->EXPIRE.TIME = parms->ping_param->timeout; parms->EXPIRE.EVENT = ICMP6_expire_echo; parms->EXPIRE.PRIVATE = parms; parms->start_time = RTCS_time_get(); /* get timestamp */ error = IP6_send(pcb, IPPROTO_ICMPV6|IPTTL(parms->ping_param->hop_limit), NULL/*ipsrc*/, &((sockaddr_in6 *)(&parms->ping_param->addr))->sin6_addr/*ipdest*/, ihandle_dest, 0); if (error != RTCS_OK) { IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); RTCSCMD_complete(parms, error); return; } /* ** If there is no error add the parm struct to config struct ** and initiate the event timer */ IF_ICMP6_STATS_ENABLED(ICMP6_cfg_ptr->STATS.ST_TX_ECHO_REQ++); /* add the prameter structure to ICMP cfg */ parms->NEXT = ICMP6_cfg_ptr->ECHO_PARAM_HEAD; if (parms->NEXT) { parms->NEXT->PREV = &parms->NEXT; } /* Endif */ ICMP6_cfg_ptr->ECHO_PARAM_HEAD = parms; parms->PREV = &ICMP6_cfg_ptr->ECHO_PARAM_HEAD; TCPIP_Event_add(&parms->EXPIRE); #else RTCSCMD_complete(parms, RTCSERR_IP_IS_DISABLED); #endif /* RTCSCFG_ENABLE_IP6 */ }
void ICMP_service ( RTCSPCB_PTR pcb, /* [IN/OUT] incoming packet */ void *dummy /* [IN] not used */ ) { /* Body */ ICMP_CFG_STRUCT_PTR ICMP_cfg_ptr; ICMP_HEADER_PTR packet; _ip_address source, dest; uint32_t error; uint16_t chksum; unsigned char type; #if BSPCFG_ENET_HW_TX_PROTOCOL_CHECKSUM _ip_address if_addr; IP_IF_PTR if_ptr; #endif ICMP_cfg_ptr = RTCS_getcfg(ICMP); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_TOTAL++); packet = (ICMP_HEADER_PTR)RTCSPCB_DATA(pcb); source = IP_source(pcb); dest = IP_dest(pcb); type = mqx_ntohc(packet->TYPE); /* ** Make sure that ** sizeof(ICMP_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ #if BSPCFG_ENET_HW_RX_PROTOCOL_CHECKSUM /* HW-offload.*/ if( ((pcb->TYPE & RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM)==0) #if RTCSCFG_LINKOPT_8023 ||(pcb->LINK_OPTIONS.RX.OPT_8023 == 1) #endif ) #endif { /* Verify the checksum */ if (IP_Sum_PCB(0, pcb) != 0xFFFF) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_BAD_CHECKSUM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_CHECKSUM); RTCSPCB_free(pcb); return; } } RTCSLOG_PCB_READ(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0); switch (type) { case ICMPTYPE_REDIRECT: #if RTCSCFG_ENABLE_GATEWAYS { /* Scope */ _ip_address origdest, gateway; ICMP_ERR_HEADER_PTR rdpacket = (ICMP_ERR_HEADER_PTR)packet; IPIF_PARM parms; /* ** Make sure that ** sizeof(ICMP_ERR_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_ERR_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ gateway = mqx_ntohl(rdpacket->DATA); origdest = mqx_ntohl(rdpacket->IP.DEST); /* If we receive a redirect to ourselves, silently discard it.*/ /* Ignore unasigned address.*/ if( IP_is_local(NULL, gateway) || (gateway == INADDR_ANY)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); } else if(IP_is_gate(source, origdest)) { parms.address = gateway; parms.network = origdest; parms.netmask = 0xFFFFFFFFL; parms.locmask = 0; RTCSCMD_internal(parms, IPIF_gate_add_redirect); } else { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_RD_NOTGATE++); } /* Endif */ } /* Endscope */ #else IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); #endif break; case ICMPTYPE_ECHO_REQ: /* RFC1122: An ICMP Echo Request destined to an IP broadcast or IP * multicast address MAY be silently discarded.*/ if((dest == INADDR_BROADCAST) || (IN_MULTICAST(dest) && (ip_if_is_joined(pcb->IFSRC, dest) == false)) ) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); } else { error = RTCSPCB_next(pcb, sizeof(ICMP_HEADER)); if (error) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_ERRORS++); IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_RX, error, (uint32_t)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); return; } /* Endif */ /* ** RTCSPCB_fork() failing isn't a serious error, so we don't check ** the error code */ RTCSPCB_fork(pcb); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++); RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0); error = RTCSPCB_insert_header(pcb, sizeof(ICMP_HEADER)); if (error) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_ECHO_REQ++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_TX, error, (uint32_t)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); return; } /* Change type from Echo to Echo Reply and recalculate checksum */ packet = (ICMP_HEADER_PTR)RTCSPCB_DATA(pcb); mqx_htonc(packet->TYPE, ICMPTYPE_ECHO_REPLY); mqx_htonc(packet->CODE, 0); mqx_htons(packet->CHECKSUM, 0); pcb->IP_SUM_PTR = NULL; #if BSPCFG_ENET_HW_TX_PROTOCOL_CHECKSUM /* HW-offload.*/ if_addr = IP_route_find(source /* Destination*/, 1); if_ptr = IP_find_if(if_addr); if( (if_ptr && (if_ptr->FEATURES & IP_IF_FEATURE_HW_TX_PROTOCOL_CHECKSUM) && (IP_will_fragment(if_ptr, RTCSPCB_SIZE(pcb)) == FALSE)) #if RTCSCFG_LINKOPT_8023 && (pcb->LINK_OPTIONS.TX.OPT_8023 == 0) #endif ) { pcb->TYPE |= RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM; } else #endif { chksum = IP_Sum_PCB(0, pcb); chksum = IP_Sum_invert(chksum); mqx_htons(packet->CHECKSUM, chksum); pcb->TYPE &= ~RTCSPCB_TYPE_HW_PROTOCOL_CHECKSUM; } if(IN_MULTICAST(dest) || IP_addr_is_broadcast(pcb, dest) ) { dest = IP_get_ipif_addr(pcb->IFSRC); } /* Send the Echo Reply whence came the Echo */ IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_TX_ECHO_REPLY++); IP_send(pcb, IPPROTO_ICMP, dest /* Source*/, source /* Destination*/, 0); pcb = NULL; } break; case ICMPTYPE_ECHO_REPLY: { /* Scope */ ICMP_ECHO_HEADER_PTR echopacket = (ICMP_ECHO_HEADER_PTR)packet; ICMP_ECHO_PARAM_PTR parms; uint16_t id, seq; /* ** Make sure that ** sizeof(ICMP_ECHO_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_ECHO_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ /* ** get the ID and Sequence number from the packet */ id = mqx_ntohs(echopacket->ID); seq = mqx_ntohs(echopacket->SEQ); /* ** Find a match for the ID and sequence number */ for (parms=ICMP_cfg_ptr->ECHO_PARAM_HEAD; parms; parms=parms->NEXT) { if ((parms->ping_param->id == id) && (parms->seq == seq)) { /* received reply for the ping request */ if (parms->NEXT) { parms->NEXT->PREV = parms->PREV; } *parms->PREV = parms->NEXT; TCPIP_Event_cancel(&parms->EXPIRE); /* Calculate round trip time */ parms->ping_param->round_trip_time = RTCS_timer_get_interval(parms->start_time, RTCS_time_get()); /* IP address of echo-reply message.*/ { IP_HEADER_PTR iphead = (IP_HEADER_PTR)RTCSPCB_DATA_NETWORK(pcb); memset(&parms->ping_param->addr, 0, sizeof(parms->ping_param->addr)); parms->ping_param->addr.sa_family = AF_INET; ((sockaddr_in*)(&parms->ping_param->addr))->sin_addr.s_addr = mqx_ntohl(iphead->SOURCE); } RTCSCMD_complete(parms, RTCS_OK); break; } /* Endif */ } /* Endfor */ } /* Endscope */ break; case ICMPTYPE_DESTUNREACH: case ICMPTYPE_TIMEEXCEED: { /* Scope */ IP_HEADER_PTR ip; ICMP_ERR_HEADER_PTR icmp_err = (ICMP_ERR_HEADER_PTR)packet; uint32_t len, remain; bool discard = TRUE; unsigned char code; /* ** Check if the attached IP header is IP over IP, and if so, strip IP ** headers until we find one whose source address is not local. Then we ** forward the ICMP error to that IP address */ remain = RTCSPCB_SIZE(pcb); /* Make sure we have at least a full IP header */ if (remain >= sizeof(ICMP_HEADER) + 4 + sizeof(IP_HEADER)) { ip = (IP_HEADER_PTR)((unsigned char *)packet + sizeof(ICMP_HEADER) + 4); remain -= sizeof(ICMP_HEADER) + 4; do { /* Make sure the IP header is IP over IP */ if (mqx_ntohc(ip->PROTOCOL) != IPPROTO_IPIP) { break; } /* Endif */ /* Make sure we have a full IP header + 8 bytes */ len = (mqx_ntohc(ip->VERSLEN) & 0x0F) << 2; if (remain < len + sizeof(IP_HEADER)) { break; } /* Endif */ /* Get next header */ ip = (IP_HEADER_PTR)((unsigned char *)(ip) + len); remain -= len; source = mqx_ntohl(ip->SOURCE); discard = IP_is_local(NULL, source); } while(discard); len = (mqx_ntohc(ip->VERSLEN) & 0x0F) << 2; /* ** discard is true if we are the originator of the IP packet ** in error, or if there was not enough information to find the ** originator. We make sure discard is false, and there is at ** least a full IP header + 8 bytes of data left */ if (!discard && (len + 8 <= remain)) { if (type == ICMPTYPE_DESTUNREACH) { code = mqx_ntohc(packet->CODE); switch (code) { case ICMPCODE_DU_PROTO_UNREACH: /* ** If we are sending back to the originator, and the ** originator did not use IP over IP, the protocol ** unreachable error is useless. */ code = ICMPCODE_DU_NET_UNREACH; break; case ICMPCODE_DU_PORT_UNREACH: /* It doesn't make sense to receive this */ discard = TRUE; break; case ICMPCODE_DU_SRCROUTE: discard = TRUE; break; } /* Endswitch */ } else { /* ** Type is ICMPTYPE_TIMEEXCEED ** ** Problem with routing loops within tunnel. Originator ** does not need to know about tunnel. */ type = ICMPTYPE_DESTUNREACH; code = ICMPCODE_DU_HOST_UNREACH; } /* Endif */ if (!discard) { ICMP_send_error_internal(type, code, mqx_ntohl(icmp_err->DATA), ip, NULL, remain); } /* Endif */ } /* Endif */ } /* Endif */ } /* Endscope */ break; } /* End Switch */ #if RTCSCFG_ENABLE_ICMP_STATS /* Update the statistics */ switch (type) { case ICMPTYPE_DESTUNREACH: ICMP_cfg_ptr->STATS.ST_RX_DESTUNREACH++; break; case ICMPTYPE_TIMEEXCEED: ICMP_cfg_ptr->STATS.ST_RX_TIMEEXCEED++; break; case ICMPTYPE_PARMPROB: ICMP_cfg_ptr->STATS.ST_RX_PARMPROB++; break; case ICMPTYPE_SRCQUENCH: ICMP_cfg_ptr->STATS.ST_RX_SRCQUENCH++; break; case ICMPTYPE_REDIRECT: ICMP_cfg_ptr->STATS.ST_RX_REDIRECT++; break; case ICMPTYPE_ECHO_REQ: ICMP_cfg_ptr->STATS.ST_RX_ECHO_REQ++; break; case ICMPTYPE_ECHO_REPLY: ICMP_cfg_ptr->STATS.ST_RX_ECHO_REPLY++; break; case ICMPTYPE_TIME_REQ: ICMP_cfg_ptr->STATS.ST_RX_TIME_REQ++; break; case ICMPTYPE_TIME_REPLY: ICMP_cfg_ptr->STATS.ST_RX_TIME_REPLY++; break; case ICMPTYPE_INFO_REQ: ICMP_cfg_ptr->STATS.ST_RX_INFO_REQ++; break; case ICMPTYPE_INFO_REPLY: ICMP_cfg_ptr->STATS.ST_RX_INFO_REPLY++; break; default: ICMP_cfg_ptr->STATS.ST_RX_OTHER++; ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++; break; } /* Endswitch */ #endif if (pcb) { RTCSLOG_PCB_FREE(pcb, RTCS_OK); RTCSPCB_free(pcb); } /* Endif */ } /* Endbody */
void TCP_Process_abort ( TCP_PARM_PTR req_ptr /* IN/OUT - the open request */ ) { /* Body */ TCP_CFG_STRUCT_PTR tcp_cfg; TCB_STRUCT_PTR tcb; int_32 reply = RTCS_OK; tcp_cfg = RTCS_getcfg(TCP); tcb = req_ptr->TCB_PTR; if ( tcb == NULL ) { RTCSCMD_complete(req_ptr, RTCSERR_TCP_CONN_RLSD); return; } IF_TCP_STATS_ENABLED(tcp_cfg->STATS.ST_CONN_ABORTS++); if ( tcb->VALID != TCB_VALID_ID ) { reply = RTCSERR_TCP_CONN_RLSD; } else { switch ( tcb->state ) { case LISTEN: /* ** allows for shutdown of listening socket with ABORT option set. */ TCP_Close_TCB(tcb, RTCS_OK, tcp_cfg); TCP_Process_release(tcb, tcp_cfg); break; case SYN_RECEIVED: case ESTABLISHED: case FINWAIT_1: case FINWAIT_2: case CLOSE_WAIT: TCP_Send_reset(tcb, tcp_cfg); /* send reset packet */ /*FALLTHROUGH*/ case SYN_SENT: case CLOSING: case LAST_ACK: case TIME_WAIT: TCP_Close_TCB(tcb, RTCSERR_TCP_CONN_ABORTED, tcp_cfg); /*FALLTHROUGH*/ case BOUND: case CLOSED: TCP_Process_release(tcb, tcp_cfg); break; default: reply = RTCSERR_TCP_NOT_CONN; break; } /* End Switch */ } /* Endif */ /* The socket will be freed as soon as we return to shutdown() */ if (tcb->VALID == TCB_VALID_ID) { /* Following code no longer needed, as the option is propagated to the TCB when set */ tcb->SOCKET = 0; } /* Endif */ RTCSCMD_complete(req_ptr, reply); } /* Endbody */
void BOOTP_service ( RTCSPCB_PTR rtcs_pcb /* [IN] BOOTREPLY packet */ ) { /* Body */ IP_IF_PTR if_ptr = (IP_IF_PTR)rtcs_pcb->IFSRC; TCPIP_PARM_BOOTP _PTR_ parms = (TCPIP_PARM_BOOTP _PTR_)if_ptr->BOOT; BOOTP_CFG_PTR bootp = (BOOTP_CFG_PTR) &parms->config; BOOTP_PACKET_PTR bootreply; IPIF_PARM parms_bind; uint_32 error; uchar_ptr opt; uchar len, optval, optlen; /* Make sure the datagram is large enough */ bootreply = (BOOTP_PACKET_PTR)RTCSPCB_DATA(rtcs_pcb); if (RTCSPCB_SIZE(rtcs_pcb) < sizeof(BOOTP_PACKET)) { RTCSLOG_PCB_FREE(rtcs_pcb, RTCS_OK); RTCSPCB_free(rtcs_pcb); return; } /* Endif */ /* Make sure the XID matches */ if (ntohl(bootreply->HEAD.XID) != bootp->XID) { RTCSLOG_PCB_FREE(rtcs_pcb, RTCS_OK); RTCSPCB_free(rtcs_pcb); return; } /* Endif */ RTCSLOG_PCB_READ(rtcs_pcb, RTCS_LOGCTRL_PORT(IPPORT_BOOTPC), 0); /* OK, assume this reply is for us */ BOOTP_close(if_ptr); /* Get our IP address, and pick the default netmask */ parms_bind.ihandle = if_ptr; parms_bind.address = ntohl(bootreply->HEAD.YIADDR); parms_bind.locmask = 0xFFFFFFFFL; parms_bind.netmask = IN_DEFAULT_NET(parms_bind.address); parms_bind.probe = FALSE; parms->data->SADDR = ntohl(bootreply->HEAD.SIADDR); #if RTCSCFG_BOOTP_RETURN_YIADDR parms->data->CLIENTADDR = ntohl(bootreply->HEAD.YIADDR); #endif _mem_copy(bootreply->DATA.SNAME, parms->data->SNAME, sizeof(BOOTP_DATA)); RTCSLOG_PCB_FREE(rtcs_pcb, RTCS_OK); RTCSPCB_free(rtcs_pcb); /* Parse the vend field for recognized options */ opt = parms->data->OPTIONS; len = sizeof(parms->data->OPTIONS); if (ntohl(opt) == BOOTP_MAGIC) { opt += 4; len -= 4; #define BOOTP_NEXTOPT opt += optlen; \ break while (len) { /* Get the next option code */ optval = ntohc(opt); opt++; len--; /* Interpret the pad and end options */ if (optval == BOOTPOPT_END) break; if (optval == BOOTPOPT_PAD) continue; /* All other codes have a length byte */ if (len == 0) break; optlen = ntohc(opt); opt++; len--; if (len < optlen) break; len -= optlen; switch (optval) { case BOOTPOPT_MASK: if (optlen != 4) {BOOTP_NEXTOPT;} parms_bind.netmask = ntohl(opt); opt += 4; break; default: BOOTP_NEXTOPT; } /* Endswitch */ } /* Endwhile */ } /* Endif */ /* Bind the received IP address to this interface */ error = RTCSCMD_internal(parms_bind, IPIF_bind); /* Done -- unblock the application */ RTCSCMD_complete(parms, error); } /* Endbody */
void TCP_Process_close ( TCP_PARM_PTR req_ptr /* IN/OUT - the open request */ ) { /* Body */ TCP_CFG_STRUCT_PTR tcp_cfg; TCB_STRUCT_PTR tcb; int_32 reply = RTCS_OK; tcp_cfg = RTCS_getcfg(TCP); tcb = req_ptr->TCB_PTR; if ( tcb == NULL ) { RTCSCMD_complete(req_ptr, RTCSERR_TCP_CONN_RLSD); return; } IF_TCP_STATS_ENABLED(tcp_cfg->STATS.ST_CONN_CLOSED++); if ( tcb->VALID != TCB_VALID_ID ) { reply = RTCSERR_TCP_CONN_RLSD; RTCS_log_error( ERROR_TCP, RTCSERR_TCP_BAD_STATE_FOR_CLOSE, (uint_32)tcb, (uint_32)tcb->state, 1 ); } else if ( tcb->state == CLOSED ) { /* This should be the standard case if the other side aborted. */ TCP_Process_release(tcb, tcp_cfg); } else if ( (tcb->status & TCPS_FINTOSEND) != 0 ) { /* Upper layer must have already given us a tcpCLOSE, so we * can generate an error here. */ reply = RTCSERR_TCP_CONN_CLOSING; } else { switch ( tcb->state ) { case LISTEN: case SYN_SENT: TCP_Close_TCB(tcb, RTCS_OK, tcp_cfg); case BOUND: TCP_Process_release(tcb, tcp_cfg); break; case SYN_RECEIVED: /* no data has been sent */ case ESTABLISHED: case CLOSE_WAIT: TCP_Event(tcb,TCPS_FINTOSEND); /* We can only effectively close if all data has been sent, * allowing us to send a FIN immediately; otherwise closing * is delayed (TCPS_FINTOSEND indicates that connection should * be closed as soon as all data is sent) */ if ( tcb->sndnxt == (tcb->sndbufseq + tcb->sndlen) ) { TCP_Process_effective_close(tcb, tcp_cfg); } else { /* ** Have to kick ourselves into sending the outstanding ** data or we'll sit here forever if the other side is ** just waiting. This would happen if we send w/o PUSH ** just before closing. */ TCP_Must_send_ack(tcb, tcp_cfg); } /* Endif */ break; default: /* we shouldn't reach here, but jic... */ RTCS_log_error( ERROR_TCP, RTCSERR_TCP_BAD_STATE_FOR_CLOSE, (uint_32)tcb, (uint_32)tcb->state, 2); reply = RTCSERR_TCP_NOT_CONN; break; } /* End Switch */ } /* Endif */ /* The socket will be freed as soon as we return to shutdown() */ if (tcb->VALID == TCB_VALID_ID) { tcb->SOCKET = 0; } /* Endif */ RTCSCMD_complete(req_ptr, reply); } /* Endbody */
void ICMP_service ( RTCSPCB_PTR pcb, /* [IN/OUT] incoming packet */ pointer dummy /* [IN] not used */ ) { /* Body */ ICMP_CFG_STRUCT_PTR ICMP_cfg_ptr; ICMP_HEADER_PTR packet; _ip_address source, dest; uint_32 error; uint_16 chksum; uchar type; ICMP_cfg_ptr = RTCS_getcfg(ICMP); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_TOTAL++); packet = (ICMP_HEADER_PTR)RTCSPCB_DATA(pcb); source = IP_source(pcb); dest = IP_dest(pcb); type = ntohc(packet->TYPE); /* ** Make sure that ** sizeof(ICMP_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ /* ** Verify the checksum */ if (IP_Sum_PCB(0, pcb) != 0xFFFF) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_BAD_CHECKSUM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_CHECKSUM); RTCSPCB_free(pcb); return; } /* Endif */ RTCSLOG_PCB_READ(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0); switch (type) { case ICMPTYPE_REDIRECT: #if RTCSCFG_ENABLE_GATEWAYS { /* Scope */ _ip_address origdest, gateway; ICMP_ERR_HEADER_PTR rdpacket = (ICMP_ERR_HEADER_PTR)packet; IPIF_PARM parms; /* ** Make sure that ** sizeof(ICMP_ERR_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_ERR_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ gateway = ntohl(rdpacket->DATA); origdest = ntohl(rdpacket->IP.DEST); // If we receive a redirect to ourselves, silently discard it if (IP_is_local(NULL, gateway)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); // Might want to add a counter here } else if (IP_is_gate(source, origdest)) { parms.address = gateway; parms.network = origdest; parms.netmask = 0xFFFFFFFFL; parms.locmask = 0; RTCSCMD_internal(parms, IPIF_gate_add_redirect); } else { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_RD_NOTGATE++); } /* Endif */ } /* Endscope */ #else IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); #endif break; case ICMPTYPE_ECHO_REQ: error = RTCSPCB_next(pcb, sizeof(ICMP_HEADER)); if (error) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_ERRORS++); IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_RX, error, (uint_32)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); return; } /* Endif */ /* ** RTCSPCB_fork() failing isn't a serious error, so we don't check ** the error code */ RTCSPCB_fork(pcb); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++); RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_ICMP), 0); error = RTCSPCB_insert_header(pcb, sizeof(ICMP_HEADER)); if (error) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_ECHO_REQ++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); IF_ICMP_STATS_ENABLED(RTCS_seterror(&ICMP_cfg_ptr->STATS.ERR_TX, error, (uint_32)pcb)); RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); return; } /* Endif */ /* Change type from Echo to Echo Reply and recalculate checksum */ packet = (ICMP_HEADER_PTR)RTCSPCB_DATA(pcb); htonc(packet->TYPE, ICMPTYPE_ECHO_REPLY); htonc(packet->CODE, 0); htons(packet->CHECKSUM, 0); chksum = IP_Sum_PCB(0, pcb); chksum = IP_Sum_invert(chksum); htons(packet->CHECKSUM, chksum); pcb->IP_SUM_PTR = NULL; /* Send the Echo Reply whence came the Echo */ IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_TX_ECHO_REPLY++); IP_send(pcb, IPPROTO_ICMP, dest, source, 0); pcb = NULL; break; case ICMPTYPE_ECHO_REPLY: { /* Scope */ ICMP_ECHO_HEADER_PTR echopacket = (ICMP_ECHO_HEADER_PTR)packet; ICMP_PARM_PTR parms; uint_16 id, seq; /* ** Make sure that ** sizeof(ICMP_ECHO_HEADER) <= RTCSPCB_SIZE(pcb) */ if (RTCSPCB_SIZE(pcb) < sizeof(ICMP_ECHO_HEADER)) { IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++); IF_ICMP_STATS_ENABLED(ICMP_cfg_ptr->STATS.ST_RX_SMALL_DGRAM++); RTCSLOG_PCB_FREE(pcb, RTCSERR_ICMP_BAD_HEADER); RTCSPCB_free(pcb); return; } /* Endif */ /* ** get the ID and Sequence number from the packet */ id = ntohs(echopacket->ID); seq = ntohs(echopacket->SEQ); /* ** Find a match for the ID and sequence number */ for (parms=ICMP_cfg_ptr->ECHO_PARM_HEAD; parms; parms=parms->NEXT) { if ((parms->id == id) && (parms->seq == seq)) { /* received reply for the ping request */ if (parms->NEXT) { parms->NEXT->PREV = parms->PREV; } /* Endif */ *parms->PREV = parms->NEXT; TCPIP_Event_cancel(&parms->EXPIRE); /* calculate round trip time */ parms->timeout = RTCS_timer_get_interval(parms->timeout, RTCS_time_get()); RTCSCMD_complete(parms, RTCS_OK); break; } /* Endif */ } /* Endfor */ } /* Endscope */ break; case ICMPTYPE_DESTUNREACH: case ICMPTYPE_TIMEEXCEED: { /* Scope */ IP_HEADER_PTR ip; ICMP_ERR_HEADER_PTR icmp_err = (ICMP_ERR_HEADER_PTR)packet; uint_32 len, remain; boolean discard = TRUE; uchar code; /* ** Check if the attached IP header is IP over IP, and if so, strip IP ** headers until we find one whose source address is not local. Then we ** forward the ICMP error to that IP address */ remain = RTCSPCB_SIZE(pcb); /* Make sure we have at least a full IP header */ if (remain >= sizeof(ICMP_HEADER) + 4 + sizeof(IP_HEADER)) { ip = (IP_HEADER_PTR)((uchar_ptr)packet + sizeof(ICMP_HEADER) + 4); remain -= sizeof(ICMP_HEADER) + 4; do { /* Make sure the IP header is IP over IP */ if (ntohc(ip->PROTOCOL) != IPPROTO_IPIP) { break; } /* Endif */ /* Make sure we have a full IP header + 8 bytes */ len = (ntohc(ip->VERSLEN) & 0x0F) << 2; if (remain < len + sizeof(IP_HEADER)) { break; } /* Endif */ /* Get next header */ ip = (IP_HEADER_PTR)((uchar_ptr)(ip) + len); remain -= len; source = ntohl(ip->SOURCE); discard = IP_is_local(NULL, source); } while(discard); len = (ntohc(ip->VERSLEN) & 0x0F) << 2; /* ** discard is true if we are the originator of the IP packet ** in error, or if there was not enough information to find the ** originator. We make sure discard is false, and there is at ** least a full IP header + 8 bytes of data left */ if (!discard && (len + 8 <= remain)) { if (type == ICMPTYPE_DESTUNREACH) { code = ntohc(packet->CODE); switch (code) { case ICMPCODE_DU_PROTO_UNREACH: /* ** If we are sending back to the originator, and the ** originator did not use IP over IP, the protocol ** unreachable error is useless. */ code = ICMPCODE_DU_NET_UNREACH; break; case ICMPCODE_DU_PORT_UNREACH: /* It doesn't make sense to receive this */ discard = TRUE; break; case ICMPCODE_DU_SRCROUTE: discard = TRUE; break; } /* Endswitch */ } else { /* ** Type is ICMPTYPE_TIMEEXCEED ** ** Problem with routing loops within tunnel. Originator ** does not need to know about tunnel. */ type = ICMPTYPE_DESTUNREACH; code = ICMPCODE_DU_HOST_UNREACH; } /* Endif */ if (!discard) { ICMP_send_error_internal(type, code, ntohl(icmp_err->DATA), ip, NULL, remain); } /* Endif */ } /* Endif */ } /* Endif */ } /* Endscope */ break; } /* End Switch */ #if RTCSCFG_ENABLE_ICMP_STATS /* Update the statistics */ switch (type) { case ICMPTYPE_DESTUNREACH: ICMP_cfg_ptr->STATS.ST_RX_DESTUNREACH++; break; case ICMPTYPE_TIMEEXCEED: ICMP_cfg_ptr->STATS.ST_RX_TIMEEXCEED++; break; case ICMPTYPE_PARMPROB: ICMP_cfg_ptr->STATS.ST_RX_PARMPROB++; break; case ICMPTYPE_SRCQUENCH: ICMP_cfg_ptr->STATS.ST_RX_SRCQUENCH++; break; case ICMPTYPE_REDIRECT: ICMP_cfg_ptr->STATS.ST_RX_REDIRECT++; break; case ICMPTYPE_ECHO_REQ: ICMP_cfg_ptr->STATS.ST_RX_ECHO_REQ++; break; case ICMPTYPE_ECHO_REPLY: ICMP_cfg_ptr->STATS.ST_RX_ECHO_REPLY++; break; case ICMPTYPE_TIME_REQ: ICMP_cfg_ptr->STATS.ST_RX_TIME_REQ++; break; case ICMPTYPE_TIME_REPLY: ICMP_cfg_ptr->STATS.ST_RX_TIME_REPLY++; break; case ICMPTYPE_INFO_REQ: ICMP_cfg_ptr->STATS.ST_RX_INFO_REQ++; break; case ICMPTYPE_INFO_REPLY: ICMP_cfg_ptr->STATS.ST_RX_INFO_REPLY++; break; default: ICMP_cfg_ptr->STATS.ST_RX_OTHER++; ICMP_cfg_ptr->STATS.COMMON.ST_RX_DISCARDED++; break; } /* Endswitch */ #endif if (pcb) { RTCSLOG_PCB_FREE(pcb, RTCS_OK); RTCSPCB_free(pcb); } /* Endif */ } /* Endbody */