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