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 19FILE_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 34struct 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 */ 45static 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 */ 99struct tcpip_protocol icmp_protocol __tcpip_protocol = { 100 .name = "ICMP", 101 .rx = icmp_rx, 102 .tcpip_proto = IP_ICMP, 103}; 104