Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2009 Michael Brown <mbrown (at) fensystems.co.uk>.
      3  *
      4  * This program is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU General Public License as
      6  * published by the Free Software Foundation; either version 2 of the
      7  * License, or any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program; if not, write to the Free Software
     16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     17  */
     18 
     19 FILE_LICENCE ( GPL2_OR_LATER );
     20 
     21 #include <string.h>
     22 #include <errno.h>
     23 #include <gpxe/iobuf.h>
     24 #include <gpxe/in.h>
     25 #include <gpxe/tcpip.h>
     26 #include <gpxe/icmp.h>
     27 
     28 /** @file
     29  *
     30  * ICMP protocol
     31  *
     32  */
     33 
     34 struct tcpip_protocol icmp_protocol __tcpip_protocol;
     35 
     36 /**
     37  * Process a received packet
     38  *
     39  * @v iobuf		I/O buffer
     40  * @v st_src		Partially-filled source address
     41  * @v st_dest		Partially-filled destination address
     42  * @v pshdr_csum	Pseudo-header checksum
     43  * @ret rc		Return status code
     44  */
     45 static int icmp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
     46 		     struct sockaddr_tcpip *st_dest,
     47 		     uint16_t pshdr_csum __unused ) {
     48 	struct icmp_header *icmp = iobuf->data;
     49 	size_t len = iob_len ( iobuf );
     50 	unsigned int csum;
     51 	int rc;
     52 
     53 	/* Sanity check */
     54 	if ( len < sizeof ( *icmp ) ) {
     55 		DBG ( "ICMP packet too short at %zd bytes (min %zd bytes)\n",
     56 		      len, sizeof ( *icmp ) );
     57 		rc = -EINVAL;
     58 		goto done;
     59 	}
     60 
     61 	/* Verify checksum */
     62 	csum = tcpip_chksum ( icmp, len );
     63 	if ( csum != 0 ) {
     64 		DBG ( "ICMP checksum incorrect (is %04x, should be 0000)\n",
     65 		      csum );
     66 		DBG_HD ( icmp, len );
     67 		rc = -EINVAL;
     68 		goto done;
     69 	}
     70 
     71 	/* We respond only to pings */
     72 	if ( icmp->type != ICMP_ECHO_REQUEST ) {
     73 		DBG ( "ICMP ignoring type %d\n", icmp->type );
     74 		rc = 0;
     75 		goto done;
     76 	}
     77 
     78 	DBG ( "ICMP responding to ping\n" );
     79 
     80 	/* Change type to response and recalculate checksum */
     81 	icmp->type = ICMP_ECHO_RESPONSE;
     82 	icmp->chksum = 0;
     83 	icmp->chksum = tcpip_chksum ( icmp, len );
     84 
     85 	/* Transmit the response */
     86 	if ( ( rc = tcpip_tx ( iob_disown ( iobuf ), &icmp_protocol, st_dest,
     87 			       st_src, NULL, NULL ) ) != 0 ) {
     88 		DBG ( "ICMP could not transmit ping response: %s\n",
     89 		      strerror ( rc ) );
     90 		goto done;
     91 	}
     92 
     93  done:
     94 	free_iob ( iobuf );
     95 	return rc;
     96 }
     97 
     98 /** ICMP TCP/IP protocol */
     99 struct tcpip_protocol icmp_protocol __tcpip_protocol = {
    100 	.name = "ICMP",
    101 	.rx = icmp_rx,
    102 	.tcpip_proto = IP_ICMP,
    103 };
    104