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 = iobuf->data;
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
113 /* Identify connection */
114 ping = ping_demux ( ntohs ( echo->ident ) );
115 DBGC ( ping, "PING %p reply id %#04x seq %#04x\n",
116 ping, ntohs ( echo->ident ), ntohs ( echo->sequence ) );
117 if ( ! ping ) {
118 rc = -ENOTCONN;
119 goto discard;
120 }
121
122 /* Strip header, construct metadata, and pass data to upper layer */
123 iob_pull ( iobuf, sizeof ( *echo ) );
124 memset ( &meta, 0, sizeof ( meta ) );
125 meta.src = ( ( struct sockaddr * ) st_src );
126 meta.flags = XFER_FL_ABS_OFFSET;
127 meta.offset = ntohs ( echo->sequence );
128 return xfer_deliver ( &ping->xfer, iob_disown ( iobuf ), &meta );
129
130 discard:
131 free_iob ( iobuf );
132 return rc;
133}
134
135/**
136 * Allocate I/O buffer for ping
137 *
138 * @v ping Ping connection
139 * @v len Payload size
140 * @ret iobuf I/O buffer, or NULL
141 */
142static struct io_buffer *
144 size_t header_len;
145 struct io_buffer *iobuf;
146
147 header_len = ( MAX_LL_NET_HEADER_LEN + sizeof ( struct icmp_echo ) );
148 iobuf = alloc_iob ( header_len + len );
149 if ( iobuf )
150 iob_reserve ( iobuf, header_len );
151 return iobuf;
152}
153
154/**
155 * Deliver datagram as I/O buffer
156 *
157 * @v ping Ping connection
158 * @v iobuf I/O buffer
159 * @v meta Data transfer metadata
160 * @ret rc Return status code
161 */
162static int ping_deliver ( struct ping_connection *ping, struct io_buffer *iobuf,
163 struct xfer_metadata *meta ) {
164 struct icmp_echo *echo = iob_push ( iobuf, sizeof ( *echo ) );
165 int rc;
166
167 /* Construct header */
168 memset ( echo, 0, sizeof ( *echo ) );
169 echo->ident = htons ( ping->port );
170 echo->sequence = htons ( meta->offset );
171
172 /* Transmit echo request */
173 if ( ( rc = icmp_tx_echo_request ( iob_disown ( iobuf ),
174 &ping->peer ) ) != 0 ) {
175 DBGC ( ping, "PING %p could not transmit: %s\n",
176 ping, strerror ( rc ) );
177 return rc;
178 }
179
180 return 0;
181}
182
183/**
184 * Close ping connection
185 *
186 * @v ping Ping connection
187 * @v rc Reason for close
188 */
189static void ping_close ( struct ping_connection *ping, int rc ) {
190
191 /* Close data transfer interface */
192 intf_shutdown ( &ping->xfer, rc );
193
194 /* Remove from list of connections and drop list's reference */
195 list_del ( &ping->list );
196 ref_put ( &ping->refcnt );
197
198 DBGC ( ping, "PING %p closed\n", ping );
199}
200
201/** Ping data transfer interface operations */
207
208/** Ping data transfer interface descriptor */
211
212/**
213 * Open a ping connection
214 *
215 * @v xfer Data transfer interface
216 * @v peer Peer socket address
217 * @v local Local socket address, or NULL
218 * @ret rc Return status code
219 */
220static int ping_open ( struct interface *xfer, struct sockaddr *peer,
221 struct sockaddr *local ) {
222 struct sockaddr_tcpip *st_peer = ( struct sockaddr_tcpip * ) peer;
223 struct sockaddr_tcpip *st_local = ( struct sockaddr_tcpip * ) local;
224 struct ping_connection *ping;
225 int port;
226 int rc;
227
228 /* Allocate and initialise structure */
229 ping = zalloc ( sizeof ( *ping ) );
230 if ( ! ping ) {
231 rc = -ENOMEM;
232 goto err_alloc;
233 }
234 DBGC ( ping, "PING %p allocated\n", ping );
235 ref_init ( &ping->refcnt, NULL );
236 intf_init ( &ping->xfer, &ping_xfer_desc, &ping->refcnt );
237 memcpy ( &ping->peer, st_peer, sizeof ( ping->peer ) );
238
239 /* Bind to local port */
240 port = tcpip_bind ( st_local, ping_port_available );
241 if ( port < 0 ) {
242 rc = port;
243 DBGC ( ping, "PING %p could not bind: %s\n",
244 ping, strerror ( rc ) );
245 goto err_bind;
246 }
247 ping->port = port;
248 DBGC ( ping, "PING %p bound to id %#04x\n", ping, port );
249
250 /* Attach parent interface, transfer reference to connection
251 * list, and return
252 */
253 intf_plug_plug ( &ping->xfer, xfer );
254 list_add ( &ping->list, &ping_conns );
255 return 0;
256
257 err_bind:
258 ref_put ( &ping->refcnt );
259 err_alloc:
260 return rc;
261}
262
263/** Ping socket opener */
264struct socket_opener ping_socket_opener __socket_opener = {
265 .semantics = PING_SOCK_ECHO,
266 .open = ping_open,
267};
268
269/** Linkage hack */
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
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:50
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:573
#define PING_SOCK_ECHO
Definition socket.h:34
int ping_sock_echo
Linkage hack.
Definition ping.c:270
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EADDRINUSE
Address already in use.
Definition errno.h:304
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTCONN
The socket is not connected.
Definition errno.h:570
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
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:89
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:217
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
#define iob_reserve(iobuf, len)
Definition iobuf.h:72
#define iob_pull(iobuf, len)
Definition iobuf.h:107
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:662
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:220
static struct io_buffer * ping_alloc_iob(struct ping_connection *ping __unused, size_t len)
Allocate I/O buffer for ping.
Definition ping.c:143
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:202
static struct interface_descriptor ping_xfer_desc
Ping data transfer interface descriptor.
Definition ping.c:209
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:162
static void ping_close(struct ping_connection *ping, int rc)
Close ping connection.
Definition ping.c:189
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:38
void * data
Start of data.
Definition iobuf.h:53
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