From 06b5132fdcac6b79ccf2f97de658235b28610bd7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 17 Feb 2009 06:59:15 +0000 Subject: [PATCH] [icmp] Add support for responding to pings --- src/include/gpxe/errfile.h | 1 + src/include/gpxe/icmp.h | 23 +++++++++ src/net/icmp.c | 101 +++++++++++++++++++++++++++++++++++++ src/net/ipv4.c | 3 ++ 4 files changed, 128 insertions(+) create mode 100644 src/include/gpxe/icmp.h create mode 100644 src/net/icmp.c diff --git a/src/include/gpxe/errfile.h b/src/include/gpxe/errfile.h index 90c21a7e..a6181453 100644 --- a/src/include/gpxe/errfile.h +++ b/src/include/gpxe/errfile.h @@ -139,6 +139,7 @@ #define ERRFILE_slam ( ERRFILE_NET | 0x00160000 ) #define ERRFILE_ib_sma ( ERRFILE_NET | 0x00170000 ) #define ERRFILE_ib_packet ( ERRFILE_NET | 0x00180000 ) +#define ERRFILE_icmp ( ERRFILE_NET | 0x00190000 ) #define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/include/gpxe/icmp.h b/src/include/gpxe/icmp.h new file mode 100644 index 00000000..49ade2f2 --- /dev/null +++ b/src/include/gpxe/icmp.h @@ -0,0 +1,23 @@ +#ifndef _GPXE_ICMP_H +#define _GPXE_ICMP_H + +/** @file + * + * ICMP protocol + * + */ + +/** An ICMP header */ +struct icmp_header { + /** Type */ + uint8_t type; + /** Code */ + uint8_t code; + /** Checksum */ + uint16_t chksum; +} __attribute__ (( packed )); + +#define ICMP_ECHO_RESPONSE 0 +#define ICMP_ECHO_REQUEST 8 + +#endif /* _GPXE_ICMP_H */ diff --git a/src/net/icmp.c b/src/net/icmp.c new file mode 100644 index 00000000..3e45c1f6 --- /dev/null +++ b/src/net/icmp.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2009 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +/** @file + * + * ICMP protocol + * + */ + +struct tcpip_protocol icmp_protocol __tcpip_protocol; + +/** + * Process a received packet + * + * @v iobuf I/O buffer + * @v st_src Partially-filled source address + * @v st_dest Partially-filled destination address + * @v pshdr_csum Pseudo-header checksum + * @ret rc Return status code + */ +static int icmp_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src, + struct sockaddr_tcpip *st_dest, + uint16_t pshdr_csum __unused ) { + struct icmp_header *icmp = iobuf->data; + size_t len = iob_len ( iobuf ); + unsigned int csum; + int rc; + + /* Sanity check */ + if ( len < sizeof ( *icmp ) ) { + DBG ( "ICMP packet too short at %zd bytes (min %zd bytes)\n", + len, sizeof ( *icmp ) ); + rc = -EINVAL; + goto done; + } + + /* Verify checksum */ + csum = tcpip_chksum ( icmp, len ); + if ( csum != 0 ) { + DBG ( "ICMP checksum incorrect (is %04x, should be 0000)\n", + csum ); + DBG_HD ( icmp, len ); + rc = -EINVAL; + goto done; + } + + /* We respond only to pings */ + if ( icmp->type != ICMP_ECHO_REQUEST ) { + DBG ( "ICMP ignoring type %d\n", icmp->type ); + rc = 0; + goto done; + } + + DBG ( "ICMP responding to ping\n" ); + + /* Change type to response and recalculate checksum */ + icmp->type = ICMP_ECHO_RESPONSE; + icmp->chksum = 0; + icmp->chksum = tcpip_chksum ( icmp, len ); + + /* Transmit the response */ + if ( ( rc = tcpip_tx ( iob_disown ( iobuf ), &icmp_protocol, st_dest, + st_src, NULL, NULL ) ) != 0 ) { + DBG ( "ICMP could not transmit ping response: %s\n", + strerror ( rc ) ); + goto done; + } + + done: + free_iob ( iobuf ); + return rc; +} + +/** ICMP TCP/IP protocol */ +struct tcpip_protocol icmp_protocol __tcpip_protocol = { + .name = "ICMP", + .rx = icmp_rx, + .tcpip_proto = IP_ICMP, +}; diff --git a/src/net/ipv4.c b/src/net/ipv4.c index 335048c8..8668d44b 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -627,3 +627,6 @@ static int ipv4_create_routes ( void ) { struct settings_applicator ipv4_settings_applicator __settings_applicator = { .apply = ipv4_create_routes, }; + +/* Drag in ICMP */ +REQUIRE_OBJECT ( icmp );