/** \brief Process recieved ICMP datagram * \ingroup periodic_functions * \author * \li Jari Lahti ([email protected]) * \date 08.07.2002 * \param frame - pointer to received IP frame structure * \param len - length of the received IP datagram (in bytes) * \return * \li -1 - packet not OK (not proper ICMP or not ICMP at all) * \li >=0 - packet OK * * Invoke process_icmp_in whenever IP datagram containing ICMP message * is detected (see main_demo.c for example main loop implementing this). * * This function simply checks correctnes of received ICMP message and * send ICMP replies when requested. * */ INT16 process_icmp_in (struct ip_frame* frame, UINT16 len) { UINT8 type; UINT8 code; UINT16 checksum; UINT16 i; UINT16 j; UINT8 tbuf[16]; /* Is this ICMP? */ ICMP_DEBUGOUT("Processing ICMP...\n\r"); if( frame->protocol != IP_ICMP ) { ICMP_DEBUGOUT("ERROR: The protocol is not ICMP\n\r"); return(-1); } /* Calculate checksum for received packet */ checksum = 0; i = len; NETWORK_RECEIVE_INITIALIZE(frame->buf_index); while(i>15) { RECEIVE_NETWORK_BUF(tbuf, 16); checksum = (UINT16)ip_checksum_buf (checksum, tbuf, 16); i -= 16; } for(j=0; j < i; j++) checksum = ip_checksum(checksum, RECEIVE_NETWORK_B(), (UINT8)j); checksum = ~ checksum; if(checksum != IP_GOOD_CS) { ICMP_DEBUGOUT("ERROR: ICMP Checksum failed!\n\r"); return (-1); } ICMP_DEBUGOUT("ICMP Checksum OK\n\r"); /* Start processing the message */ NETWORK_RECEIVE_INITIALIZE(frame->buf_index); type = RECEIVE_NETWORK_B(); code = RECEIVE_NETWORK_B(); /* We have already checked the CS, skip it */ (void)RECEIVE_NETWORK_B(); (void)RECEIVE_NETWORK_B(); switch(type) { case ICMP_ECHO_REQUEST: if(code != 0) { ICMP_DEBUGOUT("ERROR:Misformed ICMP ECHO Request\n\r"); return(-1); } ICMP_DEBUGOUT("ICMP ECHO Request received\n\r"); /* Is it a packet for setting temporary IP? */ if(len == (ICMP_ECHOREQ_HLEN + ICMP_TEMPIPSET_DATALEN) ) { /* Yep, set temporary IP address */ ICMP_DEBUGOUT("PING with 102 bytes of data, getting temp. IP\r\n"); localmachine.localip = frame->dip; localmachine.defgw = frame->sip; localmachine.netmask = 0; } /* Same IP? */ if(localmachine.localip != frame->dip) return(-1); /* Reply it */ TXBUF[0] = ICMP_ECHO_REPLY; TXBUF[1] = 0; TXBUF[2] = 0; TXBUF[3] = 0; /* Copy with truncate if needed */ if(len > NETWORK_TX_BUFFER_SIZE) len = NETWORK_TX_BUFFER_SIZE; RECEIVE_NETWORK_BUF(&TXBUF[4], len); /* Calculate Checksum for packet to be sent */ checksum = 0; checksum = (UINT16)ip_checksum_buf(checksum, &TXBUF[0], len); checksum = ~ checksum; /* Put the checksum on place */ TXBUF[2] = (UINT8)(checksum>>8); TXBUF[3] = (UINT8)checksum; /* Send it */ (void)process_ip_out(frame->sip, IP_ICMP, 0, 100, &TXBUF[0], len); ICMP_DEBUGOUT("ICMP Reply sent\n\r"); return(0); break; case ICMP_ECHO_REPLY: break; default: /* Unrecognized ICMP message */ ICMP_DEBUGOUT("Unregognized ICMP message\n\r"); return(-1); } }
/** \brief Send data to remote host using given UDP socket * \ingroup udp_app_api * \author * \li Jari Lahti ([email protected]) * \date 26.07.2002 * \param sochandle handle to UDP socket to use * \param remip remote IP address to which data should be sent * \param remport remote port number to which data should be sent * \param buf pointer to data buffer (start of user data) * \param blen buffer length in bytes (without space reserved at the * beginning of buffer for headers) * \param dlen length of user data to be sent (in bytes) * \return * \li -1 - Error (general error, e.g. parameters) * \li -2 - ARP or lower layer not ready, try again later * \li -3 - Socket closed or invalid local port * \li >0 - OK (number represents number of bytes actually sent) * * \warning * \li <i>buf</i> parameter is a pointer to data to be sent in * user buffer. But note that there <b>MUST</b> be sufficient * free buffer space before that data for UDP header (of #UDP_HLEN * size). * * Use this function to send data over an already opened UDP socket. */ INT16 udp_send (INT8 sochandle, UINT32 remip, UINT16 remport, UINT8* buf, UINT16 blen, UINT16 dlen) { struct ucb* soc; UINT8* user_buf_start; UINT16 cs; UINT8 cs_cnt; INT16 i; if( NO_OF_UDPSOCKETS < 0 ) return(-1); if( NO_OF_UDPSOCKETS == 0 ) return(-1); if( sochandle > NO_OF_UDPSOCKETS ) { UDP_DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } if( sochandle < 0 ) { UDP_DEBUGOUT("Socket handle non-valid\r\n"); return(-1); } if(remip == 0) { UDP_DEBUGOUT("Remote IP 0 not allowed\r\n"); return(-1); } if(remport == 0) { UDP_DEBUGOUT("Remote port 0 not allowed\r\n"); return(-1); } if( dlen > blen ) dlen = blen; if( (dlen + UDP_HLEN) > UDP_SEND_MTU) dlen = UDP_SEND_MTU - UDP_HLEN; soc = &udp_socket[sochandle]; /* Get referense */ if(soc->state != UDP_STATE_OPENED ) { UDP_DEBUGOUT("UDP Socket Closed\r\n"); return(-3); } if(soc->locport == 0) { UDP_DEBUGOUT("ERROR:Socket local port is zero\r\n"); return(-1); } user_buf_start = buf; buf -= UDP_HLEN; /* Put header */ *buf++ = (UINT8)(soc->locport >> 8); *buf++ = (UINT8)soc->locport; *buf++ = (UINT8)(remport >> 8); *buf++ = (UINT8)remport; *buf++ = (UINT8)((dlen + UDP_HLEN) >> 8); *buf++ = (UINT8)(dlen + UDP_HLEN); *buf++ = 0; *buf = 0; buf = user_buf_start; buf -= UDP_HLEN; /* Calculate checksum if needed */ cs = 0; if( soc->opts & UDP_OPT_SEND_CS) { cs = 0; cs_cnt = 0; /* Do it firstly to IP pseudo header */ cs = ip_checksum(cs, (UINT8)(localmachine.localip >> 24), cs_cnt++); cs = ip_checksum(cs, (UINT8)(localmachine.localip >> 16), cs_cnt++); cs = ip_checksum(cs, (UINT8)(localmachine.localip >> 8), cs_cnt++); cs = ip_checksum(cs, (UINT8)localmachine.localip, cs_cnt++); cs = ip_checksum(cs, (UINT8)(remip >> 24), cs_cnt++); cs = ip_checksum(cs, (UINT8)(remip >> 16), cs_cnt++); cs = ip_checksum(cs, (UINT8)(remip >> 8), cs_cnt++); cs = ip_checksum(cs, (UINT8)remip, cs_cnt++); cs = ip_checksum(cs, 0, cs_cnt++); cs = ip_checksum(cs, (UINT8)IP_UDP, cs_cnt++); cs = ip_checksum(cs, (UINT8)((dlen + UDP_HLEN) >> 8), cs_cnt++); cs = ip_checksum(cs, (UINT8)(dlen + UDP_HLEN), cs_cnt++); /* Go to UDP header + data */ buf = user_buf_start; buf -= UDP_HLEN; cs = ip_checksum_buf(cs, buf, dlen + UDP_HLEN); cs = ~ cs; if(cs == 0) cs = 0xFFFF; /* Save checksum in correct place */ buf = user_buf_start; buf -= UDP_HLEN; buf += 6; *buf++ = (UINT8)(cs >> 8); *buf = (UINT8)cs; buf = user_buf_start; buf -= UDP_HLEN; }