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 */
void TFTPSRV_build_ACK ( TFTP_TRANS_STRUCT_PTR trans_ptr /* [IN/OUT] The transaction state */ ) { /* Body */ mqx_htons(trans_ptr->SND.HEAD.OP, trans_ptr->SEND_OP); mqx_htons(trans_ptr->SND.HEAD.BLOCK, trans_ptr->BLOCK); trans_ptr->BLOCK++; trans_ptr->SEND_SIZE = sizeof(TFTP_HEADER); trans_ptr->NUM_RETRIES = 0; } /* Endbody */
void LCP_sendprotrej ( PCB_PTR pcb, /* [IN] - packet to reject */ PPPFSM_CFG_PTR fsm /* [IN/OUT] - State Machine */ ) { /* Body */ #if RTCSCFG_ENABLE_IP4 PPP_CFG_PTR ppp_ptr = fsm->HANDLE; LCP_CFG_PTR lcp_ptr = fsm->PRIVATE; unsigned char *packet, *src, *dst; uint16_t length; uint16_t size = ppp_ptr->SEND_OPTIONS->MRU - CP_HDR_LEN; length = pcb->FRAG[0].LENGTH; packet = pcb->FRAG[0].FRAGMENT; /* Truncate the packet if necessary */ if (length > size) { length = size; } /* Endif */ /* Make room for a Code-Reject header */ size = length + CP_HDR_LEN; /* Copy the received packet (including protocol field) to the */ /* data portion of the Protocol-Reject */ src = packet + length; dst = src + 2 + CP_HDR_LEN; while (length--) *--dst = *--src; /* Build a Code-Reject packet */ mqx_htons(packet, PPP_PROT_LCP); packet += 2; *packet++ = LCP_CODE_PROT_REJ; *packet++ = fsm->CURID; fsm->CURID = (fsm->CURID + 1) & 0xFF; mqx_htons(packet, size); packet += 2; pcb->FRAG[0].LENGTH = size + 2; lcp_ptr->ST_LCP_TX_REJECT++; PPP_send_one(ppp_ptr, PPP_PROT_LCP, pcb); #else PCB_free(pcb); #endif /* RTCSCFG_ENABLE_IP4 */ } /* Endbody */
PCB_PTR PPP_pcballoc ( uint16_t protocol, /* [IN] - PPP protocol */ uint32_t size /* [IN] - max size of packet, excluding protocol */ ) { /* Body */ PCB_FRAGMENT *pcb_frag_ptr; PCB_PTR packet; packet = _mem_alloc_system(sizeof(PCB) + sizeof(PCB_FRAGMENT) + 2 + size); if (packet) { packet->FREE = (void (_CODE_PTR_)(PCB_PTR))_mem_free; pcb_frag_ptr = packet->FRAG; pcb_frag_ptr->LENGTH = size + 2; pcb_frag_ptr->FRAGMENT = (unsigned char *)packet + sizeof(PCB) + sizeof(PCB_FRAGMENT); mqx_htons(pcb_frag_ptr->FRAGMENT, protocol); pcb_frag_ptr++; pcb_frag_ptr->LENGTH = 0; pcb_frag_ptr->FRAGMENT = NULL; } /* Endif */ return packet; } /* Endbody */
void TFTPSRV_build_DATA ( TFTP_TRANS_STRUCT_PTR trans_ptr /* [IN/OUT] The transaction state */ ) { /* Body */ int32_t datalen; datalen = RTCS_io_read(trans_ptr->TRANS_FILE_PTR, (char *)trans_ptr->SND.DATA, TFTP_DATA_SIZE); if (datalen < 0) { datalen = 0; } /* Endif */ trans_ptr->BLOCK++; mqx_htons(trans_ptr->SND.HEAD.OP, trans_ptr->SEND_OP); mqx_htons(trans_ptr->SND.HEAD.BLOCK, trans_ptr->BLOCK); trans_ptr->SEND_SIZE = sizeof(TFTP_HEADER) + datalen; trans_ptr->NUM_RETRIES = 0; trans_ptr->EXIT = (trans_ptr->SEND_SIZE < sizeof(TFTP_PACKET)); } /* Endbody */
static void RIP_build_header( unsigned char *buf, /* [OUT] the rip header */ uint8_t cmd, /* [IN] the commande */ uint8_t version /* [IN] the version */ ) { /* Body */ RIP_HEADER_PTR hd = (RIP_HEADER_PTR)buf; _mem_zero(buf, sizeof(RIP_HEADER)); mqx_htonc(hd->COMMAND, cmd); mqx_htonc(hd->VERSION, version); mqx_htons(hd->MBZ, 0); } /* Endbody */
static void RIP_build_rte( unsigned char *buf, /* [OUT] the route entry */ uint16_t family, uint16_t rt_tag, _ip_address net_addr, _ip_address net_mask, _ip_address next_hop, uint32_t metric, uint32_t rip_vers ) { /* Body */ RIP_ENTRY_PTR rte = (RIP_ENTRY_PTR)buf; if (rip_vers == RIP_V2){ mqx_htons(rte->RT_TAG, rt_tag); mqx_htonl(rte->NETMASK, net_mask); mqx_htonl(rte->NEXTHOP, next_hop); }else{ _mem_zero(buf, sizeof(RIP_ENTRY)); } mqx_htons(rte->FAMILY, family); mqx_htonl(rte->NETADDR, net_addr); mqx_htonl(rte->METRIC, metric); } /* Endbody */
void BOOTP_open ( TCPIP_PARM_BOOTP *parms ) { /* Body */ IP_IF_PTR if_ptr = (IP_IF_PTR)parms->handle; BOOTP_CFG_PTR bootp = (BOOTP_CFG_PTR) &parms->config; uint32_t 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 */ mqx_htonc(bootp->PACKET.OP, BOOTPOP_BOOTREQUEST); mqx_htonc(bootp->PACKET.HTYPE, if_ptr->DEV_TYPE); mqx_htonc(bootp->PACKET.HLEN, if_ptr->DEV_ADDRLEN); mqx_htonc(bootp->PACKET.HOPS, 0); mqx_htonl(bootp->PACKET.XID, bootp->XID); mqx_htons(bootp->PACKET.FLAGS, 0x8000); mqx_htonl(bootp->PACKET.CIADDR, INADDR_ANY); mqx_htonl(bootp->PACKET.YIADDR, INADDR_ANY); mqx_htonl(bootp->PACKET.SIADDR, INADDR_ANY); mqx_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 = (void *)parms; } /* Endbody */
bool BOOTP_send ( TCPIP_EVENT_PTR event /* [IN/OUT] the resend event */ ) { /* Body */ IP_IF_PTR if_ptr = (IP_IF_PTR)event->PRIVATE; TCPIP_PARM_BOOTP *parms = (TCPIP_PARM_BOOTP *)if_ptr->BOOT; BOOTP_CFG_PTR bootp = (BOOTP_CFG_PTR) &parms->config; RTCSPCB_PTR pcb_ptr; /* Set the event to trigger for the next retransmission (+/- 1 sec) */ bootp->RESEND.TIME = bootp->TIMEOUT + (RTCS_rand() & 0x7FF) - 0x400; /* Allocate a PCB */ pcb_ptr = RTCSPCB_alloc_send(); if (pcb_ptr == NULL) { return TRUE; } /* Endif */ //RTCSLOG_PCB_ALLOC(pcb_ptr); /* The only field that changes in BOOTREQUEST packets is 'secs' */ mqx_htons(bootp->PACKET.SECS, bootp->SECS); bootp->SECS += bootp->RESEND.TIME >> 10; /* approx. divide by 1000 */ /* Double the timeout */ bootp->TIMEOUT <<= 1; if (bootp->TIMEOUT > BOOTP_TIMEOUT_MAX) { bootp->TIMEOUT = BOOTP_TIMEOUT_MAX; } /* Endif */ /* Put the BOOTREQUEST in the PCB */ RTCSPCB_append_fragment(pcb_ptr, sizeof(BOOTP_HEADER), (unsigned char *)&bootp->PACKET); RTCSPCB_append_fragment(pcb_ptr, sizeof(BOOTP_DATA), parms->data->SNAME); RTCSLOG_PCB_WRITE(pcb_ptr, RTCS_LOGCTRL_PORT(IPPORT_BOOTPC), 0); /* Send the datagram */ BOOT_send(pcb_ptr, if_ptr); /* Always retransmit */ return TRUE; } /* Endbody */
bool DHCP_option_int16 ( unsigned char * *optptr, uint32_t *optlen, unsigned char opttype, uint16_t optval ) { /* Body */ unsigned char *opt = *optptr; if ((*optlen) < 4) return FALSE; mqx_htonc(opt, opttype); opt++; mqx_htonc(opt, 2); opt++; mqx_htons(opt, optval); opt += 2; *optlen -= 4; *optptr = opt; return TRUE; } /* 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 */
HOSTENT_STRUCT *DNS_query_resolver_task ( unsigned char *name, uint16_t query_type ) { /* Body */ DNS_MESSAGE_HEADER_STRUCT *message_head_ptr; DNS_MESSAGE_TAIL_STRUCT *message_tail_ptr; HOSTENT_STRUCT *host_ptr = NULL; sockaddr_in addr; uint32_t local_sock; uint32_t qname_size; uint32_t buffer_size; uint16_t rlen; int32_t temp_size; int32_t error; unsigned char *temp_ptr; unsigned char *qname_ptr; unsigned char *buffer_ptr; /* ** If the size of this buffer is changed, also change the buffer size ** in the recvfrom() call near the bottom of this function */ buffer_ptr = RTCS_mem_alloc_zero( DNS_MAX_UDP_MESSAGE_SIZE ); if ( buffer_ptr == NULL ) { RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_ALLOCATE_MEMORY, 0, 0, 0); return( NULL ); }/* Endif */ _mem_set_type(buffer_ptr, MEM_TYPE_DNS_UDP_MESSAGE); qname_ptr = buffer_ptr + sizeof( DNS_MESSAGE_HEADER_STRUCT ); if ( query_type == DNS_A ) { error = DNS_is_dotted_domain_name( name, qname_ptr ); if ( error == RTCSERR_DNS_INVALID_NAME || error == RTCSERR_DNS_INVALID_LOCAL_NAME ) { _mem_free(buffer_ptr); return( NULL ); }/* Endif */ } else { if ( query_type == DNS_PTR ) { error = DNS_insert_IP_query( name, qname_ptr ); if ( error == RTCSERR_DNS_INVALID_IP_ADDR ) { _mem_free(buffer_ptr); return( NULL ); }/* Endif */ } else { _mem_free(buffer_ptr); return( NULL ); } /* Endif */ } /* Endif */ local_sock = socket(AF_INET, SOCK_DGRAM, 0); if ( local_sock == RTCS_HANDLE_ERROR ) { RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_OPEN_SOCKET, 0, 0, 0); _mem_free(buffer_ptr); return( NULL ); }/* Endif */ /* Local address */ addr.sin_family = AF_INET; addr.sin_port = 0; addr.sin_addr.s_addr = INADDR_ANY; error = bind(local_sock, &addr, sizeof(addr)); if (error != RTCS_OK) { RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_BIND_SOCKET, 0, 0, 0); _mem_free(buffer_ptr); return( NULL ); } /* Endif */ /* set up buffer for sending query. */ message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT *)buffer_ptr; mqx_htons(message_head_ptr->ID, 0); mqx_htons(message_head_ptr->CONTROL, DNS_STANDARD_QUERY); mqx_htons(message_head_ptr->QDCOUNT, DNS_SINGLE_QUERY); mqx_htons(message_head_ptr->NSCOUNT, 0); mqx_htons(message_head_ptr->ARCOUNT, 0); mqx_htons(message_head_ptr->ANCOUNT, 0); qname_size = strlen((char *)qname_ptr ); /* Need to include the last '\0' character as well */ qname_size++; temp_ptr = buffer_ptr + sizeof( DNS_MESSAGE_HEADER_STRUCT ) + qname_size; message_tail_ptr = (DNS_MESSAGE_TAIL_STRUCT *)temp_ptr; mqx_htons(message_tail_ptr->QTYPE, query_type); mqx_htons(message_tail_ptr->QCLASS, DNS_IN); buffer_size = sizeof(DNS_MESSAGE_HEADER_STRUCT) + qname_size + sizeof(DNS_MESSAGE_TAIL_STRUCT); /* Remote address, DNS_Resolver currently uses port 1024 */ addr.sin_port = DNS_RESOLVER_PORT; addr.sin_addr.s_addr = DNS_RESOLVER_IP_ADDR; rlen = sizeof(addr); /* Send the buffer to the resolver for making a query */ error = sendto(local_sock, buffer_ptr, buffer_size, 0, &addr, rlen); if (error == RTCS_ERROR) { shutdown(local_sock, FLAG_ABORT_CONNECTION); RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_SEND_QUERY, 0, 0, 0); _mem_free(buffer_ptr); return( NULL ); }/* Endif */ /* Get the response from the resolver, if none received, return NULL */ error = (uint32_t)RTCS_selectset( &local_sock, 1, DNS_QUERY_TIMEOUT ); if ( !error || error == RTCS_ERROR ) { shutdown(local_sock, FLAG_ABORT_CONNECTION); RTCS_log_error(ERROR_DNS, RTCSERR_DNS_NO_RESPONSE_FROM_RESOLVER, 0, 0, 0); _mem_free(buffer_ptr); return( NULL ); } /* Endif */ temp_size = recvfrom(local_sock, buffer_ptr, DNS_MAX_UDP_MESSAGE_SIZE, 0, &addr, &rlen); if ( temp_size == RTCS_ERROR ) { shutdown(local_sock, FLAG_ABORT_CONNECTION); RTCS_log_error(ERROR_DNS, RTCSERR_DNS_PACKET_RECEPTION_ERROR, 0, 0, 0); _mem_free(buffer_ptr); return( NULL ); }/* Endif */ host_ptr = DNS_parse_UDP_response(buffer_ptr, name, query_type); shutdown(local_sock, FLAG_ABORT_CONNECTION); _mem_free(buffer_ptr); return( host_ptr ); } /* Endbody */
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 */
uint32_t ENET_send ( /* [IN] the Ethernet state structure */ _enet_handle handle, /* [IN] the packet to send */ PCB_PTR packet, /* [IN] the protocol */ uint16_t type, /* [IN] the destination Ethernet address */ _enet_address dest, /* [IN] optional flags, zero = default */ uint32_t flags ) { ENET_CONTEXT_STRUCT_PTR enet_ptr = (ENET_CONTEXT_STRUCT_PTR)handle; ENET_HEADER_PTR packet_ptr; unsigned char *type_ptr; PCB_FRAGMENT_PTR frag_ptr; uint32_t swhdr, size, frags; uint32_t error; _KLOGM(KERNEL_DATA_STRUCT_PTR kernel_data); _KLOGM(_GET_KERNEL_DATA(kernel_data)); _KLOGE6(KLOG_ENET_send, handle, packet, type, dest, flags); if (flags & ENET_OPT_8021QTAG) { swhdr = ENET_FRAMESIZE_HEAD_VLAN; } else { swhdr = ENET_FRAMESIZE_HEAD; } /* ** Make sure the first fragment is long enough for the Ethernet ** frame header. This isn't strictly necessary, but it's impractical ** to split a 14-26 byte header over multiple fragments. */ #if MQX_CHECK_ERRORS if (packet->FRAG[0].LENGTH < swhdr) { ENET_INC_STATS(COMMON.ST_TX_DISCARDED); error = ENETERR_SEND_SHORT; goto ERROR; } #endif /* ** Make sure that no fragment exceeds a maximum packet length. ** We check every fragment because we want to prevent something ** like FRAG[0].LENGTH = 2000, FRAG[1].LENGTH = -1000. This ** situation would not be detected if we only check the total ** length. */ size = frags = 0; for (frag_ptr = packet->FRAG; frag_ptr->LENGTH; frag_ptr++) { #if MQX_CHECK_ERRORS if (frag_ptr->LENGTH > enet_ptr->MaxTxFrameSize) { ENET_INC_STATS(COMMON.ST_TX_DISCARDED); error = ENETERR_SEND_LONG; goto ERROR; } #endif size += frag_ptr->LENGTH; frags++; } /* ** Make sure that the total sum of the fragments doesn't exceed ** a maximum packet length. */ #if MQX_CHECK_ERRORS if (size > enet_ptr->MaxTxFrameSize) { ENET_INC_STATS(COMMON.ST_TX_DISCARDED); error = ENETERR_SEND_LONG; goto ERROR; } #endif /* ** Everything checks out -- fill in the header. */ packet_ptr = (ENET_HEADER_PTR)packet->FRAG[0].FRAGMENT; htone(packet_ptr->DEST, dest); htone(packet_ptr->SOURCE, enet_ptr->ADDRESS); type_ptr = packet_ptr->TYPE; if (flags & ENET_OPT_8021QTAG) { ENET_8021QTAG_HEADER_PTR tag_ptr = (ENET_8021QTAG_HEADER_PTR)(type_ptr+2); uint16_t tag; tag = ENET_GETOPT_8021QPRIO(flags) << 13; mqx_htons(type_ptr, ENETPROT_8021Q); mqx_htons(tag_ptr->TAG, tag); type_ptr = tag_ptr->TYPE; } if (flags & ENET_OPT_8023) { ENET_8022_HEADER_PTR llc_ptr = (ENET_8022_HEADER_PTR)(type_ptr+2); (void)mqx_htons(type_ptr, size - swhdr); mqx_htonc(llc_ptr->DSAP, 0xAA); mqx_htonc(llc_ptr->SSAP, 0xAA); mqx_htonc(llc_ptr->COMMAND, 0x03); mqx_htonc(&llc_ptr->OUI[0], 0x00); mqx_htonc(&llc_ptr->OUI[1], 0x00); mqx_htonc(&llc_ptr->OUI[2], 0x00); type_ptr = llc_ptr->TYPE; } mqx_htons(type_ptr, type); /* ** This function can be called from any context, and it needs mutual ** exclusion with itself, and with ENET_ISR(). */ ENET_lock_context(enet_ptr); error = (*enet_ptr->PARAM_PTR->ENET_IF->MAC_IF->SEND)(handle, packet, size, frags, flags); ENET_unlock_context(enet_ptr); if (error) { ERROR: PCB_free(packet); } _KLOGX4(KLOG_ENET_send, handle, packet, error); return error; }
static RTCSPCB_PTR IPREASM_reasm_dgram ( IP_DGRAM_PTR dgram /* [IN] the dgram descriptor */ ) { /* Body */ RTCSPCB_PTR outpcb; PCB_PTR bpcb; PCB_FRAGMENT *pcb_frag_ptr; unsigned char *data; uint32_t iphlen = (mqx_ntohc(dgram->header.IP4.IPH.VERSLEN) & 0xF) << 2; uint32_t ip_totlen = iphlen + dgram->TOTLEN; bpcb = RTCS_mem_alloc_system(sizeof(PCB) + sizeof(PCB_FRAGMENT) + ip_totlen); if (!bpcb) { return NULL; } /* Endif */ data = (unsigned char *)bpcb + sizeof(PCB) + sizeof(PCB_FRAGMENT); bpcb->FREE = (void(_CODE_PTR_)(PCB_PTR))_mem_free; bpcb->PRIVATE = NULL; pcb_frag_ptr = bpcb->FRAG; pcb_frag_ptr->LENGTH = ip_totlen; pcb_frag_ptr->FRAGMENT = data; pcb_frag_ptr++; pcb_frag_ptr->LENGTH = 0; pcb_frag_ptr->FRAGMENT = NULL; /* Copy the IP header with options */ mqx_htons(dgram->header.IP4.IPH.FRAGMENT, 0); _mem_copy(&dgram->header.IP4.IPH, data, iphlen); data += iphlen; /* ** At this point, we really should update the LENGTH ** and CHECKSUM fields in the new IP header, but we ** don't actually need to, because this datagram is ** going straight to IPLOCAL_service, which doesn't ** check these things. */ /* Copy the stored data in the new packet */ IPREASM_blk_read_all(dgram, data, dgram->TOTLEN); /* Put it in an RTCSPCB */ outpcb = RTCSPCB_alloc_recv(bpcb); if (outpcb == NULL) { PCB_free(bpcb); return NULL; } /* Endif */ //RTCSLOG_PCB_ALLOC(bpcb); outpcb->IFSRC = dgram->IFSRC; outpcb->TYPE = dgram->TYPE; outpcb->LINK_OPTIONS.RX = dgram->LINKOPT; RTCSPCB_DATA_NETWORK(outpcb) = RTCSPCB_DATA(outpcb); RTCSPCB_SET_TRANS_PROTL(outpcb, dgram->header.IP4.PROTO); RTCSPCB_SET_TRANS_DELTA(outpcb, iphlen); /* Delete the local structure */ IPREASM_del_dgram(dgram); return outpcb; } /* Endbody */
uint32_t PPP_send ( _ppp_handle handle, /* [IN] - the PPP state structure */ uint16_t protocol, /* [IN] - protocol for the packet */ PCB_PTR pcb /* [IN] - the packet to send */ ) { /* Body */ #if RTCSCFG_ENABLE_IP4 PPP_CFG_PTR ppp_ptr = handle; PCB_FRAGMENT_PTR frag_ptr; uint32_t size, mru; uint32_t error; /* Do some error checking */ if (ppp_ptr->VALID != PPP_VALID) { PCB_free(pcb); return RTCSERR_PPP_INVALID_HANDLE; } else if (!(protocol&1) || (protocol&0x100)) { PCB_free(pcb); return RTCSERR_PPP_INVALID_PROTOCOL; } /* Endif */ error = PPP_OK; PPP_mutex_lock(&ppp_ptr->MUTEX); if (!ppp_ptr->LINK_STATE) { error = RTCSERR_PPP_LINK_NOT_OPEN; } else { /* SPR P122-0371-01 */ /* PCB includes 2-byte protocol field, but negotiated MRU doesn't */ mru = ppp_ptr->SEND_OPTIONS->MRU + 2; /* End SPR P122-0371-01 */ } /* Endif */ PPP_mutex_unlock(&ppp_ptr->MUTEX); if (error) { PCB_free(pcb); return error; } /* Endif */ /* ** Make sure the first fragment is long enough for the PPP protocol ** field. This isn't strictly necessary, but it's impractical ** to split a 2 byte field over multiple fragments. */ if (pcb->FRAG[0].LENGTH < 2) { PCB_free(pcb); return RTCSERR_PPP_PACKET_TOO_SHORT; } /* Endif */ /* ** Make sure that no fragment exceeds a maximum packet length. ** We check every fragment because we want to prevent something ** like FRAG[0].LENGTH = 2000, FRAG[1].LENGTH = -1000. This ** situation would not be detected if we only check the total ** length. */ size = 0; for (frag_ptr = pcb->FRAG; frag_ptr->LENGTH; frag_ptr++) { if (frag_ptr->LENGTH > mru) { PCB_free(pcb); return RTCSERR_PPP_PACKET_TOO_LONG; } /* Endif */ size += frag_ptr->LENGTH; } /* Endfor */ /* ** Make sure that the total sum of the fragments doesn't exceed ** a maximum packet length. */ if (size > mru) { PCB_free(pcb); return RTCSERR_PPP_PACKET_TOO_LONG; } /* Endif */ /* ** Everything checks out -- send the packet to the Tx task. */ mqx_htons(pcb->FRAG[0].FRAGMENT, protocol); return PPP_send_one(ppp_ptr, protocol, pcb); #else return RTCSERR_IP_IS_DISABLED; #endif /* RTCSCFG_ENABLE_IP4 */ } /* Endbody */
uint32_t TFTP_open ( void *ft_data /* [IN] the address and filename of the bootimage */ ) { /* Body */ TFTP_DATA_STRUCT_PTR tftp; sockaddr_in local_addr; char *str_ptr; unsigned char *packet; uint32_t sock; uint32_t error; uint32_t fn_len, fm_len; uint32_t pkt_len; tftp = (TFTP_DATA_STRUCT_PTR) ft_data; /* Get a socket */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == RTCS_SOCKET_ERROR) { return RTCSERR_TFTP_SOCKET; } /* Endif */ /* Must be initialized in order for TFTP_close to be able to release socket and memory */ TFTP_config.SOCK = sock; TFTP_config.RRQ_PTR = NULL; /* Bind it */ local_addr.sin_family = AF_INET; local_addr.sin_port = 0; local_addr.sin_addr.s_addr = INADDR_ANY; error = bind(sock, (const sockaddr *)&local_addr, sizeof(local_addr)); if (error != RTCS_OK) { TFTP_close(); return error; } /* Endif */ if ( (tftp->FILENAME == NULL) || (tftp->FILEMODE == NULL) ){ TFTP_close(); return TFTPERR_FILE_NOT_FOUND; } /* Endif */ /* Prepare a read request (RRQ) */ str_ptr = tftp->FILENAME; while (*str_ptr++) {}; fn_len = str_ptr - tftp->FILENAME; str_ptr = tftp->FILEMODE; while (*str_ptr++) {}; fm_len = str_ptr - tftp->FILEMODE; pkt_len = 2 + fn_len + fm_len; packet = RTCS_mem_alloc(pkt_len); if (packet == NULL) { TFTP_close(); return RTCSERR_TFTP_RRQ_ALLOC; } /* Endif */ _mem_set_type(packet, MEM_TYPE_TFTP_PACKET); TFTP_config.RRQ_PTR = packet; mqx_htons(packet, TFTPOP_RRQ); _mem_copy(tftp->FILENAME, &packet[ 2], fn_len); _mem_copy(tftp->FILEMODE, &packet[fn_len+2], fm_len); /* Send the RRQ */ TFTP_config.SOCK = sock; TFTP_config.SADDR.sin_family = AF_INET; TFTP_config.SADDR.sin_port = IPPORT_TFTP; TFTP_config.SADDR.sin_addr.s_addr = tftp->SERVER; TFTP_timeout_init(&TFTP_config.TIMEOUT); error = sendto(sock, packet, pkt_len, 0, (sockaddr *)(&TFTP_config.SADDR), sizeof(TFTP_config.SADDR)); if (error != pkt_len) { TFTP_close(); return RTCSERR_TFTP_RRQ_SEND; } /* Endif */ /* Initialize the TFTP client */ TFTP_config.RRQ_PTR = packet; TFTP_config.RRQ_LEN = pkt_len; TFTP_config.LAST = FALSE; mqx_htons(TFTP_config.ACK.OP, TFTPOP_ACK); mqx_htons(TFTP_config.ACK.BLOCK, 0); return RTCS_OK; } /* 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 */
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 */
static uint32_t LCP_buildconfreq ( PPPFSM_CFG_PTR fsm, /* [IN] - State Machine */ unsigned char *outp, /* [IN] - free packet */ uint32_t sizeleft /* [IN] - size of packet */ ) { /* Body */ LCP_CFG_PTR lcp_ptr = fsm->PRIVATE; uint32_t totlen = 0; uint32_t aplen; #define LCP_BREQ(ci,len) \ *outp++ = LCP_CI_ ## ci; \ *outp++ = len; \ totlen += len /* ** Generate configuration information for each option ** we want to negotiate. */ if (lcp_ptr->RECV_NEG.NEG_MRU) { if (sizeleft >= totlen+4) { LCP_BREQ(MRU,4); mqx_htons(outp, lcp_ptr->RECV_NEG.MRU); outp += 2; } /* Endif */ } /* Endif */ if (lcp_ptr->RECV_NEG.NEG_ACCM) { if (sizeleft >= totlen+6) { LCP_BREQ(ACCM,6); mqx_htonl(outp, lcp_ptr->RECV_NEG.ACCM); outp += 4; } /* Endif */ } /* 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 */ if (sizeleft >= totlen+aplen) { LCP_BREQ(AP,aplen); mqx_htons(outp, lcp_ptr->RECV_NEG.AP); outp += 2; switch (lcp_ptr->RECV_NEG.AP) { case PPP_PROT_CHAP: mqx_htonc(outp, 5); outp++; /* Only MD5 supported */ break; } /* Endswitch */ } /* Endif */ } /* Endif */ if (lcp_ptr->RECV_NEG.NEG_PFC) { if (sizeleft >= totlen+2) { LCP_BREQ(PFC,2); } /* Endif */ } /* Endif */ if (lcp_ptr->RECV_NEG.NEG_ACFC) { if (sizeleft >= totlen+2) { LCP_BREQ(ACFC,2); } /* Endif */ } /* Endif */ return totlen; } /* Endbody */