[icmp] Add support for responding to pings
[people/oremanj/gpxe.git] / src / net / icmp.c
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 #include <string.h>
20 #include <errno.h>
21 #include <gpxe/iobuf.h>
22 #include <gpxe/in.h>
23 #include <gpxe/tcpip.h>
24 #include <gpxe/icmp.h>
25
26 /** @file
27  *
28  * ICMP protocol
29  *
30  */
31
32 struct tcpip_protocol icmp_protocol __tcpip_protocol;
33
34 /**
35  * Process a received packet
36  *
37  * @v iobuf             I/O buffer
38  * @v st_src            Partially-filled source address
39  * @v st_dest           Partially-filled destination address
40  * @v pshdr_csum        Pseudo-header checksum
41  * @ret rc              Return status code
42  */
43 static int icmp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src,
44                      struct sockaddr_tcpip *st_dest,
45                      uint16_t pshdr_csum __unused ) {
46         struct icmp_header *icmp = iobuf->data;
47         size_t len = iob_len ( iobuf );
48         unsigned int csum;
49         int rc;
50
51         /* Sanity check */
52         if ( len < sizeof ( *icmp ) ) {
53                 DBG ( "ICMP packet too short at %zd bytes (min %zd bytes)\n",
54                       len, sizeof ( *icmp ) );
55                 rc = -EINVAL;
56                 goto done;
57         }
58
59         /* Verify checksum */
60         csum = tcpip_chksum ( icmp, len );
61         if ( csum != 0 ) {
62                 DBG ( "ICMP checksum incorrect (is %04x, should be 0000)\n",
63                       csum );
64                 DBG_HD ( icmp, len );
65                 rc = -EINVAL;
66                 goto done;
67         }
68
69         /* We respond only to pings */
70         if ( icmp->type != ICMP_ECHO_REQUEST ) {
71                 DBG ( "ICMP ignoring type %d\n", icmp->type );
72                 rc = 0;
73                 goto done;
74         }
75
76         DBG ( "ICMP responding to ping\n" );
77
78         /* Change type to response and recalculate checksum */
79         icmp->type = ICMP_ECHO_RESPONSE;
80         icmp->chksum = 0;
81         icmp->chksum = tcpip_chksum ( icmp, len );
82
83         /* Transmit the response */
84         if ( ( rc = tcpip_tx ( iob_disown ( iobuf ), &icmp_protocol, st_dest,
85                                st_src, NULL, NULL ) ) != 0 ) {
86                 DBG ( "ICMP could not transmit ping response: %s\n",
87                       strerror ( rc ) );
88                 goto done;
89         }
90
91  done:
92         free_iob ( iobuf );
93         return rc;
94 }
95
96 /** ICMP TCP/IP protocol */
97 struct tcpip_protocol icmp_protocol __tcpip_protocol = {
98         .name = "ICMP",
99         .rx = icmp_rx,
100         .tcpip_proto = IP_ICMP,
101 };