summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2006-04-28 16:13:50 +0200
committerMichael Brown2006-04-28 16:13:50 +0200
commit129c6c3968d4967f091266ee8c7d99986080e201 (patch)
tree619664ae529782f67bb6d5832443b21001a4c811
parentFix a couple of broken assertions, and align the buffer correctly. (diff)
downloadipxe-129c6c3968d4967f091266ee8c7d99986080e201.tar.gz
ipxe-129c6c3968d4967f091266ee8c7d99986080e201.tar.xz
ipxe-129c6c3968d4967f091266ee8c7d99986080e201.zip
Network layer now works as a proof of concept
-rw-r--r--src/include/gpxe/arp.h4
-rw-r--r--src/include/gpxe/netdevice.h107
-rw-r--r--src/net/arp.c52
-rw-r--r--src/net/ethernet.c41
-rw-r--r--src/net/ipv4.c42
-rw-r--r--src/net/netdevice.c118
6 files changed, 272 insertions, 92 deletions
diff --git a/src/include/gpxe/arp.h b/src/include/gpxe/arp.h
index a2db80f1..27591d3f 100644
--- a/src/include/gpxe/arp.h
+++ b/src/include/gpxe/arp.h
@@ -7,10 +7,12 @@
*
*/
+struct net_device;
struct net_header;
struct ll_header;
-extern int arp_resolve ( const struct net_header *nethdr,
+extern int arp_resolve ( struct net_device *netdev,
+ const struct net_header *nethdr,
struct ll_header *llhdr );
#endif /* _GPXE_ARP_H */
diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h
index f7d78288..6db95bbb 100644
--- a/src/include/gpxe/netdevice.h
+++ b/src/include/gpxe/netdevice.h
@@ -11,12 +11,16 @@
#include <gpxe/tables.h>
struct pk_buff;
+struct net_device;
struct net_protocol;
struct ll_protocol;
/** Maximum length of a link-layer address */
#define MAX_LL_ADDR_LEN 6
+/** Maximum length of a link-layer header */
+#define MAX_LL_HEADER_LEN 16
+
/** Maximum length of a network-layer address */
#define MAX_NET_ADDR_LEN 4
@@ -32,37 +36,37 @@ struct ll_protocol;
struct net_header {
/** Network-layer protocol */
struct net_protocol *net_protocol;
- /** Destination address flags
+ /** Flags
*
- * This is the bitwise OR of zero or more NETADDR_FL_XXX
+ * This is the bitwise OR of zero or more PKT_FL_XXX
* values.
*/
- int dest_flags;
+ int flags;
/** Network-layer destination address */
uint8_t dest_net_addr[MAX_NET_ADDR_LEN];
/** Network-layer source address */
uint8_t source_net_addr[MAX_NET_ADDR_LEN];
};
-/** Address is a broadcast address */
-#define NETADDR_FL_BROADCAST 0x01
+/** Packet is a broadcast packet */
+#define PKT_FL_BROADCAST 0x01
-/** Address is a multicast address */
-#define NETADDR_FL_MULTICAST 0x02
+/** Packet is a multicast packet */
+#define PKT_FL_MULTICAST 0x02
-/** Address is a raw hardware address */
-#define NETADDR_FL_RAW 0x04
+/** Addresses are raw hardware addresses */
+#define PKT_FL_RAW_ADDR 0x04
/** A generic link-layer header */
struct ll_header {
/** Link-layer protocol */
struct ll_protocol *ll_protocol;
- /** Destination address flags
+ /** Flags
*
- * This is the bitwise OR of zero or more NETADDR_FL_XXX
+ * This is the bitwise OR of zero or more PKT_FL_XXX
* values.
*/
- int dest_flags;
+ int flags;
/** Link-layer destination address */
uint8_t dest_ll_addr[MAX_LL_ADDR_LEN];
/** Link-layer source address */
@@ -80,21 +84,21 @@ struct ll_header {
*
*/
struct net_protocol {
+ /** Protocol name */
+ const char *name;
/**
* Perform network-layer routing
*
* @v pkb Packet buffer
- * @ret source Network-layer source address
- * @ret dest Network-layer destination address
+ * @v nethdr Generic network-layer header
* @ret rc Return status code
*
- * This method should fill in the source and destination
- * addresses with enough information to allow the link layer
- * to route the packet.
+ * This method should fill in the network header with enough
+ * information to allow the link layer to route the packet.
*
* For example, in the case of IPv4, this method should fill
- * in @c source with the IP addresses of the local adapter and
- * @c dest with the next hop destination (e.g. the gateway).
+ * in the IP addresses of the local adapter and the next hop
+ * destination (e.g. the gateway).
*/
int ( * route ) ( const struct pk_buff *pkb,
struct net_header *nethdr );
@@ -108,6 +112,19 @@ struct net_protocol {
* the packet buffer.
*/
int ( * rx ) ( struct pk_buff *pkb );
+ /**
+ * Transcribe network-layer address
+ *
+ * @v net_addr Network-layer address
+ * @ret string Human-readable transcription of address
+ *
+ * This method should convert the network-layer address into a
+ * human-readable format (e.g. dotted quad notation for IPv4).
+ *
+ * The buffer used to hold the transcription is statically
+ * allocated.
+ */
+ const char * ( *ntoa ) ( const void * net_addr );
/** Network-layer protocol
*
* This is an ETH_P_XXX constant, in network-byte order
@@ -122,9 +139,12 @@ struct net_protocol {
*
*/
struct ll_protocol {
+ /** Protocol name */
+ const char *name;
/**
* Perform link-layer routing
*
+ * @v netdev Network device
* @v nethdr Generic network-layer header
* @ret llhdr Generic link-layer header
* @ret rc Return status code
@@ -137,7 +157,8 @@ struct ll_protocol {
* return an error (after transmitting an ARP request, if
* applicable).
*/
- int ( * route ) ( const struct net_header *nethdr,
+ int ( * route ) ( struct net_device *netdev,
+ const struct net_header *nethdr,
struct ll_header *llhdr );
/**
* Fill media-specific link-layer header
@@ -164,6 +185,19 @@ struct ll_protocol {
void ( * parse_llh ) ( const struct pk_buff *pkb,
struct ll_header *llhdr );
+ /**
+ * Transcribe link-layer address
+ *
+ * @v ll_addr Link-layer address
+ * @ret string Human-readable transcription of address
+ *
+ * This method should convert the link-layer address into a
+ * human-readable format.
+ *
+ * The buffer used to hold the transcription is statically
+ * allocated.
+ */
+ const char * ( *ntoa ) ( const void * ll_addr );
/** Link-layer protocol
*
* This is an ARPHRD_XXX constant, in network byte order.
@@ -291,12 +325,29 @@ free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
}
/**
+ * Transmit raw packet via network device
+ *
+ * @v netdev Network device
+ * @v pkb Packet buffer
+ * @ret rc Return status code
+ *
+ * Transmits the packet via the specified network device. The
+ * link-layer header must already have been filled in. If this
+ * function returns success, it has taken ownership of the packet
+ * buffer.
+ */
+static inline int netdev_transmit ( struct net_device *netdev,
+ struct pk_buff *pkb ) {
+ return netdev->transmit ( netdev, pkb );
+}
+
+/**
* Register a link-layer protocol
*
* @v protocol Link-layer protocol
*/
#define LL_PROTOCOL( protocol ) \
- struct ll_protocol protocol __table ( ll_protocols, 00 )
+ struct ll_protocol protocol __table ( ll_protocols, 01 )
/**
* Register a network-layer protocol
@@ -304,7 +355,7 @@ free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
* @v protocol Network-layer protocol
*/
#define NET_PROTOCOL( protocol ) \
- struct net_protocol protocol __table ( net_protocols, 00 )
+ struct net_protocol protocol __table ( net_protocols, 01 )
/**
* Register a network-layer address for the static single network device
@@ -312,15 +363,17 @@ free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
* @v net_address Network-layer address
*/
#define STATIC_SINGLE_NETDEV_ADDRESS( address ) \
- struct net_address address __table ( sgl_netdev_addresses, 00 )
+ struct net_address address __table ( sgl_netdev_addresses, 01 )
-extern struct net_protocol *net_find_protocol ( uint16_t net_proto );
-extern struct net_device * net_find_address ( struct net_protocol *net_proto,
- void *net_addr );
+extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
+
+extern struct net_protocol *find_net_protocol ( uint16_t net_proto );
+extern struct net_device *
+find_netdev_by_net_addr ( struct net_protocol *net_protocol, void *net_addr );
+extern int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev );
extern int net_transmit ( struct pk_buff *pkb );
extern int net_poll ( void );
-extern void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
extern struct pk_buff * net_rx_dequeue ( void );
#endif /* _GPXE_NETDEVICE_H */
diff --git a/src/net/arp.c b/src/net/arp.c
index a375eec9..3720acfc 100644
--- a/src/net/arp.c
+++ b/src/net/arp.c
@@ -91,6 +91,7 @@ arp_find_entry ( struct ll_protocol *ll_protocol,
/**
* Look up media-specific link-layer address in the ARP cache
*
+ * @v netdev Network device
* @v nethdr Generic network-layer header
* @ret llhdr Generic link-layer header
* @ret rc Return status code
@@ -102,9 +103,11 @@ arp_find_entry ( struct ll_protocol *ll_protocol,
* llhdr.
*
* If no address is found in the ARP cache, an ARP request will be
- * transmitted and -ENOENT will be returned.
+ * transmitted on the specified network device and -ENOENT will be
+ * returned.
*/
-int arp_resolve ( const struct net_header *nethdr, struct ll_header *llhdr ) {
+int arp_resolve ( struct net_device *netdev, const struct net_header *nethdr,
+ struct ll_header *llhdr ) {
struct net_protocol *net_protocol = nethdr->net_protocol;
struct ll_protocol *ll_protocol = llhdr->ll_protocol;
const struct arp_entry *arp;
@@ -116,17 +119,23 @@ int arp_resolve ( const struct net_header *nethdr, struct ll_header *llhdr ) {
arp = arp_find_entry ( ll_protocol, net_protocol,
nethdr->dest_net_addr );
if ( arp ) {
+ DBG ( "ARP cache hit: %s %s => %s %s\n",
+ net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
+ ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
memcpy ( llhdr->dest_ll_addr, arp->ll_addr,
sizeof ( llhdr->dest_ll_addr ) );
return 0;
}
+ DBG ( "ARP cache miss: %s %s\n", net_protocol->name,
+ net_protocol->ntoa ( nethdr->dest_net_addr ) );
/* Allocate ARP packet */
- pkb = alloc_pkb ( sizeof ( *arphdr ) +
+ pkb = alloc_pkb ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
if ( ! pkb )
return -ENOMEM;
pkb->net_protocol = &arp_protocol;
+ pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
/* Build up ARP request */
arphdr = pkb_put ( pkb, sizeof ( *arphdr ) );
@@ -145,7 +154,7 @@ int arp_resolve ( const struct net_header *nethdr, struct ll_header *llhdr ) {
nethdr->dest_net_addr, net_protocol->net_addr_len );
/* Transmit ARP request */
- if ( ( rc = net_transmit ( pkb ) ) != 0 ) {
+ if ( ( rc = net_transmit_via ( pkb, netdev ) ) != 0 ) {
free_pkb ( pkb );
return rc;
}
@@ -175,7 +184,7 @@ static int arp_rx ( struct pk_buff *pkb ) {
/* Identify link-layer and network-layer protocols */
ll_protocol = pkb->ll_protocol;
- net_protocol = net_find_protocol ( arphdr->ar_pro );
+ net_protocol = find_net_protocol ( arphdr->ar_pro );
if ( ! net_protocol )
goto done;
@@ -192,10 +201,14 @@ static int arp_rx ( struct pk_buff *pkb ) {
memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
arphdr->ar_hln );
merge = 1;
+ DBG ( "ARP cache update: %s %s => %s %s\n",
+ net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
+ ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
}
/* See if we own the target protocol address */
- netdev = net_find_address ( net_protocol, arp_target_pa ( arphdr ) );
+ netdev = find_netdev_by_net_addr ( net_protocol,
+ arp_target_pa ( arphdr ) );
if ( ! netdev )
goto done;
@@ -208,6 +221,9 @@ static int arp_rx ( struct pk_buff *pkb ) {
arphdr->ar_hln );
memcpy ( arp->net_addr, arp_sender_pa ( arphdr ),
arphdr->ar_pln);
+ DBG ( "ARP cache add: %s %s => %s %s\n",
+ net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
+ ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
}
/* If it's not a request, there's nothing more to do */
@@ -215,11 +231,14 @@ static int arp_rx ( struct pk_buff *pkb ) {
goto done;
/* Change request to a reply, and send it */
+ DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name,
+ net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
+ ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
arphdr->ar_op = htons ( ARPOP_REPLY );
memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
arphdr->ar_hln + arphdr->ar_pln );
memcpy ( arp_target_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
- if ( net_transmit ( pkb ) == 0 )
+ if ( net_transmit_via ( pkb, netdev ) == 0 )
pkb = NULL;
done:
@@ -243,18 +262,33 @@ static int arp_route ( const struct pk_buff *pkb,
arphdr->ar_hln );
memcpy ( nethdr->dest_net_addr, arp_target_ha ( arphdr ),
arphdr->ar_hln );
- nethdr->dest_flags = NETADDR_FL_RAW;
+ nethdr->flags = PKT_FL_RAW_ADDR;
if ( arphdr->ar_op == htons ( ARPOP_REQUEST ) )
- nethdr->dest_flags |= NETADDR_FL_BROADCAST;
+ nethdr->flags |= PKT_FL_BROADCAST;
return 0;
}
+/**
+ * Transcribe ARP address
+ *
+ * @v net_addr ARP address
+ * @ret string "<ARP>"
+ *
+ * This operation is meaningless for the ARP protocol.
+ */
+static const char *
+arp_ntoa ( const void *net_addr __attribute__ (( unused )) ) {
+ return "<ARP>";
+}
+
/** ARP protocol */
struct net_protocol arp_protocol = {
+ .name = "ARP",
.net_proto = htons ( ETH_P_ARP ),
.rx = arp_rx,
.route = arp_route,
+ .ntoa = arp_ntoa,
};
NET_PROTOCOL ( arp_protocol );
diff --git a/src/net/ethernet.c b/src/net/ethernet.c
index 59b469f1..cf0ddd7d 100644
--- a/src/net/ethernet.c
+++ b/src/net/ethernet.c
@@ -51,16 +51,21 @@ static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
* is sent for the requested network-layer address and -ENOENT is
* returned.
*/
-static int eth_route ( const struct net_header *nethdr,
+static int eth_route ( struct net_device *netdev,
+ const struct net_header *nethdr,
struct ll_header *llhdr ) {
int rc;
+ /* Fill in the easy bits */
+ llhdr->net_proto = nethdr->net_protocol->net_proto;
+ memcpy ( llhdr->source_ll_addr, netdev->ll_addr, ETH_ALEN );
+
/* Work out the destination MAC address */
- if ( nethdr->dest_flags & NETADDR_FL_RAW ) {
- memcpy ( llhdr->dest_ll_addr, nethdr->dest_net_addr, ETH_ALEN);
- } else if ( nethdr->dest_flags & NETADDR_FL_BROADCAST ) {
+ if ( nethdr->flags & PKT_FL_BROADCAST ) {
memcpy ( llhdr->dest_ll_addr, eth_broadcast, ETH_ALEN );
- } else if ( nethdr->dest_flags & NETADDR_FL_MULTICAST ) {
+ } else if ( nethdr->flags & PKT_FL_RAW_ADDR ) {
+ memcpy ( llhdr->dest_ll_addr, nethdr->dest_net_addr, ETH_ALEN);
+ } else if ( nethdr->flags & PKT_FL_MULTICAST ) {
/* IP multicast is a special case; there exists a
* direct mapping from IP address to MAC address
*/
@@ -73,7 +78,7 @@ static int eth_route ( const struct net_header *nethdr,
llhdr->dest_ll_addr[5] = nethdr->dest_net_addr[3];
} else {
/* Otherwise, look up the address using ARP */
- if ( ( rc = arp_resolve ( nethdr, llhdr ) ) != 0 )
+ if ( ( rc = arp_resolve ( netdev, nethdr, llhdr ) ) != 0 )
return rc;
}
@@ -116,22 +121,40 @@ static void eth_parse_llh ( const struct pk_buff *pkb,
llhdr->net_proto = ethhdr->h_protocol;
if ( memcmp ( ethhdr->h_dest, eth_broadcast, ETH_ALEN ) == 0 ) {
- llhdr->dest_flags = NETADDR_FL_BROADCAST;
+ llhdr->flags = PKT_FL_BROADCAST;
} else if ( ethhdr->h_dest[0] & 0x01 ) {
- llhdr->dest_flags = NETADDR_FL_MULTICAST;
+ llhdr->flags = PKT_FL_MULTICAST;
} else {
- llhdr->dest_flags = 0;
+ llhdr->flags = 0;
}
}
+/**
+ * Transcribe Ethernet address
+ *
+ * @v ll_addr Link-layer address
+ * @ret string Link-layer address in human-readable format
+ */
+static const char * eth_ntoa ( const void *ll_addr ) {
+ static char buf[18]; /* "00:00:00:00:00:00" */
+ uint8_t *eth_addr = ll_addr;
+
+ sprintf ( buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ eth_addr[0], eth_addr[1], eth_addr[2],
+ eth_addr[3], eth_addr[4], eth_addr[5] );
+ return buf;
+}
+
/** Ethernet protocol */
struct ll_protocol ethernet_protocol = {
+ .name = "Ethernet",
.ll_proto = htons ( ARPHRD_ETHER ),
.ll_addr_len = ETH_ALEN,
.ll_header_len = ETH_HLEN,
.route = eth_route,
.fill_llh = eth_fill_llh,
.parse_llh = eth_parse_llh,
+ .ntoa = eth_ntoa,
};
LL_PROTOCOL ( ethernet_protocol );
diff --git a/src/net/ipv4.c b/src/net/ipv4.c
index 4200d234..2fc50672 100644
--- a/src/net/ipv4.c
+++ b/src/net/ipv4.c
@@ -1,6 +1,7 @@
#include <string.h>
#include <stdint.h>
#include <byteswap.h>
+#include <vsprintf.h>
#include <gpxe/in.h>
@@ -153,7 +154,8 @@ static int ipv4_rx ( struct pk_buff *pkb ) {
/* Transfer to uIP buffer. Horrendously space-inefficient,
* but will do as a proof-of-concept for now.
*/
- memcpy ( uip_buf, pkb->data, pkb_len ( pkb ) );
+ uip_len = pkb_len ( pkb );
+ memcpy ( uip_buf, pkb->data, uip_len );
/* Hand to uIP for processing */
uip_input ();
@@ -198,22 +200,40 @@ static int ipv4_route ( const struct pk_buff *pkb,
}
/* Set broadcast and multicast flags as applicable */
- nethdr->dest_flags = 0;
+ nethdr->flags = 0;
if ( dest->s_addr == htonl ( INADDR_BROADCAST ) ) {
- nethdr->dest_flags = NETADDR_FL_BROADCAST;
+ nethdr->flags = PKT_FL_BROADCAST;
} else if ( IN_MULTICAST ( dest->s_addr ) ) {
- nethdr->dest_flags = NETADDR_FL_MULTICAST;
+ nethdr->flags = PKT_FL_MULTICAST;
}
return 0;
}
+/**
+ * Transcribe IP address
+ *
+ * @v net_addr IP address
+ * @ret string IP address in dotted-quad notation
+ *
+ */
+static const char * ipv4_ntoa ( const void *net_addr ) {
+ static char buf[16]; /* "xxx.xxx.xxx.xxx" */
+ uint8_t *ip_addr = net_addr;
+
+ sprintf ( buf, "%d.%d.%d.%d", ip_addr[0], ip_addr[1], ip_addr[2],
+ ip_addr[3] );
+ return buf;
+}
+
/** IPv4 protocol */
struct net_protocol ipv4_protocol = {
- .net_proto = ETH_P_IP,
+ .name = "IP",
+ .net_proto = htons ( ETH_P_IP ),
.net_addr_len = sizeof ( struct in_addr ),
.rx = ipv4_rx,
.route = ipv4_route,
+ .ntoa = ipv4_ntoa,
};
NET_PROTOCOL ( ipv4_protocol );
@@ -221,6 +241,18 @@ NET_PROTOCOL ( ipv4_protocol );
/** IPv4 address for the static single net device */
struct net_address static_single_ipv4_address = {
.net_protocol = &ipv4_protocol,
+
+#warning "Remove this static-IP hack"
+ .net_addr = { 0x0a, 0xfe, 0xfe, 0x01 },
};
STATIC_SINGLE_NETDEV_ADDRESS ( static_single_ipv4_address );
+
+#warning "Remove this static-IP hack"
+static struct ipv4_route routing_table[NUM_ROUTES] = {
+ { { htonl ( 0x0afefe00 ) }, { htonl ( 0xfffffffc ) },
+ { htonl ( 0x00000000 ) }, { htonl ( 0x0afefe01 ) } },
+ { { htonl ( 0x00000000 ) }, { htonl ( 0x00000000 ) },
+ { htonl ( 0x0afefe02 ) }, { htonl ( 0x0afefe01 ) } },
+};
+
diff --git a/src/net/netdevice.c b/src/net/netdevice.c
index 3ff6657c..59861d05 100644
--- a/src/net/netdevice.c
+++ b/src/net/netdevice.c
@@ -61,6 +61,22 @@ static struct net_address static_single_netdev_addresses_end[0]
static LIST_HEAD ( rx_queue );
/**
+ * Add packet to receive queue
+ *
+ * @v netdev Network device
+ * @v pkb Packet buffer
+ *
+ * The packet is added to the RX queue. Ownership of the packet is
+ * transferred to the RX queue; the caller must not touch the packet
+ * buffer after calling netdev_rx().
+ */
+void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) {
+ DBG ( "Packet received\n" );
+ pkb->ll_protocol = netdev->ll_protocol;
+ list_add_tail ( &pkb->list, &rx_queue );
+}
+
+/**
* Identify network protocol
*
* @v net_proto Network-layer protocol, in network-byte order
@@ -69,7 +85,7 @@ static LIST_HEAD ( rx_queue );
* Identify a network-layer protocol from a protocol number, which
* must be an ETH_P_XXX constant in network-byte order.
*/
-struct net_protocol * net_find_protocol ( uint16_t net_proto ) {
+struct net_protocol * find_net_protocol ( uint16_t net_proto ) {
struct net_protocol *net_protocol;
for ( net_protocol = net_protocols ; net_protocol < net_protocols_end ;
@@ -93,8 +109,9 @@ struct net_protocol * net_find_protocol ( uint16_t net_proto ) {
* Note that even with a static single network device, this function
* can still return NULL.
*/
-struct net_device * net_find_address ( struct net_protocol *net_protocol,
- void *net_addr ) {
+struct net_device *
+find_netdev_by_net_addr ( struct net_protocol *net_protocol,
+ void *net_addr ) {
struct net_address *net_address;
struct net_device *netdev = &static_single_netdev;
@@ -106,60 +123,89 @@ struct net_device * net_find_address ( struct net_protocol *net_protocol,
net_protocol->net_addr_len ) == 0 ) )
return netdev;
}
+
return NULL;
}
/**
- * Transmit packet
+ * Transmit packet via a network device
*
* @v pkb Packet buffer
+ * @v netdev Network device, or NULL
* @ret rc Return status code
*
- * Transmits the packet via the appropriate network device. If this
+ * Transmits the packet via the specified network device. The packet
+ * must begin with a network-layer header, and the @c net_protocol
+ * field must have been filled in. If @c netdev is NULL, the network
+ * device is identified via the packet contents, if possible. If this
* function returns success, it has taken ownership of the packet
* buffer.
*/
-int net_transmit ( struct pk_buff *pkb ) {
+int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) {
struct net_protocol *net_protocol;
struct net_header nethdr;
struct ll_protocol *ll_protocol;
struct ll_header llhdr;
- struct net_device *netdev;
int rc;
/* Perform network-layer routing */
net_protocol = pkb->net_protocol;
nethdr.net_protocol = net_protocol;
- if ( ( rc = net_protocol->route ( pkb, &nethdr ) ) != 0 )
- goto err;
+ if ( ( rc = net_protocol->route ( pkb, &nethdr ) ) != 0 ) {
+ DBG ( "Could not route to %s address %s\n",
+ net_protocol->name,
+ net_protocol->ntoa ( nethdr.dest_net_addr ) );
+ return rc;
+ }
- /* Identify transmitting network device */
- netdev = net_find_address ( net_protocol, nethdr.source_net_addr );
- if ( ! netdev )
- goto err;
+ /* Identify transmitting network device, if not specified */
+ if ( ! netdev ) {
+ netdev = find_netdev_by_net_addr ( net_protocol,
+ nethdr.source_net_addr );
+ if ( ! netdev ) {
+ DBG ( "No network device for %s address %s\n",
+ net_protocol->name,
+ net_protocol->ntoa ( nethdr.source_net_addr ) );
+ return -EHOSTUNREACH;
+ }
+ }
/* Perform link-layer routing */
ll_protocol = netdev->ll_protocol;
llhdr.ll_protocol = ll_protocol;
- llhdr.net_proto = net_protocol->net_proto;
- memcpy ( llhdr.source_ll_addr, netdev->ll_addr,
- ll_protocol->ll_addr_len);
- if ( ( rc = ll_protocol->route ( &nethdr, &llhdr ) ) != 0 )
- goto err;
+ if ( ( rc = ll_protocol->route ( netdev, &nethdr, &llhdr ) ) != 0 ) {
+ DBG ( "No link-layer route to %s address %s\n",
+ net_protocol->name,
+ net_protocol->ntoa ( nethdr.dest_net_addr ) );
+ return rc;
+ }
/* Prepend link-layer header */
pkb_push ( pkb, ll_protocol->ll_header_len );
ll_protocol->fill_llh ( &llhdr, pkb );
/* Transmit packet */
- if ( ( rc = netdev->transmit ( netdev, pkb ) ) != 0 )
- goto err;
-
+ if ( ( rc = netdev->transmit ( netdev, pkb ) ) != 0 ) {
+ DBG ( "Device failed to transmit packet\n" );
+ return rc;
+ }
+
+ DBG ( "Packet transmitted\n" );
return 0;
+}
- err:
- free_pkb ( pkb );
- return rc;
+/**
+ * Transmit packet
+ *
+ * @v pkb Packet buffer
+ * @ret rc Return status code
+ *
+ * Transmits the packet via the appropriate network device. If this
+ * function returns success, it has taken ownership of the packet
+ * buffer.
+ */
+int net_transmit ( struct pk_buff *pkb ) {
+ return net_transmit_via ( pkb, NULL );
}
/**
@@ -174,27 +220,13 @@ int net_transmit ( struct pk_buff *pkb ) {
int net_poll ( void ) {
struct net_device *netdev = &static_single_netdev;
+ DBG ( "Polling network\n" );
netdev->poll ( netdev );
return ( ! list_empty ( &rx_queue ) );
}
/**
- * Add packet to receive queue
- *
- * @v netdev Network device
- * @v pkb Packet buffer
- *
- * The packet is added to the RX queue. Ownership of the packet is
- * transferred to the RX queue; the caller must not touch the packet
- * buffer after calling netdev_rx().
- */
-void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) {
- pkb->ll_protocol = netdev->ll_protocol;
- list_add_tail ( &pkb->list, &rx_queue );
-}
-
-/**
* Remove packet from receive queue
*
* @ret pkb Packet buffer, or NULL
@@ -225,22 +257,26 @@ void net_run ( void ) {
ll_protocol->parse_llh ( pkb, &llhdr );
/* Identify network-layer protocol */
- net_protocol = net_find_protocol ( llhdr.net_proto );
+ net_protocol = find_net_protocol ( llhdr.net_proto );
if ( ! net_protocol ) {
- DBG ( "Unknown network-layer protocol %02x\n",
+ DBG ( "Unknown network-layer protocol %x\n",
ntohs ( llhdr.net_proto ) );
free_pkb ( pkb );
continue;
}
+ pkb->net_protocol = net_protocol;
/* Strip off link-layer header */
pkb_pull ( pkb, ll_protocol->ll_header_len );
/* Hand off to network layer */
if ( net_protocol->rx ( pkb ) != 0 ) {
+ DBG ( "Network-layer protocol refused packet\n" );
free_pkb ( pkb );
continue;
}
+
+ DBG ( "Processed received packet\n" );
}
}