소스 검색

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 년 전
부모
커밋
fdc2ee79db
8개의 변경된 파일732개의 추가작업 그리고 493개의 파일을 삭제
  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 파일 보기

@@ -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 파일 보기

@@ -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 파일 보기

@@ -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 파일 보기

@@ -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 파일 보기

@@ -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 파일 보기

@@ -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 파일 보기

@@ -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 파일 보기

@@ -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…
취소
저장