Sfoglia il codice sorgente

Network API now allows for multiple network devices (although the

implementation allows for only one, and does so without compromising on
the efficiency of static allocation).

Link-layer protocols are cleanly separated from the device drivers.

Network-layer protocols are cleanly separated from individual network
devices.

Link-layer and network-layer protocols are cleanly separated from each
other.
tags/v0.9.3
Michael Brown 18 anni fa
parent
commit
fdc2ee79db
8 ha cambiato i file con 732 aggiunte e 493 eliminazioni
  1. 112
    101
      src/drivers/net/pnic.c
  2. 7
    14
      src/include/gpxe/arp.h
  3. 248
    125
      src/include/gpxe/netdevice.h
  4. 17
    34
      src/include/gpxe/pkbuff.h
  5. 107
    84
      src/net/arp.c
  6. 69
    48
      src/net/ethernet.c
  7. 171
    86
      src/net/netdevice.c
  8. 1
    1
      src/proto/uip/uipopt.h

+ 112
- 101
src/drivers/net/pnic.c Vedi File

@@ -12,21 +12,21 @@ Bochs Pseudo NIC driver for Etherboot
12 12
  * See pnic_api.h for an explanation of the Bochs Pseudo NIC.
13 13
  */
14 14
 
15
-/* to get some global routines like printf */
16
-#include "etherboot.h"
17
-/* to get the interface to the body of the program */
18
-#include "nic.h"
19
-/* to get the PCI support functions, if this is a PCI NIC */
20
-#include "pci.h"
21
-
22
-/* PNIC API */
23
-#include "pnic_api.h"
15
+#include <stdint.h>
16
+#include <io.h>
17
+#include <vsprintf.h>
18
+#include <errno.h>
19
+#include <gpxe/pci.h>
20
+#include <gpxe/if_ether.h>
21
+#include <gpxe/ethernet.h>
22
+#include <gpxe/pkbuff.h>
23
+#include <gpxe/netdevice.h>
24 24
 
25
-/* Function prototypes */
26
-static int pnic_api_check ( uint16_t api_version );
25
+#include "pnic_api.h"
27 26
 
28
-/* NIC specific static variables go here */
29
-uint8_t tx_buffer[ETH_FRAME_LEN] __shared;
27
+struct pnic {
28
+	unsigned short ioaddr;
29
+};
30 30
 
31 31
 /* 
32 32
  * Utility functions: issue a PNIC command, retrieve result.  Use
@@ -40,7 +40,7 @@ uint8_t tx_buffer[ETH_FRAME_LEN] __shared;
40 40
  * of data).
41 41
  */
42 42
 
43
-static uint16_t pnic_command_quiet ( struct nic *nic, uint16_t command,
43
+static uint16_t pnic_command_quiet ( struct pnic *pnic, uint16_t command,
44 44
 				     void *input, uint16_t input_length,
45 45
 				     void *output, uint16_t output_max_length,
46 46
 				     uint16_t *output_length ) {
@@ -50,18 +50,19 @@ static uint16_t pnic_command_quiet ( struct nic *nic, uint16_t command,
50 50
 
51 51
 	if ( input != NULL ) {
52 52
 		/* Write input length */
53
-		outw ( input_length, nic->ioaddr + PNIC_REG_LEN );
53
+		outw ( input_length, pnic->ioaddr + PNIC_REG_LEN );
54 54
 		/* Write input data */
55 55
 		for ( i = 0; i < input_length; i++ ) {
56
-			outb( ((char*)input)[i], nic->ioaddr + PNIC_REG_DATA );
56
+			outb( ((char*)input)[i],
57
+			      pnic->ioaddr + PNIC_REG_DATA );
57 58
 		}
58 59
 	}
59 60
 	/* Write command */
60
-	outw ( command, nic->ioaddr + PNIC_REG_CMD );
61
+	outw ( command, pnic->ioaddr + PNIC_REG_CMD );
61 62
 	/* Retrieve status */
62
-	status = inw ( nic->ioaddr + PNIC_REG_STAT );
63
+	status = inw ( pnic->ioaddr + PNIC_REG_STAT );
63 64
 	/* Retrieve output length */
64
-	_output_length = inw ( nic->ioaddr + PNIC_REG_LEN );
65
+	_output_length = inw ( pnic->ioaddr + PNIC_REG_LEN );
65 66
 	if ( output_length == NULL ) {
66 67
 		if ( _output_length != output_max_length ) {
67 68
 			printf ( "pnic_command %#hx: wrong data length "
@@ -81,17 +82,17 @@ static uint16_t pnic_command_quiet ( struct nic *nic, uint16_t command,
81 82
 		/* Retrieve output data */
82 83
 		for ( i = 0; i < _output_length; i++ ) {
83 84
 			((char*)output)[i] =
84
-				inb ( nic->ioaddr + PNIC_REG_DATA );
85
+				inb ( pnic->ioaddr + PNIC_REG_DATA );
85 86
 		}
86 87
 	}
87 88
 	return status;
88 89
 }
89 90
 
90
-static uint16_t pnic_command ( struct nic *nic, uint16_t command,
91
+static uint16_t pnic_command ( struct pnic *pnic, uint16_t command,
91 92
 			       void *input, uint16_t input_length,
92 93
 			       void *output, uint16_t output_max_length,
93 94
 			       uint16_t *output_length ) {
94
-	uint16_t status = pnic_command_quiet ( nic, command,
95
+	uint16_t status = pnic_command_quiet ( pnic, command,
95 96
 					       input, input_length,
96 97
 					       output, output_max_length,
97 98
 					       output_length );
@@ -110,135 +111,134 @@ static int pnic_api_check ( uint16_t api_version ) {
110 111
 			 PNIC_API_VERSION >> 8, PNIC_API_VERSION & 0xff );
111 112
 	}
112 113
 	if ( api_version < PNIC_API_VERSION ) {
113
-		printf ( "*** You may need to update your copy of Bochs ***\n" );
114
+		printf ( "** You may need to update your copy of Bochs **\n" );
114 115
 	}
115 116
 	return ( api_version == PNIC_API_VERSION );
116 117
 }
117 118
 
118
-/**************************************************************************
119
-CONNECT - connect adapter to the network
120
-***************************************************************************/
121
-static int pnic_connect ( struct nic *nic __unused ) {
122
-	/* Nothing to do */
123
-	return 1;
124
-}
125
-
126 119
 /**************************************************************************
127 120
 POLL - Wait for a frame
128 121
 ***************************************************************************/
129
-static int pnic_poll ( struct nic *nic, int retrieve ) {
122
+static void pnic_poll ( struct net_device *netdev ) {
123
+	struct pnic *pnic = netdev->priv;
124
+	struct pk_buff *pkb;
130 125
 	uint16_t length;
131 126
 	uint16_t qlen;
132 127
 
133
-	/* Check receive queue length to see if there's anything to
134
-	 * get.  Necessary since once we've called PNIC_CMD_RECV we
135
-	 * have to read out the packet, otherwise it's lost forever.
136
-	 */
137
-	if ( pnic_command ( nic, PNIC_CMD_RECV_QLEN, NULL, 0,
138
-			    &qlen, sizeof(qlen), NULL )
139
-	     != PNIC_STATUS_OK ) return ( 0 );
140
-	if ( qlen == 0 ) return ( 0 );
141
-
142
-	/* There is a packet ready.  Return 1 if we're only checking. */
143
-	if ( ! retrieve ) return ( 1 );
144
-
145
-	/* Retrieve the packet */
146
-	if ( pnic_command ( nic, PNIC_CMD_RECV, NULL, 0,
147
-			    nic->packet, ETH_FRAME_LEN, &length )
148
-	     != PNIC_STATUS_OK ) return ( 0 );
149
-	nic->packetlen = length;
150
-	return ( 1 );
128
+	/* Fetch all available packets */
129
+	while ( 1 ) {
130
+		if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0,
131
+				    &qlen, sizeof ( qlen ), NULL )
132
+		     != PNIC_STATUS_OK )
133
+			break;
134
+		if ( qlen == 0 )
135
+			break;
136
+		pkb = alloc_pkb ( ETH_FRAME_LEN );
137
+		if ( ! pkb )
138
+			break;
139
+		if ( pnic_command ( pnic, PNIC_CMD_RECV, NULL, 0,
140
+				    pkb->data, ETH_FRAME_LEN, &length )
141
+		     != PNIC_STATUS_OK ) {
142
+			free_pkb ( pkb );
143
+			break;
144
+		}
145
+		pkb_put ( pkb, length );
146
+		netdev_rx ( netdev, pkb );
147
+	}
151 148
 }
152 149
 
153 150
 /**************************************************************************
154 151
 TRANSMIT - Transmit a frame
155 152
 ***************************************************************************/
156
-static void pnic_transmit ( struct nic *nic, const char *dest,
157
-			    unsigned int type, unsigned int size,
158
-			    const char *data ) {
159
-	unsigned int nstype = htons ( type );
160
-
161
-	if ( ( ETH_HLEN + size ) >= ETH_FRAME_LEN ) {
162
-		printf ( "pnic_transmit: packet too large\n" );
163
-		return;
164
-	}
153
+static int pnic_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
154
+	struct pnic *pnic = netdev->priv;
165 155
 
166
-	/* Assemble packet */
167
-	memcpy ( tx_buffer, dest, ETH_ALEN );
168
-	memcpy ( tx_buffer + ETH_ALEN, nic->node_addr, ETH_ALEN );
169
-	memcpy ( tx_buffer + 2 * ETH_ALEN, &nstype, 2 );
170
-	memcpy ( tx_buffer + ETH_HLEN, data, size );
171
-
172
-	pnic_command ( nic, PNIC_CMD_XMIT, tx_buffer, ETH_HLEN + size,
156
+	pnic_command ( pnic, PNIC_CMD_XMIT, pkb, pkb_len ( pkb ),
173 157
 		       NULL, 0, NULL );
174
-}
175
-
176
-/**************************************************************************
177
-DISABLE - Turn off ethernet interface
178
-***************************************************************************/
179
-static void pnic_disable ( struct nic *nic, struct pci_device *pci __unused ) {
180
-	nic_disable ( nic );
181
-	pnic_command ( nic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL );
158
+	free_pkb ( pkb );
159
+	return 0;
182 160
 }
183 161
 
184 162
 /**************************************************************************
185 163
 IRQ - Handle card interrupt status
186 164
 ***************************************************************************/
187
-static void pnic_irq ( struct nic *nic, irq_action_t action ) {
165
+#if 0
166
+static void pnic_irq ( struct net_device *netdev, irq_action_t action ) {
167
+	struct pnic *pnic = netdev->priv;
188 168
 	uint8_t enabled;
189 169
 
190 170
 	switch ( action ) {
191 171
 	case DISABLE :
192 172
 	case ENABLE :
193 173
 		enabled = ( action == ENABLE ? 1 : 0 );
194
-		pnic_command ( nic, PNIC_CMD_MASK_IRQ,
195
-			       &enabled, sizeof(enabled), NULL, 0, NULL );
174
+		pnic_command ( pnic, PNIC_CMD_MASK_IRQ,
175
+			       &enabled, sizeof ( enabled ), NULL, 0, NULL );
196 176
 		break;
197 177
 	case FORCE :
198
-		pnic_command ( nic, PNIC_CMD_FORCE_IRQ,
178
+		pnic_command ( pnic, PNIC_CMD_FORCE_IRQ,
199 179
 			       NULL, 0, NULL, 0, NULL );
200 180
 		break;
201 181
 	}
202 182
 }
183
+#endif
203 184
 
204 185
 /**************************************************************************
205
-NIC operations table
186
+DISABLE - Turn off ethernet interface
206 187
 ***************************************************************************/
207
-static struct nic_operations pnic_operations = {
208
-	.connect	= pnic_connect,
209
-	.poll		= pnic_poll,
210
-	.transmit	= pnic_transmit,
211
-	.irq		= pnic_irq,
212
-};
188
+static void pnic_remove ( struct pci_device *pci ) {
189
+	struct net_device *netdev = pci_get_drvdata ( pci );
190
+	struct pnic *pnic = netdev->priv;
191
+
192
+	unregister_netdev ( netdev );
193
+	pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL );
194
+}
213 195
 
214 196
 /**************************************************************************
215 197
 PROBE - Look for an adapter, this routine's visible to the outside
216 198
 ***************************************************************************/
217
-static int pnic_probe ( struct nic *nic, struct pci_device *pci ) {
199
+static int pnic_probe ( struct pci_device *pci ) {
200
+	struct net_device *netdev;
201
+	struct pnic *pnic;
218 202
 	uint16_t api_version;
219 203
 	uint16_t status;
204
+	int rc;
220 205
 
221
-	/* Retrieve relevant information about PCI device */
222
-	pci_fill_nic ( nic, pci );
206
+	/* Allocate net device */
207
+	netdev = alloc_etherdev ( sizeof ( *pnic ) );
208
+	if ( ! netdev ) {
209
+		rc = -ENOMEM;
210
+		goto err;
211
+	}
212
+	pnic = netdev->priv;
213
+	pci_set_drvdata ( pci, netdev );
214
+	pnic->ioaddr = pci->ioaddr;
223 215
 
224 216
 	/* API version check */
225
-	status = pnic_command_quiet( nic, PNIC_CMD_API_VER, NULL, 0,
226
-				     &api_version,
227
-				     sizeof(api_version), NULL );
217
+	status = pnic_command_quiet ( pnic, PNIC_CMD_API_VER, NULL, 0,
218
+				      &api_version,
219
+				      sizeof ( api_version ), NULL );
228 220
 	if ( status != PNIC_STATUS_OK ) {
229 221
 		printf ( "PNIC failed installation check, code %#hx\n",
230 222
 			 status );
231
-		return 0;
223
+		rc = -EIO;
224
+		goto err;
232 225
 	}
233
-	pnic_api_check(api_version);
226
+	pnic_api_check ( api_version );
234 227
 
235 228
 	/* Get MAC address */
236
-	status = pnic_command ( nic, PNIC_CMD_READ_MAC, NULL, 0,
237
-				nic->node_addr, ETH_ALEN, NULL );
229
+	status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0,
230
+				netdev->ll_addr, ETH_ALEN, NULL );
231
+
232
+	/* Point to NIC specific routines */
233
+	netdev->poll	 = pnic_poll;
234
+	netdev->transmit = pnic_transmit;
235
+
236
+	return 0;
238 237
 
239
-	/* point to NIC specific routines */
240
-	nic->nic_op	= &pnic_operations;
241
-	return 1;
238
+ err:
239
+	/* Free net device */
240
+	free_netdev ( netdev );
241
+	return rc;
242 242
 }
243 243
 
244 244
 static struct pci_id pnic_nics[] = {
@@ -246,7 +246,18 @@ static struct pci_id pnic_nics[] = {
246 246
 PCI_ROM ( 0xfefe, 0xefef, "pnic", "Bochs Pseudo NIC Adaptor" ),
247 247
 };
248 248
 
249
-PCI_DRIVER ( pnic_driver, pnic_nics, PCI_NO_CLASS );
249
+static struct pci_driver pnic_driver = {
250
+	.ids = pnic_nics,
251
+	.id_count = ( sizeof ( pnic_nics ) / sizeof ( pnic_nics[0] ) ),
252
+	.class = PCI_NO_CLASS,
253
+	//	.probe = pnic_probe,
254
+	//	.remove = pnic_remove,
255
+};
256
+
257
+// PCI_DRIVER ( pnic_driver );
258
+
259
+#include "dev.h"
260
+extern struct type_driver test_driver;
250 261
 
251
-DRIVER ( "PNIC", nic_driver, pci_driver, pnic_driver,
252
-	 pnic_probe, pnic_disable );
262
+DRIVER ( "PNIC", test_driver, pci_driver, pnic_driver,
263
+	 pnic_probe, pnic_remove );

+ 7
- 14
src/include/gpxe/arp.h Vedi File

@@ -1,5 +1,5 @@
1
-#ifndef _ARP_H
2
-#define _ARP_H
1
+#ifndef _GPXE_ARP_H
2
+#define _GPXE_ARP_H
3 3
 
4 4
 /** @file
5 5
  *
@@ -7,17 +7,10 @@
7 7
  *
8 8
  */
9 9
 
10
-struct net_device;
11
-struct net_interface;
12
-struct pk_buff;
10
+struct net_header;
11
+struct ll_header;
13 12
 
14
-extern int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
15
-			 const void **ll_addr );
13
+extern int arp_resolve ( const struct net_header *nethdr,
14
+			 struct ll_header *llhdr );
16 15
 
17
-extern int arp_process ( struct net_interface *arp_netif,
18
-			 struct pk_buff *pkb );
19
-
20
-extern int arp_add_generic_header ( struct net_interface *arp_netif,
21
-				    struct pk_buff *pkb );
22
-
23
-#endif /* _ARP_H */
16
+#endif /* _GPXE_ARP_H */

+ 248
- 125
src/include/gpxe/netdevice.h Vedi File

@@ -1,203 +1,326 @@
1
-#ifndef _NETDEVICE_H
2
-#define _NETDEVICE_H
1
+#ifndef _GPXE_NETDEVICE_H
2
+#define _GPXE_NETDEVICE_H
3 3
 
4 4
 /** @file
5 5
  *
6
- * Network device and network interface
6
+ * Network device management
7 7
  *
8 8
  */
9 9
 
10 10
 #include <stdint.h>
11
-#include <gpxe/list.h>
11
+#include <gpxe/tables.h>
12 12
 
13
-struct net_device;
14
-struct net_interface;
15 13
 struct pk_buff;
14
+struct net_protocol;
15
+struct ll_protocol;
16 16
 
17 17
 /** Maximum length of a link-layer address */
18
-#define MAX_LLH_ADDR_LEN 6
18
+#define MAX_LL_ADDR_LEN 6
19 19
 
20 20
 /** Maximum length of a network-layer address */
21 21
 #define MAX_NET_ADDR_LEN 4
22 22
 
23
+/* Network-layer address may be required to hold a link-layer address
24
+ * (if NETADDR_FL_RAW is set
25
+ */
26
+#if MAX_NET_ADDR_LEN < MAX_LL_ADDR_LEN
27
+#undef MAX_NET_ADDR_LEN
28
+#define MAX_NET_ADDR_LEN MAX_LL_ADDR_LEN
29
+#endif
30
+
31
+/** A generic network-layer header */
32
+struct net_header {
33
+	/** Network-layer protocol */
34
+	struct net_protocol *net_protocol;
35
+	/** Destination address flags
36
+	 *
37
+	 * This is the bitwise OR of zero or more NETADDR_FL_XXX
38
+	 * values.
39
+	 */
40
+	int dest_flags;
41
+	/** Network-layer destination address */
42
+	uint8_t dest_net_addr[MAX_NET_ADDR_LEN];
43
+	/** Network-layer source address */
44
+	uint8_t source_net_addr[MAX_NET_ADDR_LEN];
45
+};
46
+
47
+/** Address is a broadcast address */
48
+#define NETADDR_FL_BROADCAST 0x01
49
+
50
+/** Address is a multicast address */
51
+#define NETADDR_FL_MULTICAST 0x02
52
+
53
+/** Address is a raw hardware address */
54
+#define NETADDR_FL_RAW 0x04
55
+
56
+/** A generic link-layer header */
57
+struct ll_header {
58
+	/** Link-layer protocol */
59
+	struct ll_protocol *ll_protocol;
60
+	/** Destination address flags
61
+	 *
62
+	 * This is the bitwise OR of zero or more NETADDR_FL_XXX
63
+	 * values.
64
+	 */
65
+	int dest_flags;
66
+	/** Link-layer destination address */
67
+	uint8_t dest_ll_addr[MAX_LL_ADDR_LEN];
68
+	/** Link-layer source address */
69
+	uint8_t source_ll_addr[MAX_LL_ADDR_LEN];
70
+	/** Network-layer protocol
71
+	 *
72
+	 *
73
+	 * This is an ETH_P_XXX constant, in network-byte order
74
+	 */
75
+	uint16_t net_proto;
76
+};
77
+
23 78
 /**
24
- * A network device
25
- *
26
- * This structure represents a piece of networking hardware.  It has
27
- * properties such as a link-layer address and methods for
28
- * transmitting and receiving raw packets.  It does not know anything
29
- * about network-layer protocols (e.g. IP) or their addresses; these
30
- * are handled by struct @c net_interface instead.
79
+ * A network-layer protocol
31 80
  *
32
- * Note that this structure must represent a generic network device,
33
- * not just an Ethernet device.
34 81
  */
35
-struct net_device {
36
-	/** Transmit packet
82
+struct net_protocol {
83
+	/**
84
+	 * Perform network-layer routing
37 85
 	 *
38
-	 * @v netdev	Network device
39 86
 	 * @v pkb	Packet buffer
87
+	 * @ret source	Network-layer source address
88
+	 * @ret dest	Network-layer destination address
40 89
 	 * @ret rc	Return status code
41 90
 	 *
42
-	 * This method should cause the hardware to initiate
43
-	 * transmission of the packet buffer.  The buffer may be
44
-	 * reused immediately after the method returns, and so the
45
-	 * method should either wait for packet transmission to
46
-	 * complete, or take a copy of the buffer contents.
91
+	 * This method should fill in the source and destination
92
+	 * addresses with enough information to allow the link layer
93
+	 * to route the packet.
94
+	 *
95
+	 * For example, in the case of IPv4, this method should fill
96
+	 * in @c source with the IP addresses of the local adapter and
97
+	 * @c dest with the next hop destination (e.g. the gateway).
47 98
 	 */
48
-	int ( * transmit ) ( struct net_device *netdev,
49
-			     struct pk_buff *pkb );
50
-	/** Poll for received packet
99
+	int ( * route ) ( const struct pk_buff *pkb,
100
+			  struct net_header *nethdr );
101
+	/**
102
+	 * Handle received packets
51 103
 	 *
52
-	 * @v netdev	Network device
53
-	 * @v pkb	Packet buffer to contain received packet
104
+	 * @v pkb	Packet buffer
54 105
 	 * @ret rc	Return status code
55 106
 	 *
56
-	 * This method should cause the hardware to check for a
57
-	 * received packet.  If no packet is available, the method
58
-	 * should return -EAGAIN (i.e. this method is *always*
59
-	 * considered to be a non-blocking read).  If a packet is
60
-	 * available, the method should fill the packet buffer and
61
-	 * return zero for success.
107
+	 * If this method returns success, it has taken ownership of
108
+	 * the packet buffer.
62 109
 	 */
63
-	int ( * poll ) ( struct net_device *netdev, struct pk_buff *pkb );
64
-	/** Build link-layer header
110
+	int ( * rx ) ( struct pk_buff *pkb );
111
+	/** Network-layer protocol
65 112
 	 *
66
-	 * @v netdev	Network device
67
-	 * @v pkb	Packet buffer
113
+	 * This is an ETH_P_XXX constant, in network-byte order
114
+	 */
115
+	uint16_t net_proto;
116
+	/** Network-layer address length */
117
+	uint8_t net_addr_len;
118
+};
119
+
120
+/**
121
+ * A link-layer protocol
122
+ *
123
+ */
124
+struct ll_protocol {
125
+	/**
126
+	 * Perform link-layer routing
127
+	 *
128
+	 * @v nethdr	Generic network-layer header
129
+	 * @ret llhdr	Generic link-layer header
68 130
 	 * @ret rc	Return status code
69 131
 	 *
70
-	 * This method should fill in the link-layer header based on
71
-	 * the metadata contained in @c pkb.
132
+	 * This method should construct the generic link-layer header
133
+	 * based on the generic network-layer header.
72 134
 	 *
73 135
 	 * If a link-layer header cannot be constructed (e.g. because
74 136
 	 * of a missing ARP cache entry), then this method should
75 137
 	 * return an error (after transmitting an ARP request, if
76 138
 	 * applicable).
77 139
 	 */
78
-	int ( * build_llh ) ( struct net_device *netdev, struct pk_buff *pkb );
79
-	/** Parse link-layer header
140
+	int ( * route ) ( const struct net_header *nethdr,
141
+			  struct ll_header *llhdr );
142
+	/**
143
+	 * Fill media-specific link-layer header
80 144
 	 *
81
-	 * @v netdev	Network device
145
+	 * @v llhdr	Generic link-layer header
82 146
 	 * @v pkb	Packet buffer
83
-	 * @ret rc	Return status code
84 147
 	 *
85
-	 * This method should parse the link-layer header and fill in
86
-	 * the metadata in @c pkb.
148
+	 * This method should fill in the link-layer header in the
149
+	 * packet buffer based on information in the generic
150
+	 * link-layer header.
151
+	 */
152
+	void ( * fill_llh ) ( const struct ll_header *llhdr,
153
+			      struct pk_buff *pkb );
154
+	/**
155
+	 * Parse media-specific link-layer header
156
+	 *
157
+	 * @v pkb	Packet buffer
158
+	 * @v llhdr	Generic link-layer header
159
+	 *
160
+	 * This method should fill in the generic link-layer header
161
+	 * based on information in the link-layer header in the packet
162
+	 * buffer.
87 163
 	 */
88
-	int ( * parse_llh ) ( struct net_device *netdev, struct pk_buff *pkb );
164
+	void ( * parse_llh ) ( const struct pk_buff *pkb,
165
+			       struct ll_header *llhdr );
166
+
89 167
 	/** Link-layer protocol
90 168
 	 *
91 169
 	 * This is an ARPHRD_XXX constant, in network byte order.
92 170
 	 */
93 171
 	uint16_t ll_proto;
94
-	/** Link-layer header length */
95
-	uint8_t ll_hlen;
96 172
 	/** Link-layer address length */
97 173
 	uint8_t ll_addr_len;
98
-	/** Link-layer address
99
-	 *
100
-	 * For Ethernet, this is the MAC address.
101
-	 */
102
-	uint8_t ll_addr[MAX_LLH_ADDR_LEN];
103
-	/** Linked list of network devices */
104
-	struct list_head devices;
105
-	/** List of network interfaces */
106
-	struct list_head interfaces;
107
-	/** Driver private data */
108
-	void *priv;
174
+	/** Link-layer header length */
175
+	uint8_t ll_header_len;
109 176
 };
110 177
 
111 178
 /**
112
- * A network interface
113
- *
114
- * This structure represents a particular network layer protocol's
115
- * interface to a piece of network hardware (a struct @c net_device).
179
+ * A network-layer address assigned to a network device
116 180
  *
117 181
  */
118
-struct net_interface {
119
-	/** Underlying net device */
120
-	struct net_device *netdev;
121
-	/** Linked list of interfaces for this device */
122
-	struct list_head interfaces;
123
-	/** Network-layer protocol
124
-	 *
125
-	 * This is an ETH_P_XXX constant, in network byte order.
126
-	 */
127
-	uint16_t net_proto;
128
-	/** Network-layer address length */
129
-	uint8_t net_addr_len;
182
+struct net_address {
183
+	/** Network-layer protocol */
184
+	struct net_protocol *net_protocol;
130 185
 	/** Network-layer address */
131 186
 	uint8_t net_addr[MAX_NET_ADDR_LEN];
132
-	/** Fill in packet metadata
187
+};
188
+
189
+/**
190
+ * A network device
191
+ *
192
+ * This structure represents a piece of networking hardware.  It has
193
+ * properties such as a link-layer address and methods for
194
+ * transmitting and receiving raw packets.
195
+ *
196
+ * Note that this structure must represent a generic network device,
197
+ * not just an Ethernet device.
198
+ */
199
+struct net_device {
200
+	/** Transmit packet
133 201
 	 *
134
-	 * @v netif	Network interface
202
+	 * @v netdev	Network device
135 203
 	 * @v pkb	Packet buffer
136 204
 	 * @ret rc	Return status code
137 205
 	 *
138
-	 * This method should fill in the @c pkb metadata with enough
139
-	 * information to enable net_device::build_llh to construct
140
-	 * the link-layer header.
206
+	 * This method should cause the hardware to initiate
207
+	 * transmission of the packet buffer.
208
+	 *
209
+	 * If the method returns success, ownership of the packet
210
+	 * buffer is transferred to the @c net_device, which must
211
+	 * eventually call free_pkb() to release the buffer.
141 212
 	 */
142
-	int ( * add_llh_metadata ) ( struct net_interface *netif,
143
-				     struct pk_buff *pkb );
144
-	/** Received packet processor
213
+	int ( * transmit ) ( struct net_device *netdev, struct pk_buff *pkb );
214
+	/** Poll for received packet
145 215
 	 *
146
-	 * @v netif	Network interface
147
-	 * @v pkb	Packet buffer
148
-	 * @ret rc	Return status code
216
+	 * @v netdev	Network device
149 217
 	 *
150
-	 * This method is called for packets arriving on the
151
-	 * associated network device that match this interface's
152
-	 * network-layer protocol.
218
+	 * This method should cause the hardware to check for received
219
+	 * packets.  Any received packets should be delivered via
220
+	 * netdev_rx().
221
+	 */
222
+	void ( * poll ) ( struct net_device *netdev );
223
+
224
+	/** Link-layer protocol */
225
+	struct ll_protocol *ll_protocol;
226
+	/** Link-layer address
153 227
 	 *
154
-	 * When this method is called, the link-layer header will
155
-	 * already have been stripped from the packet.
228
+	 * For Ethernet, this is the MAC address.
156 229
 	 */
157
-	int ( * rx_packet ) ( struct net_interface *netif,
158
-			      struct pk_buff *pkb );
230
+	uint8_t ll_addr[MAX_LL_ADDR_LEN];
231
+
232
+	/** Driver private data */
233
+	void *priv;
159 234
 };
160 235
 
236
+extern struct net_device static_single_netdev;
237
+
238
+/**
239
+ * Allocate network device
240
+ *
241
+ * @v priv_size		Size of private data area (net_device::priv)
242
+ * @ret netdev		Network device, or NULL
243
+ *
244
+ * Allocates space for a network device and its private data area.
245
+ *
246
+ * This macro allows for a very efficient implementation in the case
247
+ * of a single static network device; it neatly avoids dynamic
248
+ * allocation and can never return failure, meaning that the failure
249
+ * path will be optimised away.  However, driver writers should not
250
+ * rely on this feature; the drivers should be written to allow for
251
+ * multiple instances of network devices.
252
+ */
253
+#define alloc_netdev( priv_size ) ( {		\
254
+	static char priv_data[priv_size];	\
255
+	static_single_netdev.priv = priv_data;	\
256
+	&static_single_netdev; } )
257
+
161 258
 /**
162
- * Find interface for a specific protocol
259
+ * Register network device
163 260
  *
164
- * @v netdev	Network device
165
- * @v net_proto	Network-layer protocol, in network byte order
166
- * @ret netif	Network interface, or NULL if none found
261
+ * @v netdev		Network device
262
+ * @ret rc		Return status code
167 263
  *
264
+ * Adds the network device to the list of network devices.
168 265
  */
169
-static inline struct net_interface *
170
-netdev_find_netif ( const struct net_device *netdev, uint16_t net_proto ) {
171
-	struct net_interface *netif;
172
-
173
-	list_for_each_entry ( netif, &netdev->interfaces, interfaces ) {
174
-		if ( netif->net_proto == net_proto )
175
-			return netif;
176
-	}
177
-	return NULL;
266
+static inline int
267
+register_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
268
+	return 0;
178 269
 }
179 270
 
180
-extern int register_netdevice ( struct net_device *netdev );
181
-extern void unregister_netdevice ( struct net_device *netdev );
182
-extern int netdev_send ( struct net_device *netdev, struct pk_buff *pkb );
183
-extern int netdev_poll ( struct net_device *netdev, struct pk_buff *pkb );
184
-extern int netif_send ( struct net_interface *netif, struct pk_buff *pkb );
185
-extern int netdev_rx_packet ( struct net_device *netdev, struct pk_buff *pkb );
186
-extern int net_poll ( struct pk_buff *pkb, struct net_device **netdev );
271
+/**
272
+ * Unregister network device
273
+ *
274
+ * @v netdev		Network device
275
+ *
276
+ * Removes the network device from the list of network devices.
277
+ */
278
+static inline void 
279
+unregister_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
280
+	/* Nothing to do */
281
+}
187 282
 
283
+/**
284
+ * Free network device
285
+ *
286
+ * @v netdev		Network device
287
+ */
288
+static inline void
289
+free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
290
+	/* Nothing to do */
291
+}
188 292
 
293
+/**
294
+ * Register a link-layer protocol
295
+ *
296
+ * @v protocol		Link-layer protocol
297
+ */
298
+#define LL_PROTOCOL( protocol ) \
299
+	struct ll_protocol protocol __table ( ll_protocols, 00 )
189 300
 
190
-extern struct net_device static_single_netdev;
301
+/**
302
+ * Register a network-layer protocol
303
+ *
304
+ * @v protocol		Network-layer protocol
305
+ */
306
+#define NET_PROTOCOL( protocol ) \
307
+	struct net_protocol protocol __table ( net_protocols, 00 )
191 308
 
192
-/* Must be a macro because priv_data[] is of variable size */
193
-#define alloc_netdevice( priv_size ) ( {		\
194
-	static char priv_data[priv_size];		\
195
-	static_single_netdev.priv = priv_data;	\
196
-	&static_single_netdev; } )
309
+/**
310
+ * Register a network-layer address for the static single network device
311
+ *
312
+ * @v net_address	Network-layer address
313
+ */
314
+#define STATIC_SINGLE_NETDEV_ADDRESS( address ) \
315
+	struct net_address address __table ( sgl_netdev_addresses, 00 )
197 316
 
317
+extern struct net_protocol *net_find_protocol ( uint16_t net_proto );
318
+extern struct net_device * net_find_address ( struct net_protocol *net_proto,
319
+					      void *net_addr );
198 320
 
199
-static inline void free_netdevice ( struct net_device *netdev __unused ) {
200
-	/* Do nothing */
201
-}
321
+extern int net_transmit ( struct pk_buff *pkb );
322
+extern int net_poll ( void );
323
+extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
324
+extern struct pk_buff * net_rx_dequeue ( void );
202 325
 
203
-#endif /* _NETDEVICE_H */
326
+#endif /* _GPXE_NETDEVICE_H */

+ 17
- 34
src/include/gpxe/pkbuff.h Vedi File

@@ -1,5 +1,5 @@
1
-#ifndef _PKBUFF_H
2
-#define _PKBUFF_H
1
+#ifndef _GPXE_PKBUFF_H
2
+#define _GPXE_PKBUFF_H
3 3
 
4 4
 /** @file
5 5
  *
@@ -12,6 +12,10 @@
12 12
 
13 13
 #include <stdint.h>
14 14
 #include <assert.h>
15
+#include <gpxe/list.h>
16
+
17
+struct net_protocol;
18
+struct ll_protocol;
15 19
 
16 20
 /** A packet buffer
17 21
  *
@@ -27,38 +31,14 @@ struct pk_buff {
27 31
 	/** End of the buffer */
28 32
         void *end;
29 33
 
30
-	/** The network-layer protocol
31
-	 *
32
-	 * This is the network-layer protocol expressed as an
33
-	 * ETH_P_XXX constant, in network-byte order.
34
-	 */
35
-	uint16_t net_proto;
36
-	/** Flags
37
-	 *
38
-	 * Filled in only on outgoing packets.  Value is the
39
-	 * bitwise-OR of zero or more PKB_FL_XXX constants.
40
-	 */
41
-	uint8_t flags;
42
-	/** Network-layer address length 
43
-	 *
44
-	 * Filled in only on outgoing packets.
45
-	 */
46
-	uint8_t net_addr_len;
47
-	/** Network-layer address
48
-	 *
49
-	 * Filled in only on outgoing packets.
50
-	 */
51
-	void *net_addr;
52
-};
53
-
54
-/** Packet is a broadcast packet */
55
-#define PKB_FL_BROADCAST 0x01
34
+	/** List of which this buffer is a member */
35
+	struct list_head list;
56 36
 
57
-/** Packet is a multicast packet */
58
-#define PKB_FL_MULTICAST 0x02
59
-
60
-/** Network-layer address is a raw hardware address */
61
-#define PKB_FL_RAW_NET_ADDR 0x04
37
+	/** The network-layer protocol */
38
+	struct net_protocol *net_protocol;
39
+	/** The link-layer protocol */
40
+	struct ll_protocol *ll_protocol;
41
+};
62 42
 
63 43
 /**
64 44
  * Add data to start of packet buffer
@@ -130,4 +110,7 @@ static inline size_t pkb_len ( struct pk_buff *pkb ) {
130 110
 	return ( pkb->tail - pkb->data );
131 111
 }
132 112
 
133
-#endif /* _PKBUFF_H */
113
+extern struct pk_buff * alloc_pkb ( size_t len );
114
+extern void free_pkb ( struct pk_buff *pkb );
115
+
116
+#endif /* _GPXE_PKBUFF_H */

+ 107
- 84
src/net/arp.c Vedi File

@@ -39,13 +39,13 @@
39 39
 /** An ARP cache entry */
40 40
 struct arp_entry {
41 41
 	/** Network-layer protocol */
42
-	uint16_t net_proto;
42
+	struct net_protocol *net_protocol;
43 43
 	/** Link-layer protocol */
44
-	uint16_t ll_proto;
44
+	struct ll_protocol *ll_protocol;
45 45
 	/** Network-layer address */
46 46
 	uint8_t net_addr[MAX_NET_ADDR_LEN];
47 47
 	/** Link-layer address */
48
-	uint8_t ll_addr[MAX_LLH_ADDR_LEN];
48
+	uint8_t ll_addr[MAX_LL_ADDR_LEN];
49 49
 };
50 50
 
51 51
 /** Number of entries in the ARP cache
@@ -61,25 +61,28 @@ static struct arp_entry arp_table[NUM_ARP_ENTRIES];
61 61
 
62 62
 static unsigned int next_new_arp_entry = 0;
63 63
 
64
+struct net_protocol arp_protocol;
65
+
64 66
 /**
65 67
  * Find entry in the ARP cache
66 68
  *
67
- * @v ll_proto		Link-layer protocol
68
- * @v net_proto		Network-layer protocol
69
+ * @v ll_protocol	Link-layer protocol
70
+ * @v net_protocol	Network-layer protocol
69 71
  * @v net_addr		Network-layer address
70
- * @v net_addr_len	Network-layer address length
71 72
  * @ret arp		ARP cache entry, or NULL if not found
72 73
  *
73 74
  */
74 75
 static struct arp_entry *
75
-arp_find_entry ( uint16_t ll_proto, uint16_t net_proto, const void *net_addr,
76
-		 size_t net_addr_len ) {
76
+arp_find_entry ( struct ll_protocol *ll_protocol,
77
+		 struct net_protocol *net_protocol,
78
+		 const void *net_addr ) {
77 79
 	struct arp_entry *arp;
78 80
 
79 81
 	for ( arp = arp_table ; arp < arp_table_end ; arp++ ) {
80
-		if ( ( arp->ll_proto == ll_proto ) &&
81
-		     ( arp->net_proto == net_proto ) &&
82
-		     ( memcmp ( arp->net_addr, net_addr, net_addr_len ) == 0 ))
82
+		if ( ( arp->ll_protocol == ll_protocol ) &&
83
+		     ( arp->net_protocol == net_protocol ) &&
84
+		     ( memcmp ( arp->net_addr, net_addr,
85
+				net_protocol->net_addr_len ) == 0 ) )
83 86
 			return arp;
84 87
 	}
85 88
 	return NULL;
@@ -88,59 +91,64 @@ arp_find_entry ( uint16_t ll_proto, uint16_t net_proto, const void *net_addr,
88 91
 /**
89 92
  * Look up media-specific link-layer address in the ARP cache
90 93
  *
91
- * @v netdev		Network device
92
- * @v pkb		Packet buffer
93
- * @ret ll_addr		Pointer to link-layer address
94
+ * @v nethdr		Generic network-layer header
95
+ * @ret llhdr		Generic link-layer header
94 96
  * @ret rc		Return status code
95 97
  *
96 98
  * This function will use the ARP cache to look up the link-layer
97
- * address for the media corresponding to @c netdev and the
98
- * network-layer address as specified in the @c pkb metadata.
99
+ * address for the link-layer protocol specified in @c llhdr and the
100
+ * network-layer protocol and address as specified in @c nethdr.  If
101
+ * found, the destination link-layer address will be filled in in @c
102
+ * llhdr.
99 103
  *
100 104
  * If no address is found in the ARP cache, an ARP request will be
101
- * transmitted, -ENOENT will be returned, and the packet buffer
102
- * contents will be undefined.
105
+ * transmitted and -ENOENT will be returned.
103 106
  */
104
-int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
105
-		  const void **ll_addr ) {
107
+int arp_resolve ( const struct net_header *nethdr, struct ll_header *llhdr ) {
108
+	struct net_protocol *net_protocol = nethdr->net_protocol;
109
+	struct ll_protocol *ll_protocol = llhdr->ll_protocol;
106 110
 	const struct arp_entry *arp;
107
-	struct net_interface *netif;
111
+	struct pk_buff *pkb;
108 112
 	struct arphdr *arphdr;
113
+	int rc;
109 114
 
110 115
 	/* Look for existing entry in ARP table */
111
-	arp = arp_find_entry ( netdev->ll_proto, pkb->net_proto,
112
-			       pkb->net_addr, pkb->net_addr_len );
116
+	arp = arp_find_entry ( ll_protocol, net_protocol,
117
+			       nethdr->dest_net_addr );
113 118
 	if ( arp ) {
114
-		*ll_addr = arp->ll_addr;
119
+		memcpy ( llhdr->dest_ll_addr, arp->ll_addr,
120
+			 sizeof ( llhdr->dest_ll_addr ) );
115 121
 		return 0;
116 122
 	}
117 123
 
118
-	/* Find interface for this protocol */
119
-	netif = netdev_find_netif ( netdev, pkb->net_proto );
120
-	if ( ! netif )
121
-		return -EAFNOSUPPORT;
124
+	/* Allocate ARP packet */
125
+	pkb = alloc_pkb ( sizeof ( *arphdr ) +
126
+			  2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
127
+	if ( ! pkb )
128
+		return -ENOMEM;
129
+	pkb->net_protocol = &arp_protocol;
122 130
 
123 131
 	/* Build up ARP request */
124
-	pkb_empty ( pkb );
125 132
 	arphdr = pkb_put ( pkb, sizeof ( *arphdr ) );
126
-	arphdr->ar_hrd = netdev->ll_proto;
127
-	arphdr->ar_hln = netdev->ll_addr_len;
128
-	arphdr->ar_pro = pkb->net_proto;
129
-	arphdr->ar_pln = pkb->net_addr_len;
133
+	arphdr->ar_hrd = ll_protocol->ll_proto;
134
+	arphdr->ar_hln = ll_protocol->ll_addr_len;
135
+	arphdr->ar_pro = net_protocol->net_proto;
136
+	arphdr->ar_pln = net_protocol->net_addr_len;
130 137
 	arphdr->ar_op = htons ( ARPOP_REQUEST );
131
-	memcpy ( pkb_put ( pkb, netdev->ll_addr_len ),
132
-		 netdev->ll_addr, netdev->ll_addr_len );
133
-	memcpy ( pkb_put ( pkb, netif->net_addr_len ),
134
-		 netif->net_addr, netif->net_addr_len );
135
-	memset ( pkb_put ( pkb, netdev->ll_addr_len ),
136
-		 0xff, netdev->ll_addr_len );
137
-	memcpy ( pkb_put ( pkb, netif->net_addr_len ),
138
-		 pkb->net_addr, netif->net_addr_len );
139
-
140
-	/* Locate ARP interface and send ARP request */
141
-	netif = netdev_find_netif ( netdev, htons ( ETH_P_ARP ) );
142
-	assert ( netif != NULL );
143
-	netif_send ( netif, pkb );
138
+	memcpy ( pkb_put ( pkb, ll_protocol->ll_addr_len ),
139
+		 llhdr->source_ll_addr, ll_protocol->ll_addr_len );
140
+	memcpy ( pkb_put ( pkb, net_protocol->net_addr_len ),
141
+		 nethdr->source_net_addr, net_protocol->net_addr_len );
142
+	memset ( pkb_put ( pkb, ll_protocol->ll_addr_len ),
143
+		 0, ll_protocol->ll_addr_len );
144
+	memcpy ( pkb_put ( pkb, net_protocol->net_addr_len ),
145
+		 nethdr->dest_net_addr, net_protocol->net_addr_len );
146
+
147
+	/* Transmit ARP request */
148
+	if ( ( rc = net_transmit ( pkb ) ) != 0 ) {
149
+		free_pkb ( pkb );
150
+		return rc;
151
+	}
144 152
 
145 153
 	return -ENOENT;
146 154
 }
@@ -148,7 +156,6 @@ int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
148 156
 /**
149 157
  * Process incoming ARP packets
150 158
  *
151
- * @v arp_netif		Network interface for ARP packets
152 159
  * @v pkb		Packet buffer
153 160
  * @ret rc		Return status code
154 161
  *
@@ -158,80 +165,96 @@ int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
158 165
  * avoiding the need for extraneous ARP requests; read the RFC for
159 166
  * details.
160 167
  */
161
-int arp_process ( struct net_interface *arp_netif, struct pk_buff *pkb ) {
168
+static int arp_rx ( struct pk_buff *pkb ) {
162 169
 	struct arphdr *arphdr = pkb->data;
163
-	struct net_device *netdev = arp_netif->netdev;
164
-	struct net_interface *netif;
170
+	struct ll_protocol *ll_protocol;
171
+	struct net_protocol *net_protocol;
165 172
 	struct arp_entry *arp;
173
+	struct net_device *netdev;
166 174
 	int merge = 0;
167 175
 
168
-	/* Check for correct link-layer protocol and length */
169
-	if ( ( arphdr->ar_hrd != netdev->ll_proto ) ||
170
-	     ( arphdr->ar_hln != netdev->ll_addr_len ) )
171
-		return 0;
176
+	/* Identify link-layer and network-layer protocols */
177
+	ll_protocol = pkb->ll_protocol;
178
+	net_protocol = net_find_protocol ( arphdr->ar_pro );
179
+	if ( ! net_protocol )
180
+		goto done;
172 181
 
173
-	/* See if we have an interface for this network-layer protocol */
174
-	netif = netdev_find_netif ( netdev, arphdr->ar_pro );
175
-	if ( ! netif )
176
-		return 0;
177
-	if ( arphdr->ar_pln != netif->net_addr_len )
178
-		return 0;
182
+	/* Sanity checks */
183
+	if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
184
+	     ( arphdr->ar_hln != ll_protocol->ll_addr_len ) ||
185
+	     ( arphdr->ar_pln != net_protocol->net_addr_len ) )
186
+		goto done;
179 187
 
180 188
 	/* See if we have an entry for this sender, and update it if so */
181
-	arp = arp_find_entry ( arphdr->ar_hrd, arphdr->ar_pro,
182
-			       arp_sender_pa ( arphdr ), arphdr->ar_pln );
189
+	arp = arp_find_entry ( ll_protocol, net_protocol,
190
+			       arp_sender_pa ( arphdr ) );
183 191
 	if ( arp ) {
184 192
 		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
185 193
 			 arphdr->ar_hln );
186 194
 		merge = 1;
187 195
 	}
188 196
 
189
-	/* See if we are the target protocol address */
190
-	if ( memcmp ( arp_target_pa ( arphdr ), netif->net_addr,
191
-		      arphdr->ar_pln ) != 0 )
192
-		return 0;
193
-
197
+	/* See if we own the target protocol address */
198
+	netdev = net_find_address ( net_protocol, arp_target_pa ( arphdr ) );
199
+	if ( ! netdev )
200
+		goto done;
201
+	
194 202
 	/* Create new ARP table entry if necessary */
195 203
 	if ( ! merge ) {
196 204
 		arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES];
197
-		arp->ll_proto = arphdr->ar_hrd;
198
-		arp->net_proto = arphdr->ar_pro;
205
+		arp->ll_protocol = ll_protocol;
206
+		arp->net_protocol = net_protocol;
199 207
 		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
200 208
 			 arphdr->ar_hln );
201 209
 		memcpy ( arp->net_addr, arp_sender_pa ( arphdr ),
202
-			 arphdr->ar_pln );
210
+			 arphdr->ar_pln);
203 211
 	}
204 212
 
205 213
 	/* If it's not a request, there's nothing more to do */
206 214
 	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) )
207
-		return 0;
215
+		goto done;
208 216
 
209 217
 	/* Change request to a reply, and send it */
210 218
 	arphdr->ar_op = htons ( ARPOP_REPLY );
211
-	memcpy ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
219
+	memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
212 220
 		 arphdr->ar_hln + arphdr->ar_pln );
213 221
 	memcpy ( arp_target_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
214
-	memcpy ( arp_target_pa ( arphdr ), netif->net_addr, arphdr->ar_pln );
215
-	netif_send ( arp_netif, pkb );
222
+	if ( net_transmit ( pkb ) == 0 )
223
+		pkb = NULL;
216 224
 
225
+ done:
226
+	free_pkb ( pkb );
217 227
 	return 0;
218 228
 }
219 229
 
220 230
 /**
221
- * Add media-independent link-layer header
231
+ * Perform ARP network-layer routing
222 232
  *
223
- * @v arp_netif		Network interface for ARP packets
224
- * @v pkb		Packet buffer
225
- * @ret rc		Return status code
233
+ * @v pkb	Packet buffer
234
+ * @ret source	Network-layer source address
235
+ * @ret dest	Network-layer destination address
236
+ * @ret rc	Return status code
226 237
  */
227
-int arp_add_llh_metadata ( struct net_interface *arp_netif __unused,
228
-			   struct pk_buff *pkb ) {
238
+static int arp_route ( const struct pk_buff *pkb,
239
+		       struct net_header *nethdr ) {
229 240
 	struct arphdr *arphdr = pkb->data;
230 241
 
231
-	pkb->net_proto = htons ( ETH_P_ARP );
232
-	pkb->flags = PKB_FL_RAW_NET_ADDR;
233
-	pkb->net_addr_len = arphdr->ar_hln;
234
-	pkb->net_addr = arp_target_ha ( arphdr );
242
+	memcpy ( nethdr->source_net_addr, arp_sender_ha ( arphdr ),
243
+		 arphdr->ar_hln );
244
+	memcpy ( nethdr->dest_net_addr, arp_target_ha ( arphdr ),
245
+		 arphdr->ar_hln );
246
+	nethdr->dest_flags = NETADDR_FL_RAW;
247
+	if ( arphdr->ar_op == htons ( ARPOP_REQUEST ) )
248
+		nethdr->dest_flags |= NETADDR_FL_BROADCAST;
235 249
 	
236 250
 	return 0;
237 251
 }
252
+
253
+/** ARP protocol */
254
+struct net_protocol arp_protocol = {
255
+	.net_proto = ETH_P_ARP,
256
+	.rx = arp_rx,
257
+	.route = arp_route,
258
+};
259
+
260
+NET_PROTOCOL ( arp_protocol );

+ 69
- 48
src/net/ethernet.c Vedi File

@@ -20,10 +20,12 @@
20 20
 #include <string.h>
21 21
 #include <byteswap.h>
22 22
 #include <assert.h>
23
+#include <gpxe/if_arp.h>
23 24
 #include <gpxe/if_ether.h>
24 25
 #include <gpxe/netdevice.h>
25 26
 #include <gpxe/pkbuff.h>
26 27
 #include <gpxe/arp.h>
28
+#include <gpxe/ethernet.h>
27 29
 
28 30
 /** @file
29 31
  *
@@ -32,85 +34,104 @@
32 34
  */
33 35
 
34 36
 /** Ethernet broadcast MAC address */
35
-static uint8_t eth_broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
37
+static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
36 38
 
37 39
 /**
38
- * Build Ethernet link-layer header
40
+ * Perform Ethernet routing
39 41
  *
40
- * @v netdev	Network device
41
- * @v pkb	Packet buffer
42
+ * @v nethdr	Generic network-layer header
43
+ * @ret llhdr	Generic link-layer header
42 44
  * @ret rc	Return status code
43 45
  *
44
- * This constructs the Ethernet link-layer header (destination MAC,
45
- * source MAC, network-layer protocol) based on the metadata found in
46
- * @c pkb.
46
+ * Constructs the generic link-layer header based on the generic
47
+ * network-layer header, i.e. maps network-layer addresses (e.g. IPv4
48
+ * addresses) to MAC addresses.
47 49
  *
48 50
  * If the destination MAC address cannot be determined, an ARP request
49
- * is sent for the requested network-layer address instead.
51
+ * is sent for the requested network-layer address and -ENOENT is
52
+ * returned.
50 53
  */
51
-int eth_build_llh ( struct net_device *netdev, struct pk_buff *pkb ) {
52
-	struct ethhdr *ethhdr = pkb->data;
53
-	const void *eth_dest;
54
+static int eth_route ( const struct net_header *nethdr,
55
+		       struct ll_header *llhdr ) {
54 56
 	int rc;
55 57
 
56
-	/* Do the easy bits */
57
-	ethhdr->h_protocol = pkb->net_proto;
58
-	memcpy ( ethhdr->h_source, netdev->ll_addr,
59
-		 sizeof ( ethhdr->h_source ) );
60
-
61 58
 	/* Work out the destination MAC address */
62
-	if ( pkb->flags & PKB_FL_RAW_NET_ADDR ) {
63
-		eth_dest = pkb->net_addr;
64
-	} else if ( pkb->flags & PKB_FL_BROADCAST ) {
65
-		eth_dest = eth_broadcast;
66
-	} else if ( pkb->flags & PKB_FL_MULTICAST ) {
59
+	if ( nethdr->dest_flags & NETADDR_FL_RAW ) {
60
+		memcpy ( llhdr->dest_ll_addr, nethdr->dest_net_addr, ETH_ALEN);
61
+	} else if ( nethdr->dest_flags & NETADDR_FL_BROADCAST ) {
62
+		memcpy ( llhdr->dest_ll_addr, eth_broadcast, ETH_ALEN );
63
+	} else if ( nethdr->dest_flags & NETADDR_FL_MULTICAST ) {
67 64
 		/* IP multicast is a special case; there exists a
68 65
 		 * direct mapping from IP address to MAC address
69 66
 		 */
70
-		assert ( pkb->net_proto == htons ( ETH_P_IP ) );
71
-		ethhdr->h_dest[0] = 0x01;
72
-		ethhdr->h_dest[1] = 0x00;
73
-		ethhdr->h_dest[2] = 0x5e;
74
-		ethhdr->h_dest[3] = *( ( char * ) pkb->net_addr + 1 ) & 0x7f;
75
-		ethhdr->h_dest[4] = *( ( char * ) pkb->net_addr + 2 );
76
-		ethhdr->h_dest[5] = *( ( char * ) pkb->net_addr + 3 );
77
-		eth_dest = ethhdr->h_dest;
67
+		assert ( nethdr->net_protocol->net_proto == htons(ETH_P_IP) );
68
+		llhdr->dest_ll_addr[0] = 0x01;
69
+		llhdr->dest_ll_addr[1] = 0x00;
70
+		llhdr->dest_ll_addr[2] = 0x5e;
71
+		llhdr->dest_ll_addr[3] = nethdr->dest_net_addr[1] & 0x7f;
72
+		llhdr->dest_ll_addr[4] = nethdr->dest_net_addr[2];
73
+		llhdr->dest_ll_addr[5] = nethdr->dest_net_addr[3];
78 74
 	} else {
79 75
 		/* Otherwise, look up the address using ARP */
80
-		if ( ( rc = arp_resolve ( netdev, pkb, &eth_dest ) ) != 0 )
76
+		if ( ( rc = arp_resolve ( nethdr, llhdr ) ) != 0 )
81 77
 			return rc;
82 78
 	}
83 79
 
84
-	/* Fill in destination MAC address */
85
-	memcpy ( ethhdr->h_dest, eth_dest, sizeof ( ethhdr->h_dest ) );
86
-
87 80
 	return 0;
88 81
 }
89 82
 
83
+/**
84
+ * Fill in Ethernet link-layer header
85
+ *
86
+ * @v pkb	Packet buffer
87
+ * @v llhdr	Generic link-layer header
88
+ *
89
+ * Fills in the Ethernet link-layer header in the packet buffer based
90
+ * on information in the generic link-layer header.
91
+ */
92
+static void eth_fill_llh ( const struct ll_header *llhdr,
93
+			   struct pk_buff *pkb ) {
94
+	struct ethhdr *ethhdr = pkb->data;
95
+
96
+	memcpy ( ethhdr->h_dest, llhdr->dest_ll_addr, ETH_ALEN );
97
+	memcpy ( ethhdr->h_source, llhdr->source_ll_addr, ETH_ALEN );
98
+	ethhdr->h_protocol = llhdr->net_proto;
99
+}
100
+
90 101
 /**
91 102
  * Parse Ethernet link-layer header
92 103
  *
93
- * @v netdev	Network device
94 104
  * @v pkb	Packet buffer
95
- * @ret rc	Return status code
105
+ * @v llhdr	Generic link-layer header
96 106
  *
97
- * This parses the Ethernet link-layer header (destination MAC, source
98
- * MAC, network-layer protocol) and fills in the metadata in @c pkb.
107
+ * Fills in the generic link-layer header based on information in the
108
+ * Ethernet link-layer header in the packet buffer.
99 109
  */
100
-int eth_parse_llh ( struct net_device *netdev __unused, struct pk_buff *pkb ) {
110
+static void eth_parse_llh ( const struct pk_buff *pkb,
111
+			    struct ll_header *llhdr ) {
101 112
 	struct ethhdr *ethhdr = pkb->data;
102 113
 
103
-	pkb->net_proto = ethhdr->h_protocol;
104
-	pkb->flags = PKB_FL_RAW_NET_ADDR;
105
-	pkb->net_addr_len = sizeof ( ethhdr->h_dest );
106
-	pkb->net_addr = ethhdr->h_dest;
114
+	memcpy ( llhdr->dest_ll_addr, ethhdr->h_dest, ETH_ALEN );
115
+	memcpy ( llhdr->source_ll_addr, ethhdr->h_source, ETH_ALEN );
116
+	llhdr->net_proto = ethhdr->h_protocol;
107 117
 
108
-	if ( memcmp ( ethhdr->h_dest, eth_broadcast,
109
-		      sizeof ( ethhdr->h_dest ) ) == 0 ) {
110
-		pkb->flags |= PKB_FL_BROADCAST;
118
+	if ( memcmp ( ethhdr->h_dest, eth_broadcast, ETH_ALEN ) == 0 ) {
119
+		llhdr->dest_flags = NETADDR_FL_BROADCAST;
111 120
 	} else if ( ethhdr->h_dest[0] & 0x01 ) {
112
-		pkb->flags |= PKB_FL_MULTICAST;
121
+		llhdr->dest_flags = NETADDR_FL_MULTICAST;
122
+	} else {
123
+		llhdr->dest_flags = 0;
113 124
 	}
114
-
115
-	return 0;
116 125
 }
126
+
127
+/** Ethernet protocol */
128
+struct ll_protocol ethernet_protocol = {
129
+	.ll_proto = htons ( ARPHRD_ETHER ),
130
+	.ll_addr_len = ETH_ALEN,
131
+	.ll_header_len = ETH_HLEN,
132
+	.route = eth_route,
133
+	.fill_llh = eth_fill_llh,
134
+	.parse_llh = eth_parse_llh,
135
+};
136
+
137
+LL_PROTOCOL ( ethernet_protocol );

+ 171
- 86
src/net/netdevice.c Vedi File

@@ -18,146 +18,231 @@
18 18
 
19 19
 #include <stdint.h>
20 20
 #include <byteswap.h>
21
+#include <string.h>
21 22
 #include <errno.h>
22 23
 #include <gpxe/if_ether.h>
23 24
 #include <gpxe/pkbuff.h>
25
+#include <gpxe/tables.h>
24 26
 #include <gpxe/netdevice.h>
25 27
 
26 28
 /** @file
27 29
  *
28
- * Network devices and network interfaces
30
+ * Network device management
29 31
  *
30 32
  */
31 33
 
32
-/** List of all registered network devices */
33
-static LIST_HEAD ( net_devices );
34
-
35 34
 /**
36
- * Register network device
35
+ * Static single instance of a network device
36
+ *
37
+ * The gPXE API is designed to accommodate multiple network devices.
38
+ * However, in the interests of code size, the implementation behind
39
+ * the API supports only a single instance of a network device.
37 40
  *
38
- * @v netdev	Network device
39
- * @ret rc	Return status code
41
+ * No code outside of netdevice.c should ever refer directly to @c
42
+ * static_single_netdev.
40 43
  *
41
- * Adds the network device to the list of network devices.
44
+ * Callers should always check the return status of alloc_netdev(),
45
+ * register_netdev() etc.  In the current implementation this code
46
+ * will be optimised out by the compiler, so there is no penalty.
42 47
  */
43
-int register_netdevice ( struct net_device *netdev ) {
44
-	list_add ( &netdev->devices, &net_devices );
45
-	return 0;
46
-}
48
+struct net_device static_single_netdev;
49
+
50
+/** Registered network-layer protocols */
51
+static struct net_protocol net_protocols[0] __table_start ( net_protocols );
52
+static struct net_protocol net_protocols_end[0] __table_end ( net_protocols );
53
+
54
+/** Network-layer addresses for @c static_single_netdev */
55
+static struct net_address static_single_netdev_addresses[0]
56
+	__table_start ( sgl_netdev_addresses );
57
+static struct net_address static_single_netdev_addresses_end[0]
58
+	__table_end ( sgl_netdev_addresses );
59
+
60
+/** Recevied packet queue */
61
+static LIST_HEAD ( rx_queue );
47 62
 
48 63
 /**
49
- * Unregister network device
64
+ * Identify network protocol
50 65
  *
51
- * @v netdev	Network device
66
+ * @v net_proto		Network-layer protocol, in network-byte order
67
+ * @ret net_protocol	Network-layer protocol, or NULL
52 68
  *
53
- * Removes the network device from the list of network devices.
69
+ * Identify a network-layer protocol from a protocol number, which
70
+ * must be an ETH_P_XXX constant in network-byte order.
54 71
  */
55
-void unregister_netdevice ( struct net_device *netdev ) {
56
-	list_del ( &netdev->devices );
72
+struct net_protocol * net_find_protocol ( uint16_t net_proto ) {
73
+	struct net_protocol *net_protocol;
74
+
75
+	for ( net_protocol = net_protocols ; net_protocol < net_protocols_end ;
76
+	      net_protocol++ ) {
77
+		if ( net_protocol->net_proto == net_proto )
78
+			return net_protocol;
79
+	}
80
+	return NULL;
57 81
 }
58 82
 
59 83
 /**
60
- * Transmit packet via network device
84
+ * Identify network device by network-layer address
61 85
  *
62
- * @v netdev	Network device
63
- * @v pkb	Packet buffer
64
- * @ret rc	Return status code
86
+ * @v net_protocol	Network-layer protocol
87
+ * @v net_addr		Network-layer address
88
+ * @ret netdev		Network device, or NULL
65 89
  *
66
- * Transmits the packet via the network device.  The @c pkb link-layer
67
- * metadata must already have been filled in, and space for the
68
- * link-layer header must already be present in the packet buffer.
90
+ * Searches through all network devices to find the device with the
91
+ * specified network-layer address.
92
+ *
93
+ * Note that even with a static single network device, this function
94
+ * can still return NULL.
69 95
  */
70
-int netdev_send ( struct net_device *netdev, struct pk_buff *pkb ) {
71
-	int rc;
72
-
73
-	if ( pkb->net_proto != ETH_P_RAW ) {
74
-		if ( ( rc = netdev->build_llh ( netdev, pkb ) ) != 0 )
75
-			return rc;
96
+struct net_device * net_find_address ( struct net_protocol *net_protocol,
97
+				       void *net_addr ) {
98
+	struct net_address *net_address;
99
+	struct net_device *netdev = &static_single_netdev;
100
+	
101
+	for ( net_address = static_single_netdev_addresses ;
102
+	      net_address < static_single_netdev_addresses_end ;
103
+	      net_address ++ ) {
104
+		if ( ( net_address->net_protocol == net_protocol ) &&
105
+		     ( memcmp ( net_address->net_addr, net_addr,
106
+				net_protocol->net_addr_len ) == 0 ) )
107
+			return netdev;
76 108
 	}
77
-	return netdev->transmit ( netdev, pkb );
109
+	return NULL;
78 110
 }
79 111
 
80 112
 /**
81
- * Poll for packet on network device
113
+ * Transmit packet
82 114
  *
83
- * @v netdev	Network device
84
- * @v pkb	Packet buffer
85
- * @ret rc	Return status code
115
+ * @v pkb		Packet buffer
116
+ * @ret rc		Return status code
86 117
  *
87
- * Polls the network device for a packet.  If a packet is available,
88
- * it will be added to the packet buffer, and the link-layer metadata
89
- * fields in @c pkb will be filled in.
118
+ * Transmits the packet via the appropriate network device.  If this
119
+ * function returns success, it has taken ownership of the packet
120
+ * buffer.
90 121
  */
91
-int netdev_poll ( struct net_device *netdev, struct pk_buff *pkb ) {
122
+int net_transmit ( struct pk_buff *pkb ) {
123
+	struct net_protocol *net_protocol;
124
+	struct net_header nethdr;
125
+	struct ll_protocol *ll_protocol;
126
+	struct ll_header llhdr;
127
+	struct net_device *netdev;
92 128
 	int rc;
93 129
 
94
-	if ( ( rc = netdev->poll ( netdev, pkb ) ) != 0 )
95
-		return rc;
96
-	return netdev->parse_llh ( netdev, pkb );
130
+	/* Perform network-layer routing */
131
+	net_protocol = pkb->net_protocol;
132
+	nethdr.net_protocol = net_protocol;
133
+	if ( ( rc = net_protocol->route ( pkb, &nethdr ) ) != 0 )
134
+		goto err;
135
+
136
+	/* Identify transmitting network device */
137
+	netdev = net_find_address ( net_protocol, nethdr.source_net_addr );
138
+	if ( ! netdev )
139
+		goto err;
140
+
141
+	/* Perform link-layer routing */
142
+	ll_protocol = netdev->ll_protocol;
143
+	llhdr.ll_protocol = ll_protocol;
144
+	llhdr.net_proto = net_protocol->net_proto;
145
+	memcpy ( llhdr.source_ll_addr, netdev->ll_addr,
146
+		 ll_protocol->ll_addr_len);
147
+	if ( ( rc = ll_protocol->route ( &nethdr, &llhdr ) ) != 0 )
148
+		goto err;
149
+
150
+	/* Prepend link-layer header */
151
+	pkb_push ( pkb, ll_protocol->ll_header_len );
152
+	ll_protocol->fill_llh ( &llhdr, pkb );
153
+
154
+	/* Transmit packet */
155
+	if ( ( rc = netdev->transmit ( netdev, pkb ) ) != 0 )
156
+		goto err;
157
+
158
+	return 0;
159
+
160
+ err:
161
+	free_pkb ( pkb );
162
+	return rc;
97 163
 }
98 164
 
99 165
 /**
100
- * Transmit packet via network interface
166
+ * Poll for packet on all network devices
101 167
  *
102
- * @v netif	Network interface
103
- * @v pkb	Packet buffer
104
- * @ret rc	Return status code
168
+ * @ret True		There are packets present in the receive queue
169
+ * @ret False		There are no packets present in the receive queue
105 170
  *
106
- * Transmits the packet via the network interface.  The packet must
107
- * start with a network-layer header (e.g. an IP header, for an IP
108
- * interface).  The packet contents are undefined on return.
171
+ * Polls all network devices for received packets.  Any received
172
+ * packets will be added to the RX packet queue via netdev_rx().
109 173
  */
110
-int netif_send ( struct net_interface *netif, struct pk_buff *pkb ) {
111
-	struct net_device *netdev = netif->netdev;
112
-	int rc;
174
+int net_poll ( void ) {
175
+	struct net_device *netdev = &static_single_netdev;
176
+
177
+	netdev->poll ( netdev );
113 178
 
114
-	if ( ( rc = netif->add_llh_metadata ( netif, pkb ) ) != 0 )
115
-		return rc;
116
-	pkb_push ( pkb, netdev->ll_hlen );
117
-	return netdev_send ( netdev, pkb );
179
+	return ( ! list_empty ( &rx_queue ) );
118 180
 }
119 181
 
120 182
 /**
121
- * Process received packet
183
+ * Add packet to receive queue
122 184
  *
123
- * @v netif	Network interface
124
- * @v pkb	Packet buffer
125
- * @ret rc	Return status code
185
+ * @v netdev		Network device
186
+ * @v pkb		Packet buffer
126 187
  *
127
- * Processes a packet received via netdev_poll().  The interface
128
- * corresponding to the network-layer protocol is identified, the
129
- * link-layer header is stripped from the packet and the packet is
130
- * passed to the net_interface::rx_packet() method.
188
+ * The packet is added to the RX queue.  Ownership of the packet is
189
+ * transferred to the RX queue; the caller must not touch the packet
190
+ * buffer after calling netdev_rx().
131 191
  */
132
-int netdev_rx_packet ( struct net_device *netdev, struct pk_buff *pkb ) {
133
-	struct net_interface *netif;
134
-
135
-	netif = netdev_find_netif ( netdev, pkb->net_proto );
136
-	if ( ! netif )
137
-		return -EAFNOSUPPORT;
138
-
139
-	pkb_pull ( pkb, netdev->ll_hlen );
140
-	return netif->rx_packet ( netif, pkb );
192
+void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) {
193
+	pkb->ll_protocol = netdev->ll_protocol;
194
+	list_add_tail ( &pkb->list, &rx_queue );
141 195
 }
142 196
 
143 197
 /**
144
- * Poll for packet on all network devices
198
+ * Remove packet from receive queue
145 199
  *
146
- * @v pkb	Packet buffer
147
- * @ret netdev	Network device
148
- * @ret rc	Return status code
200
+ * @ret pkb		Packet buffer, or NULL
149 201
  *
150
- * Polls all network devices for a packet.  If a packet is available
151
- * on any interface, @c netdev will be filled in and the packet will
152
- * be received as per netdev_poll().
202
+ * Removes the first packet from the RX queue and returns it.
203
+ * Ownership of the packet is transferred to the caller.
153 204
  */
154
-int net_poll ( struct pk_buff *pkb, struct net_device **netdev ) {
155
-	int rc;
205
+struct pk_buff * net_rx_dequeue ( void ) {
206
+	struct pk_buff *pkb;
156 207
 
157
-	list_for_each_entry ( (*netdev), &net_devices, devices ) {
158
-		if ( ( rc = netdev_poll ( *netdev, pkb ) ) == 0 )
159
-			return rc;
208
+	list_for_each_entry ( pkb, &rx_queue, list ) {
209
+		list_del ( &pkb->list );
210
+		return pkb;
160 211
 	}
212
+	return NULL;
213
+}
161 214
 
162
-	return -EAGAIN;
215
+void net_run ( void ) {
216
+	struct pk_buff *pkb;
217
+	struct ll_protocol *ll_protocol;
218
+	struct ll_header llhdr;
219
+	struct net_protocol *net_protocol;
220
+
221
+	while ( ( pkb = net_rx_dequeue () ) ) {
222
+
223
+		/* Parse link-layer header */
224
+		ll_protocol = pkb->ll_protocol;
225
+		ll_protocol->parse_llh ( pkb, &llhdr );
226
+
227
+		/* Identify network-layer protocol */
228
+		net_protocol = net_find_protocol ( llhdr.net_proto );
229
+		if ( ! net_protocol ) {
230
+			DBG ( "Unknown network-layer protocol %02x\n",
231
+			      ntohs ( llhdr.net_proto ) );
232
+			free_pkb ( pkb );
233
+			continue;
234
+		}
235
+
236
+		/* Strip off link-layer header */
237
+		pkb_pull ( pkb, ll_protocol->ll_header_len );
238
+
239
+		/* Hand off to network layer */
240
+		if ( net_protocol->rx ( pkb ) != 0 ) {
241
+			free_pkb ( pkb );
242
+			continue;
243
+		}
244
+	}
163 245
 }
246
+
247
+
248
+

+ 1
- 1
src/proto/uip/uipopt.h Vedi File

@@ -464,7 +464,7 @@ void uip_log(char *msg);
464 464
  *
465 465
  * \hideinitializer
466 466
  */
467
-#define UIP_LLH_LEN     14
467
+#define UIP_LLH_LEN     0
468 468
 
469 469
 
470 470
 /** @} */

Loading…
Annulla
Salva