iPXE
lotest.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 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 <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include <byteswap.h>
32 #include <ipxe/iobuf.h>
33 #include <ipxe/netdevice.h>
34 #include <ipxe/if_ether.h>
35 #include <ipxe/keys.h>
36 #include <ipxe/console.h>
37 #include <usr/ifmgmt.h>
38 #include <usr/lotest.h>
39 
40 /** @file
41  *
42  * Loopback testing
43  *
44  */
45 
46 /** Current loopback test receiver */
47 static struct net_device *lotest_receiver;
48 
49 /** Loopback testing received packets */
50 static LIST_HEAD ( lotest_queue );
51 
52 /**
53  * Process received packet
54  *
55  * @v iobuf I/O buffer
56  * @v netdev Network device
57  * @v ll_dest Link-layer destination address
58  * @v ll_source Link-layer source address
59  * @v flags Packet flags
60  * @ret rc Return status code
61  */
62 static int lotest_rx ( struct io_buffer *iobuf,
63  struct net_device *netdev,
64  const void *ll_dest __unused,
65  const void *ll_source __unused,
66  unsigned int flags __unused ) {
67 
68  /* Add to received packet queue if currently performing a test */
69  if ( netdev == lotest_receiver ) {
70  list_add_tail ( &iobuf->list, &lotest_queue );
71  } else {
72  free_iob ( iobuf );
73  }
74 
75  return 0;
76 }
77 
78 /**
79  * Dequeue received packet
80  *
81  * @ret iobuf I/O buffer, or NULL
82  */
83 static struct io_buffer * lotest_dequeue ( void ) {
84  struct io_buffer *iobuf;
85 
86  /* Remove first packet (if any) from received packet queue */
87  iobuf = list_first_entry ( &lotest_queue, struct io_buffer, list );
88  if ( ! iobuf )
89  return NULL;
90  list_del ( &iobuf->list );
91 
92  return iobuf;
93 }
94 
95 /**
96  * Transcribe network-layer address
97  *
98  * @v net_addr Network-layer address
99  * @ret string Human-readable transcription of address
100  */
101 static const char * lotest_ntoa ( const void *net_addr __unused ) {
102  return "<INVALID>";
103 }
104 
105 /**
106  * Loopback test network-layer protocol
107  *
108  * Using a dedicated network-layer protocol avoids problems caused by
109  * cards supporting features such as IPv4 checksum offload trying to
110  * interpret the (randomly generated) network-layer content.
111  */
112 static struct net_protocol lotest_protocol __net_protocol = {
113  .name = "LOTEST",
114  .rx = lotest_rx,
115  .ntoa = lotest_ntoa,
116  .net_proto = htons ( 0x6950 ), /* Not a genuine protocol number */
117  .net_addr_len = 0,
118 };
119 
120 /**
121  * Discard all received loopback test packets
122  *
123  */
124 static void lotest_flush ( void ) {
125  struct io_buffer *iobuf;
126 
127  while ( ( iobuf = lotest_dequeue() ) != NULL )
128  free_iob ( iobuf );
129 }
130 
131 /**
132  * Wait for packet to be received
133  *
134  * @v data Expected data
135  * @v len Expected data length
136  * @ret rc Return status code
137  */
138 static int loopback_wait ( void *data, size_t len ) {
139  struct io_buffer *iobuf;
140 
141  /* Poll until packet arrives */
142  while ( 1 ) {
143 
144  /* Check for cancellation */
145  if ( iskey() && ( getchar() == CTRL_C ) )
146  return -ECANCELED;
147 
148  /* Poll network devices */
149  net_poll();
150 
151  /* Dequeue packet, if available */
152  iobuf = lotest_dequeue();
153  if ( ! iobuf )
154  continue;
155 
156  /* Check packet length */
157  if ( iob_len ( iobuf ) != len ) {
158  printf ( "\nLength mismatch: sent %zd, received %zd",
159  len, iob_len ( iobuf ) );
160  DBG ( "\nSent:\n" );
161  DBG_HDA ( 0, data, len );
162  DBG ( "Received:\n" );
163  DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
164  free_iob ( iob_disown ( iobuf ) );
165  return -EINVAL;
166  }
167 
168  /* Check packet content */
169  if ( memcmp ( iobuf->data, data, len ) != 0 ) {
170  printf ( "\nContent mismatch" );
171  DBG ( "\nSent:\n" );
172  DBG_HDA ( 0, data, len );
173  DBG ( "Received:\n" );
174  DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
175  free_iob ( iob_disown ( iobuf ) );
176  return -EINVAL;
177  }
178 
179  /* Discard packet and return */
180  free_iob ( iob_disown ( iobuf ) );
181  return 0;
182  }
183 }
184 
185 /**
186  * Perform loopback test between two network devices
187  *
188  * @v sender Sending network device
189  * @v receiver Received network device
190  * @v mtu Packet size (excluding link-layer headers)
191  * @v broadcast Use broadcast link-layer address
192  * @ret rc Return status code
193  */
194 int loopback_test ( struct net_device *sender, struct net_device *receiver,
195  size_t mtu, int broadcast ) {
196  uint8_t *buf;
197  uint32_t *seq;
198  struct io_buffer *iobuf;
199  const void *ll_dest;
200  unsigned int i;
201  unsigned int successes;
202  int rc;
203 
204  /* Open network devices */
205  if ( ( rc = ifopen ( sender ) ) != 0 )
206  return rc;
207  if ( ( rc = ifopen ( receiver ) ) != 0 )
208  return rc;
209 
210  /* Wait for link-up */
211  if ( ( rc = iflinkwait ( sender, 0 ) ) != 0 )
212  return rc;
213  if ( ( rc = iflinkwait ( receiver, 0 ) ) != 0 )
214  return rc;
215 
216  /* Allocate data buffer */
217  if ( mtu < sizeof ( *seq ) )
218  mtu = sizeof ( *seq );
219  buf = malloc ( mtu );
220  if ( ! buf )
221  return -ENOMEM;
222  seq = ( ( void * ) buf );
223 
224  /* Determine destination address */
225  ll_dest = ( broadcast ? sender->ll_broadcast : receiver->ll_addr );
226 
227  /* Print initial statistics */
228  printf ( "Performing %sloopback test from %s to %s with %zd byte MTU\n",
229  ( broadcast ? "broadcast " : "" ), sender->name,
230  receiver->name, mtu );
231  ifstat ( sender );
232  ifstat ( receiver );
233 
234  /* Start loopback test */
235  lotest_flush();
236  lotest_receiver = receiver;
237 
238  /* Perform loopback test */
239  for ( successes = 0 ; ; successes++ ) {
240 
241  /* Print running total */
242  printf ( "\r%d", successes );
243 
244  /* Generate random packet */
245  *seq = htonl ( successes );
246  for ( i = sizeof ( *seq ) ; i < mtu ; i++ )
247  buf[i] = random();
248  iobuf = alloc_iob ( MAX_LL_HEADER_LEN + mtu );
249  if ( ! iobuf ) {
250  printf ( "\nFailed to allocate I/O buffer" );
251  rc = -ENOMEM;
252  break;
253  }
254  iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
255  memcpy ( iob_put ( iobuf, mtu ), buf, mtu );
256 
257  /* Transmit packet */
258  if ( ( rc = net_tx ( iob_disown ( iobuf ), sender,
259  &lotest_protocol, ll_dest,
260  sender->ll_addr ) ) != 0 ) {
261  printf ( "\nFailed to transmit packet: %s",
262  strerror ( rc ) );
263  break;
264  }
265 
266  /* Wait for received packet */
267  if ( ( rc = loopback_wait ( buf, mtu ) ) != 0 )
268  break;
269  }
270 
271  printf ( "\n");
272 
273  /* Stop loopback testing */
275  lotest_flush();
276 
277  /* Dump final statistics */
278  ifstat ( sender );
279  ifstat ( receiver );
280 
281  /* Free buffer */
282  free ( buf );
283 
284  return 0;
285 }
#define EINVAL
Invalid argument.
Definition: errno.h:428
static struct net_device * lotest_receiver
Current loopback test receiver.
Definition: lotest.c:47
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
const char * name
Protocol name.
Definition: netdevice.h:66
#define iob_put(iobuf, len)
Definition: iobuf.h:116
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition: vsprintf.c:464
#define DBG_HDA(...)
Definition: compiler.h:499
void net_poll(void)
Poll the network stack.
Definition: netdevice.c:1052
Error codes.
I/O buffers.
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition: iobuf.c:145
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
static void lotest_flush(void)
Discard all received loopback test packets.
Definition: lotest.c:124
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition: iobuf.c:128
#define htonl(value)
Definition: byteswap.h:133
#define ECANCELED
Operation canceled.
Definition: errno.h:343
u16 seq
802.11 Sequence Control field
Definition: ieee80211.h:19
int loopback_test(struct net_device *sender, struct net_device *receiver, size_t mtu, int broadcast)
Perform loopback test between two network devices.
Definition: lotest.c:194
#define list_first_entry(list, type, member)
Get the container of the first entry in a list.
Definition: list.h:333
#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
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition: list.h:93
static LIST_HEAD(lotest_queue)
Loopback testing received packets.
static int loopback_wait(void *data, size_t len)
Wait for packet to be received.
Definition: lotest.c:138
static struct net_device * netdev
Definition: gdbudp.c:52
#define CTRL_C
Definition: keys.h:20
#define MAX_LL_HEADER_LEN
Maximum length of a link-layer header.
Definition: netdevice.h:45
static struct io_buffer * lotest_dequeue(void)
Dequeue received packet.
Definition: lotest.c:83
static int lotest_rx(struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, const void *ll_source __unused, unsigned int flags __unused)
Process received packet.
Definition: lotest.c:62
User interaction.
static const char * lotest_ntoa(const void *net_addr __unused)
Transcribe network-layer address.
Definition: lotest.c:101
int getchar(void)
Read a single character from any console.
Definition: console.c:82
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:151
A network device.
Definition: netdevice.h:348
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition: random.c:30
unsigned char uint8_t
Definition: stdint.h:10
unsigned int uint32_t
Definition: stdint.h:12
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
struct stp_switch sender
Sender switch.
Definition: stp.h:30
int ifopen(struct net_device *netdev)
Open network device.
Definition: ifmgmt.c:65
A network-layer protocol.
Definition: netdevice.h:64
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
char name[NETDEV_NAME_LEN]
Name of this network device.
Definition: netdevice.h:358
struct list_head list
List of which this buffer is a member.
Definition: iobuf.h:39
int net_tx(struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest, const void *ll_source)
Transmit network-layer packet.
Definition: netdevice.c:999
uint32_t len
Length.
Definition: ena.h:14
int iflinkwait(struct net_device *netdev, unsigned long timeout)
Wait for link-up, with status indication.
Definition: ifmgmt.c:216
uint32_t mtu
Maximum MTU.
Definition: ena.h:28
Key definitions.
void * data
Start of data.
Definition: iobuf.h:44
Loopback testing.
Network interface management.
void ifstat(struct net_device *netdev)
Print status of network device.
Definition: ifmgmt.c:110
struct arbelprm_port_state_change_st data
Message.
Definition: arbel.h:12
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
Definition: netdevice.h:381
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
static struct net_protocol lotest_protocol __net_protocol
Loopback test network-layer protocol.
Definition: lotest.c:112
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:113
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
String functions.
#define htons(value)
Definition: byteswap.h:135
int iskey(void)
Check for available input on any console.
Definition: console.c:127
A persistent I/O buffer.
Definition: iobuf.h:32
uint8_t flags
Flags.
Definition: ena.h:18