iPXE
ping.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <stdlib.h>
28#include <string.h>
29#include <errno.h>
30#include <byteswap.h>
31#include <ipxe/refcnt.h>
32#include <ipxe/list.h>
33#include <ipxe/iobuf.h>
34#include <ipxe/tcpip.h>
35#include <ipxe/icmp.h>
36#include <ipxe/interface.h>
37#include <ipxe/xfer.h>
38#include <ipxe/open.h>
39#include <ipxe/netdevice.h>
40#include <ipxe/ping.h>
41
42/** @file
43 *
44 * ICMP ping protocol
45 *
46 */
47
48/**
49 * A ping connection
50 *
51 */
53 /** Reference counter */
54 struct refcnt refcnt;
55 /** List of ping connections */
57
58 /** Remote socket address */
60 /** Local port number */
62
63 /** Data transfer interface */
65};
66
67/** List of registered ping connections */
68static LIST_HEAD ( ping_conns );
69
70/**
71 * Identify ping connection by local port number
72 *
73 * @v port Local port number
74 * @ret ping Ping connection, or NULL
75 */
76static struct ping_connection * ping_demux ( unsigned int port ) {
77 struct ping_connection *ping;
78
79 list_for_each_entry ( ping, &ping_conns, list ) {
80 if ( ping->port == port )
81 return ping;
82 }
83 return NULL;
84}
85
86/**
87 * Check if local port number is available
88 *
89 * @v port Local port number
90 * @ret port Local port number, or negative error
91 */
92static int ping_port_available ( int port ) {
93
94 return ( ping_demux ( port ) ? -EADDRINUSE : port );
95}
96
97/**
98 * Process ICMP ping reply
99 *
100 * @v iobuf I/O buffer
101 * @v st_src Source address
102 * @ret rc Return status code
103 */
104int ping_rx ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src ) {
105 struct icmp_echo *echo;
106 struct ping_connection *ping;
107 struct xfer_metadata meta;
108 int rc;
109
110 /* Sanity check: should already have been checked by ICMP layer */
111 assert ( iob_len ( iobuf ) >= sizeof ( *echo ) );
112 echo = iobuf->data;
113
114 /* Identify connection */
115 ping = ping_demux ( ntohs ( echo->ident ) );
116 DBGC ( ping, "PING %p reply id %#04x seq %#04x\n",
117 ping, ntohs ( echo->ident ), ntohs ( echo->sequence ) );
118 if ( ! ping ) {
119 rc = -ENOTCONN;
120 goto discard;
121 }
122
123 /* Strip header, construct metadata, and pass data to upper layer */
124 iob_pull ( iobuf, sizeof ( *echo ) );
125 memset ( &meta, 0, sizeof ( meta ) );
126 meta.src = ( ( struct sockaddr * ) st_src );
127 meta.flags = XFER_FL_ABS_OFFSET;
128 meta.offset = ntohs ( echo->sequence );
129 return xfer_deliver ( &ping->xfer, iob_disown ( iobuf ), &meta );
130
131 discard:
132 free_iob ( iobuf );
133 return rc;
134}
135
136/**
137 * Allocate I/O buffer for ping
138 *
139 * @v ping Ping connection
140 * @v len Payload size
141 * @ret iobuf I/O buffer, or NULL
142 */
143static struct io_buffer *
145 size_t header_len;
146 struct io_buffer *iobuf;
147
148 header_len = ( MAX_LL_NET_HEADER_LEN + sizeof ( struct icmp_echo ) );
149 iobuf = alloc_iob ( header_len + len );
150 if ( iobuf )
151 iob_reserve ( iobuf, header_len );
152 return iobuf;
153}
154
155/**
156 * Deliver datagram as I/O buffer
157 *
158 * @v ping Ping connection
159 * @v iobuf I/O buffer
160 * @v meta Data transfer metadata
161 * @ret rc Return status code
162 */
163static int ping_deliver ( struct ping_connection *ping, struct io_buffer *iobuf,
164 struct xfer_metadata *meta ) {
165 struct icmp_echo *echo = iob_push ( iobuf, sizeof ( *echo ) );
166 int rc;
167
168 /* Construct header */
169 memset ( echo, 0, sizeof ( *echo ) );
170 echo->ident = htons ( ping->port );
171 echo->sequence = htons ( meta->offset );
172
173 /* Transmit echo request */
174 if ( ( rc = icmp_tx_echo_request ( iob_disown ( iobuf ),
175 &ping->peer ) ) != 0 ) {
176 DBGC ( ping, "PING %p could not transmit: %s\n",
177 ping, strerror ( rc ) );
178 return rc;
179 }
180
181 return 0;
182}
183
184/**
185 * Close ping connection
186 *
187 * @v ping Ping connection
188 * @v rc Reason for close
189 */
190static void ping_close ( struct ping_connection *ping, int rc ) {
191
192 /* Close data transfer interface */
193 intf_shutdown ( &ping->xfer, rc );
194
195 /* Remove from list of connections and drop list's reference */
196 list_del ( &ping->list );
197 ref_put ( &ping->refcnt );
198
199 DBGC ( ping, "PING %p closed\n", ping );
200}
201
202/** Ping data transfer interface operations */
208
209/** Ping data transfer interface descriptor */
212
213/**
214 * Open a ping connection
215 *
216 * @v xfer Data transfer interface
217 * @v peer Peer socket address
218 * @v local Local socket address, or NULL
219 * @ret rc Return status code
220 */
221static int ping_open ( struct interface *xfer, struct sockaddr *peer,
222 struct sockaddr *local ) {
223 struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
224 struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
225 struct ping_connection *ping;
226 int port;
227 int rc;
228
229 /* Allocate and initialise structure */
230 ping = zalloc ( sizeof ( *ping ) );
231 if ( ! ping ) {
232 rc = -ENOMEM;
233 goto err_alloc;
234 }
235 DBGC ( ping, "PING %p allocated\n", ping );
236 ref_init ( &ping->refcnt, NULL );
237 intf_init ( &ping->xfer, &ping_xfer_desc, &ping->refcnt );
238 memcpy ( &ping->peer, st_peer, sizeof ( ping->peer ) );
239
240 /* Bind to local port */
241 port = tcpip_bind ( st_local, ping_port_available );
242 if ( port < 0 ) {
243 rc = port;
244 DBGC ( ping, "PING %p could not bind: %s\n",
245 ping, strerror ( rc ) );
246 goto err_bind;
247 }
248 ping->port = port;
249 DBGC ( ping, "PING %p bound to id %#04x\n", ping, port );
250
251 /* Attach parent interface, transfer reference to connection
252 * list, and return
253 */
254 intf_plug_plug ( &ping->xfer, xfer );
255 list_add ( &ping->list, &ping_conns );
256 return 0;
257
258 err_bind:
259 ref_put ( &ping->refcnt );
260 err_alloc:
261 return rc;
262}
263
264/** Ping socket opener */
265struct socket_opener ping_socket_opener __socket_opener = {
266 .semantics = PING_SOCK_ECHO,
267 .open = ping_open,
268};
269
270/** Linkage hack */
#define NULL
NULL pointer (VOID *).
Definition Base.h:321
u8 port
Port number.
Definition CIB_PRM.h:3
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned short uint16_t
Definition stdint.h:11
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:61
ring len
Length.
Definition dwmac.h:226
uint8_t meta
Metadata flags.
Definition ena.h:3
Error codes.
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:598
#define PING_SOCK_ECHO
Definition socket.h:34
int ping_sock_echo
Linkage hack.
Definition ping.c:271
#define DBGC(...)
Definition compiler.h:530
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:921
#define EADDRINUSE
Address already in use.
Definition errno.h:347
#define ENOMEM
Not enough space.
Definition errno.h:578
#define ENOTCONN
The socket is not connected.
Definition errno.h:613
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:951
int icmp_tx_echo_request(struct io_buffer *iobuf, struct sockaddr_tcpip *st_dest)
Transmit ICMP echo request.
Definition icmp.c:106
ICMP protocol.
#define htons(value)
Definition byteswap.h:136
#define ntohs(value)
Definition byteswap.h:137
Transport-network layer interface.
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition interface.c:250
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition interface.c:108
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition interface.c:279
Object interfaces.
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition interface.h:81
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition interface.h:204
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition interface.h:33
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
I/O buffers.
#define iob_push(iobuf, len)
Definition iobuf.h:149
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:277
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:220
#define iob_reserve(iobuf, len)
Definition iobuf.h:132
#define iob_pull(iobuf, len)
Definition iobuf.h:167
int echo(void)
Definition kb.c:133
Linked lists.
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition list.h:432
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#define LIST_HEAD(list)
Declare a static list head.
Definition list.h:38
#define list_add(new, head)
Add a new entry to the head of a list.
Definition list.h:70
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:718
struct mschapv2_challenge peer
Peer challenge.
Definition mschapv2.h:1
Network device management.
#define MAX_LL_NET_HEADER_LEN
Maximum combined length of a link-layer and network-layer header.
Definition netdevice.h:59
Data transfer interface opening.
#define __socket_opener
Register a socket opener.
Definition open.h:89
static int ping_open(struct interface *xfer, struct sockaddr *peer, struct sockaddr *local)
Open a ping connection.
Definition ping.c:221
static struct io_buffer * ping_alloc_iob(struct ping_connection *ping __unused, size_t len)
Allocate I/O buffer for ping.
Definition ping.c:144
int ping_rx(struct io_buffer *iobuf, struct sockaddr_tcpip *st_src)
Process ICMP ping reply.
Definition ping.c:104
static int ping_port_available(int port)
Check if local port number is available.
Definition ping.c:92
static struct ping_connection * ping_demux(unsigned int port)
Identify ping connection by local port number.
Definition ping.c:76
static struct interface_operation ping_xfer_operations[]
Ping data transfer interface operations.
Definition ping.c:203
static struct interface_descriptor ping_xfer_desc
Ping data transfer interface descriptor.
Definition ping.c:210
static int ping_deliver(struct ping_connection *ping, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram as I/O buffer.
Definition ping.c:163
static void ping_close(struct ping_connection *ping, int rc)
Close ping connection.
Definition ping.c:190
ICMP ping protocol.
int ping(const char *hostname, unsigned long timeout, size_t len, unsigned int count, int quiet)
Ping a host.
Definition pingmgmt.c:70
Reference counting.
#define ref_put(refcnt)
Drop reference to object.
Definition refcnt.h:107
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition refcnt.h:65
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
An ICMP echo request/reply.
Definition icmp.h:30
An object interface descriptor.
Definition interface.h:56
An object interface operation.
Definition interface.h:18
An object interface.
Definition interface.h:125
A persistent I/O buffer.
Definition iobuf.h:98
void * data
Start of data.
Definition iobuf.h:113
A doubly-linked list entry (or list head).
Definition list.h:19
A ping connection.
Definition ping.c:52
struct sockaddr_tcpip peer
Remote socket address.
Definition ping.c:59
uint16_t port
Local port number.
Definition ping.c:61
struct interface xfer
Data transfer interface.
Definition ping.c:64
struct list_head list
List of ping connections.
Definition ping.c:56
struct refcnt refcnt
Reference counter.
Definition ping.c:54
TCP/IP socket address.
Definition tcpip.h:76
Generalized socket address structure.
Definition socket.h:97
A socket opener.
Definition open.h:71
Data transfer metadata.
Definition xfer.h:23
int tcpip_bind(struct sockaddr_tcpip *st_local, int(*available)(int port))
Bind to local TCP/IP port.
Definition tcpip.c:215
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
struct io_buffer * xfer_alloc_iob(struct interface *intf, size_t len)
Allocate I/O buffer.
Definition xfer.c:159
Data transfer interfaces.
#define XFER_FL_ABS_OFFSET
Offset is absolute.
Definition xfer.h:48