• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Michael Brown <mbrown@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  */
icmp_rx(struct io_buffer * iobuf,struct sockaddr_tcpip * st_src,struct sockaddr_tcpip * st_dest,uint16_t pshdr_csum __unused)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