/* ** Function used to init session structure ** ** IN: ** FTPSRV_SESSION_STRUCT* session - session structure pointer ** FTPSRV_STRUCT *server - pointer to server structure (needed for session parameters) ** const int sock - socket handle used for communication with client ** ** OUT: ** none ** ** Return Value: ** none */ static void ftpsrv_ses_init(FTPSRV_STRUCT *server, FTPSRV_SESSION_STRUCT *session, const int sock) { if (server && session) { /* Some buffer of arbitrary size so we can get filesystem pointer */ char dev_name[16] = {0}; /* Init session structure */ session->control_sock = sock; session->connected = TRUE; session->auth_tbl = server->params.auth_table; session->root_dir = (char*) server->params.root_dir; session->cur_dir = RTCS_mem_alloc_zero(sizeof("\\")); session->cur_dir[0] = '\\'; session->start_time = RTCS_time_get(); _io_get_dev_for_path(dev_name, NULL, 16, session->root_dir, NULL); session->fs_ptr = _io_get_fs_by_name(dev_name); session->msg_queue = RTCS_mem_alloc_zero(sizeof(LWMSGQ_STRUCT) + FTPSRV_NUM_MESSAGES*sizeof(FTPSRV_TRANSFER_MSG)*sizeof(_mqx_max_type)); if (session->msg_queue != NULL) { _lwmsgq_init(session->msg_queue, FTPSRV_NUM_MESSAGES, sizeof(FTPSRV_TRANSFER_MSG)/sizeof(_mqx_max_type)); } } }
/* ** Read data from client to CGI script ** ** IN: ** uint32_t ses_handle - handle to session used for reading ** char* buffer - user buffer to read data to ** uint32_t length - size of buffer in bytes ** ** OUT: ** none ** ** Return Value: ** uint32_t - Number of bytes read */ uint32_t HTTPSRV_cgi_read(uint32_t ses_handle, char* buffer, uint32_t length) { HTTPSRV_SESSION_STRUCT* session = (HTTPSRV_SESSION_STRUCT*) ses_handle; uint32_t retval; if ( (session == NULL) || (buffer == NULL) || (length == 0) ) { return(0); } retval = httpsrv_read(session, buffer, length); if (retval > 0) { RTCS_ASSERT(retval <= session->request.content_length); if (retval <= session->request.content_length) { session->request.content_length -= retval; } } else { if (RTCS_geterror(session->sock) == RTCSERR_TCP_TIMED_OUT) { retval = 0; } } session->time = RTCS_time_get(); return(retval); }
static void IGMP_rcv_query ( IP_IF_PTR ipif, /* [IN] the interface which receive the report */ _ip_address group_ip, /* [IN] the ip address of the multicast group */ uint32_t max_resp_time /* [IN] the maximum response time of the query */ ) { /* Body */ MC_MEMBER_PTR member; /* sanity check */ if (IN_LOCAL_MULTICAST(group_ip)) { return; } /* Endif */ #ifndef IGMP_V2 max_resp_time = 0; /* force a IGMP_V1 report */ #endif /* test if it is a IGMPv1 query */ if (max_resp_time == 0) { max_resp_time = IGMP_V1_QUERY_RESPONSE_INTERVAL; #ifdef IGMP_V2 /* set the time out */ ipif->IGMP_V1_ROUTER_FLAG = TRUE; ipif->IGMP_V1_ROUTER_TIMEOUT = RTCS_time_get() + IGMP_V1_ROUTER_TIMEOUT_VALUE; #endif /* IGMP_V2 */ group_ip = 0; /* with IGMPv1, an query is always general (never group-specific) */ } else { /* convert IGMP_UNIT (1/10 sec) into the local unit (1/1000 sec) */ max_resp_time = max_resp_time * (1000/10); } /* Endif */ /* test if the group is already joined */ for (member = ipif->IGMP_MEMBER ; member ; member = member->NEXT) { /* filter the suitable member(s) */ if (group_ip && group_ip != member->IGRP.imr_multiaddr.s_addr) { continue; } /* Endif */ /* never report a local group */ if (IN_LOCAL_MULTICAST(member->IGRP.imr_multiaddr.s_addr)) { continue; } /* Endif */ if (member->RUNNING_TIMER) { /* if a timer is running, check if the timer must be relaunched */ if (TCPIP_Event_expire(&member->TIMER) > max_resp_time) { IGMP_stop_timer(member); IGMP_launch_timer(member, RTCS_rand() % max_resp_time); } /* Endif */ } else { IGMP_init_timer(member); IGMP_launch_timer(member, RTCS_rand() % max_resp_time); } /* Endif */ } /* Endfor */ } /* Endbody */
uint_32 TFTP_timeout_restart ( TFTP_TO_STRUCT_PTR to ) { /* Body */ to->TS = RTCS_time_get(); to->UPDATE = FALSE; return to->TO; } /* Endbody */
uint_32 TFTP_timeout_init ( TFTP_TO_STRUCT_PTR to ) { /* Body */ to->TS = RTCS_time_get(); to->UPDATE = TRUE; to->TO = TFTP_TIMEOUT_MIN; to->M = TFTP_TIMEOUT_MIN; to->D = 0; return to->TO; } /* Endbody */
uint_32 TFTP_timeout_update ( TFTP_TO_STRUCT_PTR to ) { /* Body */ uint_32 time, time_elapsed; int_32 error; time = RTCS_time_get(); if (to->UPDATE) { time_elapsed = time - to->TS; error = time_elapsed - to->M; to->M += error >> 3; if (!to->M) to->M++; if (error < 0) error = -error; error -= to->D; to->D += error >> 2; if (!to->D) to->D++; to->TO = to->M + (to->D << 2); } /* Endif */
void TCP_half_open_TCB_close ( TCP_CFG_STRUCT_PTR tcp_cfg /* IN/OUT - TCP layer data */ ) { /* Body */ TCB_STRUCT_PTR tcb; uint_32 curr_time; uint_32 removed_tcb_count = 0; int i; curr_time = RTCS_time_get(); /* ** Delete all the TCBs older than the default retransmission ** timeout (3 seconds). */ for (i = 0; i < tcp_cfg->HALF_OPEN_TCB_COUNT; i++) { tcb = tcp_cfg->HALF_OPEN_TCB_LIST[i]; if ((curr_time - tcb->tcb_spawn_time) > TCP_INITIAL_RTO_DEFAULT) { TCP_Send_reset(tcb, tcp_cfg); /* send reset packet */ TCP_Close_TCB(tcb, RTCSERR_TCP_CONN_ABORTED, tcp_cfg); TCP_Process_release(tcb, tcp_cfg); i--; /* we removed a TCB and replaced another TCB from the end, so we need to check same spot again */ removed_tcb_count++; } /* Endif */ } /* Endfor */ /* ** Remove one TCB from the half open list randomly. Remove the TCB ** with a reset. If this is not an attack the client will resend the SYN. */ if (!removed_tcb_count && tcp_cfg->HALF_OPEN_TCB_COUNT) { i = RTCS_rand() % tcp_cfg->HALF_OPEN_TCB_COUNT; tcb = tcp_cfg->HALF_OPEN_TCB_LIST[i]; TCP_Send_reset(tcb, tcp_cfg); /* send reset packet */ TCP_Close_TCB(tcb, RTCSERR_TCP_CONN_ABORTED, tcp_cfg); TCP_Process_release(tcb, tcp_cfg); } /* Endif */ } /* Endbody */
void NAT_event_tick ( TCPIP_EVENT_PTR tcpip_event_ptr, /* [IN] Controlling event */ boolean force /* [IN] Force expiry of first event */ ) { /* Body */ NAT_EVENT_HEAD_PTR nat_event_head_ptr = tcpip_event_ptr->PRIVATE; uint_32 msec, elapsed; msec = RTCS_time_get(); if (nat_event_head_ptr->FIRST) { if (force) { elapsed = nat_event_head_ptr->FIRST->TIME; } else { elapsed = RTCS_timer_get_interval(nat_event_head_ptr->TIMESTAMP, msec); } /* Endif */ if (nat_event_head_ptr->FIRST->TIME <= elapsed) { nat_event_head_ptr->FIRST->TIME = 0; } else { nat_event_head_ptr->FIRST->TIME -= elapsed; } /* Endif */ if (nat_event_head_ptr->TIMEDELTA <= elapsed) { nat_event_head_ptr->TIMEDELTA = 0; } else { nat_event_head_ptr->TIMEDELTA -= elapsed; } /* Endif */ } /* Endif */ nat_event_head_ptr->TIMESTAMP = msec; } /* Endbody */
/* ** Write data to client from CGI script ** ** IN: ** HTTPSRV_CGI_RES_STRUCT* response - CGI response structure used for forming response ** ** OUT: ** none ** ** Return Value: ** uint_32 - Number of bytes written */ uint32_t HTTPSRV_cgi_write(HTTPSRV_CGI_RES_STRUCT* response) { HTTPSRV_SESSION_STRUCT* session = (HTTPSRV_SESSION_STRUCT*) response->ses_handle; uint32_t retval = 0; int32_t wrote; if (session == NULL) { return(0); } if (!(session->flags & HTTPSRV_FLAG_HEADER_SENT)) { session->response.status_code = response->status_code; session->response.content_type = response->content_type; session->response.length = response->content_length; if (response->content_length < 0) { session->flags |= HTTPSRV_FLAG_IS_TRANSCODED; } /* * Ignore rest of received data in buffer (set buffer offset to zero). * We do this because otherwise any buffered but unread data would be * part of response (before header) and render it invalid. */ if (session->buffer.offset <= session->request.content_length) { session->request.content_length -= session->buffer.offset; } session->buffer.offset = 0; httpsrv_sendhdr(session, response->content_length, 1); } if (session->flags & HTTPSRV_FLAG_IS_TRANSCODED) { char length_str[sizeof("FFFFFFFF\r\n")] = {0}; /* Write length. */ snprintf(length_str, sizeof(length_str), "%x\r\n", response->data_length); wrote = httpsrv_write(session, length_str, strlen(length_str)); if (wrote < 0) { retval = 0; goto EXIT; } /* Write data. */ wrote = httpsrv_write(session, response->data, response->data_length); if (wrote < 0) { retval = 0; goto EXIT; } retval = wrote; /* Write tail. */ wrote = httpsrv_write(session, "\r\n", strlen("\r\n")); if (wrote < 0) { retval = 0; goto EXIT; } } else if ((response->data != NULL) && (response->data_length > 0)) { retval = httpsrv_write(session, response->data, response->data_length); } EXIT: session->time = RTCS_time_get(); return(retval); }
bool IGMP_send_report ( ip_mreq *igrp, uint16_t type ) { /* Body */ IGMP_CFG_STRUCT_PTR IGMP_cfg_ptr = RTCS_getcfg(IGMP); uint32_t error; uint16_t checksum; RTCSPCB_PTR pcb; IGMP_HEADER_PTR header; IP_IF_PTR ipif; _ip_address ipdst; IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_TOTAL++); /* never send a report for the local groups */ if (IN_LOCAL_MULTICAST(igrp->imr_multiaddr.s_addr)) { return TRUE; } /* Endif */ /* get the interface with its ip address */ ipif = IP_find_if(igrp->imr_interface.s_addr); if (ipif == NULL) { IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); return FALSE; } /* Endif */ pcb = RTCSPCB_alloc_send(); if (pcb == NULL) { IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); return FALSE; } /* Endif */ //RTCSLOG_PCB_ALLOC(pcb); error = RTCSPCB_insert_header(pcb, sizeof(IGMP_HEADER)); if (error) { RTCSLOG_PCB_FREE(pcb, error); RTCSPCB_free(pcb); IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.COMMON.ST_TX_MISSED++); return FALSE; } /* Endif */ RTCSLOG_PCB_WRITE(pcb, RTCS_LOGCTRL_PROTO(IPPROTO_IGMP), 1); #ifdef IGMP_V2 /* check if routers igmpv1 are present or not */ if (type == IGMPTYPE_V2_REPORT && ipif->IGMP_V1_ROUTER_FLAG) { uint32_t curTime = RTCS_time_get(); /* WORK: handle the overflow (see tcp seq) */ if (curTime < ipif->IGMP_V1_ROUTER_TIMEOUT) { type = IGMPTYPE_V1_REPORT; } else { /* if the timeout expired, clear the flag */ ipif->IGMP_V1_ROUTER_FLAG = 0; } /* Endif */ } /* Endif */ #endif /* IGMP_V2 */ /* build the igmp packet */ header = (IGMP_HEADER_PTR)RTCSPCB_DATA(pcb); mqx_htonc(header->TYPE, type); mqx_htonc(header->MAX_RESP_TIME, 0); mqx_htons(header->CHECKSUM, 0); mqx_htonl(header->GROUP_ADDRESS, igrp->imr_multiaddr.s_addr); checksum = _mem_sum_ip(0, sizeof(IGMP_HEADER), header); checksum = IP_Sum_invert(checksum); mqx_htons(header->CHECKSUM, checksum); /* WORK: for IGMP_V2, add a router alert option but currently ip layer doesnt support ip options */ /* send the igmp packet */ ipdst = igrp->imr_multiaddr.s_addr; #ifdef IGMP_V2 if (type == IGMPTYPE_LEAVE) { ipdst = INADDR_ALLROUTERS_GROUP; } /* Endif */ #endif IF_IGMP_STATS_ENABLED(IGMP_cfg_ptr->STATS.ST_TX_REPORT++); /* WORK: not always true for IGMP_V2 */ error = IP_send(pcb, IPPROTO_IGMP | IPTTL(1), igrp->imr_interface.s_addr, ipdst, RTCS_MSG_NOLOOP); return TRUE; } /* Endbody */
void PPP_tx_task ( void *handle, /* [IN] - the PPP state structure */ void *creator /* [IN] - the creation information */ ) { /* Body */ #if RTCSCFG_ENABLE_IP4 PPP_CFG_PTR ppp_ptr = handle; uint32_t ctrl; bool state; PPP_OPT opt; PCB_PTR pcb; uint32_t pcbopt; PPP_MESSAGE_PTR message, xmithead, * xmitnode; uint32_t timebefore, timeafter; bool wait; int32_t timeout; uint16_t protocol; _queue_id queue; void *param; /* Obtain a message queue so that PPP_send() can reach us */ queue = RTCS_msgq_open(0, 0); if (queue == 0) { RTCS_task_exit(creator, RTCSERR_PPP_OPEN_QUEUE_FAILED); } /* Endif */ RTCS_task_resume_creator(creator, PPP_OK); ppp_ptr->MSG_QUEUE = queue; xmithead = NULL; timebefore = RTCS_time_get(); #define PPPTX_DISCARD(msg) \ (msg)->PCB->FREE = (msg)->ORIG_FREE; \ PCB_free((msg)->PCB); \ RTCS_msg_free(msg) for(;;) { /********************************************************** ** ** Wait for a packet to send ** */ wait = TRUE; timeout = 0; /* Check if a packet is waiting for retransmission */ if (xmithead) { /* Measure elapsed time */ timeafter = RTCS_time_get(); timeout = RTCS_timer_get_interval(timebefore, timeafter); timebefore = timeafter; xmithead->DELTA -= timeout; /* If its timer has expired, send it */ timeout = xmithead->DELTA; if (timeout <= 0) { message = NULL; wait = FALSE; } /* Endif */ } /* Endif */ /* ** There are three cases at this point: ** 1) Retransmission queue is empty ** (wait == TRUE, timeout == 0, message == ?) ** 2) Retransmission queue is nonempty, positive timeout ** (wait == TRUE, timeout > 0, message == ?) ** 3) Retransmission queue is nonempty, nonpositive timeout, ** i.e., head of retransmission queue timed out ** (wait == FALSE, timeout == 0, message == NULL) */ /* If there are no expired messages, block */ if (wait) { message = RTCS_msgq_receive(queue, timeout, ppp_ptr->MSG_POOL); } /* Endif */ /* ** There are two cases at this point: ** 1) We got a message from _msgq_receive ** (message != NULL) ** 2) Head of retransmission queue timed out ** (message == NULL) */ /* We got a packet to send */ if (message) { /* Control packets restart or stop retransmission */ ctrl = message->COMMAND; if (ctrl == PPPCMD_SHUTDOWN) { param = message->PARAM; /* Free the message we just got */ RTCS_msg_free(message); for (xmitnode = &xmithead;;){ if (*xmitnode == NULL) { break; } else { /* unlink */ message = *xmitnode; *xmitnode = message->NEXT; /* Free the message from the list */ PPPTX_DISCARD(message); } /* Endif */ } /* Endfor */ RTCS_msgq_close(queue); /* Unblock PPP_shutdown() */ RTCS_sem_post(param); /* Kill self */ return; } /* Endif */ if (ctrl != PPPCMD_SEND) { protocol = message->PROTOCOL; RTCS_msg_free(message); /* ** Search the retransmission queue for a packet ** matching the protocol field of the control message */ for (xmitnode = &xmithead;; xmitnode = &(*xmitnode)->NEXT) { if (*xmitnode == NULL) { break; } else if ((*xmitnode)->PROTOCOL == protocol) { message = *xmitnode; switch (ctrl) { case PPPCMD_RESTART: message->TIMEOUT = _PPP_MIN_XMIT_TIMEOUT; message->RETRY = _PPP_MAX_CONF_RETRIES; break; case PPPCMD_STOP: if (message->NEXT) { message->NEXT->DELTA += message->DELTA; } /* Endif */ *xmitnode = message->NEXT; PPPTX_DISCARD(message); break; } /* Endswitch */ break; } /* Endif */ } /* Endfor */ continue; } /* Endif */ /* Save the PCB's FREE field */ message->ORIG_FREE = message->PCB->FREE; if (message->TIMEOUT) { message->PCB->FREE = PPP_tx_pcbfree; } /* Endif */ /* Receive timed out -- get the head of the retransmission queue */ } else { message = xmithead; xmithead = message->NEXT; if (xmithead) { xmithead->DELTA += message->DELTA; } /* Endif */ /* Generate a TO event */ if (message->CALL) { message->CALL(message->PARAM, message->PCB, message->RETRY == 1); } /* Endif */ /* RETRY == 0 means retry forever */ if (message->RETRY) { /* When the retry count reaches zero, discard the packet */ if (!--message->RETRY) { PPPTX_DISCARD(message); continue; } /* Endif */ } /* Endif */ /* Use exponential backoff when retransmitting */ message->TIMEOUT <<= 1; if (message->TIMEOUT > _PPP_MAX_XMIT_TIMEOUT) { message->TIMEOUT = _PPP_MAX_XMIT_TIMEOUT; } /* Endif */ } /* Endif */ /********************************************************** ** ** We have a packet -- validate it ** */ /* Take a snapshot of the current state and send options */ PPP_mutex_lock(&ppp_ptr->MUTEX); state = ppp_ptr->LINK_STATE; opt = *ppp_ptr->SEND_OPTIONS; PPP_mutex_unlock(&ppp_ptr->MUTEX); /* Send the data packet (unless the link is not open) */ if (!state && message->PROTOCOL != PPP_PROT_LCP) { PPPTX_DISCARD(message); ppp_ptr->ST_TX_DISCARDED++; continue; } /* Endif */ /********************************************************** ** ** We have a valid packet -- send it ** */ /* LCP control packets are always sent with default options */ if (message->PROTOCOL == PPP_PROT_LCP && message->PCB->FRAG[0].FRAGMENT[2] >= 1 && message->PCB->FRAG[0].FRAGMENT[2] <= 7) { pcbopt = 1; } else { pcbopt = 0; } /* Endif */ pcb = message->PCB; /* Only data packets are compressed */ /* Start CR 2296 */ //if (((message->PROTOCOL & 0xC000) == 0) && opt.CP) { /* End CR 2296 */ // pcb = opt.CP->CP_comp(&ppp_ptr->CCP_STATE.SEND_DATA, pcb, ppp_ptr, &opt); // mqx_htons(pcb->FRAG[0].FRAGMENT, PPP_PROT_CP); //} /* Endif */ _iopcb_write(ppp_ptr->DEVICE, pcb, pcbopt); /********************************************************** ** ** Packet is sent -- update retransmission queue ** */ /* Free the buffer unless it may need to be retransmitted */ if (message->TIMEOUT) { /* Measure elapsed time */ timeafter = RTCS_time_get(); timeout = RTCS_timer_get_interval(timebefore, timeafter); timebefore = timeafter; if (xmithead) { xmithead->DELTA -= timeout; } /* Endif */ /* Insert packet into proper place in retransmission queue */ for (message->DELTA = message->TIMEOUT, xmitnode = &xmithead;; message->DELTA -= (*xmitnode)->DELTA, xmitnode = &(*xmitnode)->NEXT) { if (*xmitnode == NULL) { /* Add packet at tail of queue */ message->NEXT = NULL; *xmitnode = message; break; } else if ((*xmitnode)->DELTA > message->TIMEOUT) { /* Insert packet in middle (possibly head) of queue */ (*xmitnode)->DELTA -= message->DELTA; message->NEXT = *xmitnode; *xmitnode = message; break; } /* Endif */ } /* Endfor */ } else { /* PCB has already been freed by _iopcb_write() */ RTCS_msg_free(message); } /* Endif */ } /* Endfor */ #endif /* RTCSCFG_ENABLE_IP4 */ } /* 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 TCPIP_task ( void *dummy, void *creator ) { /* Body */ TCPIP_CFG_STRUCT TCPIP_cfg; RTCS_DATA_PTR RTCS_data_ptr; uint32_t i; TCPIP_MESSAGE_PTR tcpip_msg; uint32_t timeout = 1, timebefore, timeafter, timedelta; uint32_t status; /* Return status */ _queue_id tcpip_qid; RTCSLOG_FNE2(RTCSLOG_FN_TCPIP_task, creator); RTCS_data_ptr = RTCS_get_data(); RTCS_setcfg(TCPIP, &TCPIP_cfg); TCPIP_cfg.status = RTCS_OK; tcpip_qid = RTCS_msgq_open(TCPIP_QUEUE, 0); if (tcpip_qid == 0) { RTCS_task_exit(creator, RTCSERR_OPEN_QUEUE_FAILED); } /* Endif */ RTCS_data_ptr->TCPIP_TASKID = RTCS_task_getid(); /* ** Initialize the Time Service */ TCP_tick = TCPIP_fake_tick; TCPIP_Event_init(); timebefore = RTCS_time_get(); /* ** Allocate a block of PCBs */ status = RTCSPCB_init(); if (status != RTCS_OK) { RTCS_task_exit(creator, status); } /* Endif */ IF_FREE = NULL; /* ** Initialize the protocols */ #if RTCSCFG_ENABLE_IP4 /********************************************* * Initialize IPv4 **********************************************/ status = IP_init(); if (status) { RTCS_task_exit(creator, status); } #if RTCSCFG_ENABLE_ICMP status = ICMP_init(); if (status) { RTCS_task_exit(creator, status); } #endif /* RTCSCFG_ENABLE_ICMP */ ARP_init(); BOOT_init(); #endif /* RTCSCFG_ENABLE_IP4 */ #if RTCSCFG_ENABLE_IP6 /********************************************* * Initialize IPv6 **********************************************/ status = IP6_init(); if (status) { RTCS_task_exit(creator, status); } /* Init ICMP6. */ status = ICMP6_init(); //TBD Add it to RTCS6_protocol_table if (status) { RTCS_task_exit(creator, status); } #endif /* RTCSCFG_ENABLE_IP6*/ #if (RTCSCFG_ENABLE_IP_REASSEMBLY && RTCSCFG_ENABLE_IP4) || (RTCSCFG_ENABLE_IP6_REASSEMBLY && RTCSCFG_ENABLE_IP6) /* Initialize the reassembler */ status = IP_reasm_init(); if (status) { RTCS_task_exit(creator, status); } #endif /* Add loopback interface.*/ status = IPLOCAL_init (); if (status) { RTCS_task_exit(creator, status); }; for (i = 0; RTCS_protocol_table[i]; i++) { status = (*RTCS_protocol_table[i])(); if (status) { RTCS_task_exit(creator, status); } /* Endif */ } /* Endfor */ _RTCS_initialized= TRUE; RTCS_task_resume_creator(creator, RTCS_OK); while (1) { TCPIP_EVENT_PTR queue = TCPIP_Event_head; tcpip_msg = (TCPIP_MESSAGE_PTR)RTCS_msgq_receive(tcpip_qid, timeout, RTCS_data_ptr->TCPIP_msg_pool); if (tcpip_msg) { if (NULL != tcpip_msg->COMMAND) { tcpip_msg->COMMAND(tcpip_msg->DATA); } RTCS_msg_free(tcpip_msg); } timeout = TCP_tick(); timeafter = RTCS_time_get(); /* If head changed set time delta to zero to prevent immidiate event */ if (queue == TCPIP_Event_head) { timedelta = RTCS_timer_get_interval(timebefore, timeafter); } else { timedelta = 0; } timebefore = timeafter; timedelta = TCPIP_Event_time(timedelta); if (timedelta != 0) { if ((timedelta < timeout) || (timeout == 0)) { timeout = timedelta; } } } } /* 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 */