david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Network layer now works as a proof of concept

This commit is contained in:
Michael Brown 2006-04-28 14:13:50 +00:00
parent 1488cd3b73
commit 129c6c3968
6 changed files with 291 additions and 111 deletions

View File

@ -7,10 +7,12 @@
* *
*/ */
struct net_device;
struct net_header; struct net_header;
struct ll_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 ); struct ll_header *llhdr );
#endif /* _GPXE_ARP_H */ #endif /* _GPXE_ARP_H */

View File

@ -11,12 +11,16 @@
#include <gpxe/tables.h> #include <gpxe/tables.h>
struct pk_buff; struct pk_buff;
struct net_device;
struct net_protocol; struct net_protocol;
struct ll_protocol; struct ll_protocol;
/** Maximum length of a link-layer address */ /** Maximum length of a link-layer address */
#define MAX_LL_ADDR_LEN 6 #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 */ /** Maximum length of a network-layer address */
#define MAX_NET_ADDR_LEN 4 #define MAX_NET_ADDR_LEN 4
@ -32,37 +36,37 @@ struct ll_protocol;
struct net_header { struct net_header {
/** Network-layer protocol */ /** Network-layer protocol */
struct net_protocol *net_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. * values.
*/ */
int dest_flags; int flags;
/** Network-layer destination address */ /** Network-layer destination address */
uint8_t dest_net_addr[MAX_NET_ADDR_LEN]; uint8_t dest_net_addr[MAX_NET_ADDR_LEN];
/** Network-layer source address */ /** Network-layer source address */
uint8_t source_net_addr[MAX_NET_ADDR_LEN]; uint8_t source_net_addr[MAX_NET_ADDR_LEN];
}; };
/** Address is a broadcast address */ /** Packet is a broadcast packet */
#define NETADDR_FL_BROADCAST 0x01 #define PKT_FL_BROADCAST 0x01
/** Address is a multicast address */ /** Packet is a multicast packet */
#define NETADDR_FL_MULTICAST 0x02 #define PKT_FL_MULTICAST 0x02
/** Address is a raw hardware address */ /** Addresses are raw hardware addresses */
#define NETADDR_FL_RAW 0x04 #define PKT_FL_RAW_ADDR 0x04
/** A generic link-layer header */ /** A generic link-layer header */
struct ll_header { struct ll_header {
/** Link-layer protocol */ /** Link-layer protocol */
struct ll_protocol *ll_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. * values.
*/ */
int dest_flags; int flags;
/** Link-layer destination address */ /** Link-layer destination address */
uint8_t dest_ll_addr[MAX_LL_ADDR_LEN]; uint8_t dest_ll_addr[MAX_LL_ADDR_LEN];
/** Link-layer source address */ /** Link-layer source address */
@ -80,21 +84,21 @@ struct ll_header {
* *
*/ */
struct net_protocol { struct net_protocol {
/** Protocol name */
const char *name;
/** /**
* Perform network-layer routing * Perform network-layer routing
* *
* @v pkb Packet buffer * @v pkb Packet buffer
* @ret source Network-layer source address * @v nethdr Generic network-layer header
* @ret dest Network-layer destination address
* @ret rc Return status code * @ret rc Return status code
* *
* This method should fill in the source and destination * This method should fill in the network header with enough
* addresses with enough information to allow the link layer * information to allow the link layer to route the packet.
* to route the packet.
* *
* For example, in the case of IPv4, this method should fill * For example, in the case of IPv4, this method should fill
* in @c source with the IP addresses of the local adapter and * in the IP addresses of the local adapter and the next hop
* @c dest with the next hop destination (e.g. the gateway). * destination (e.g. the gateway).
*/ */
int ( * route ) ( const struct pk_buff *pkb, int ( * route ) ( const struct pk_buff *pkb,
struct net_header *nethdr ); struct net_header *nethdr );
@ -108,6 +112,19 @@ struct net_protocol {
* the packet buffer. * the packet buffer.
*/ */
int ( * rx ) ( struct pk_buff *pkb ); 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 /** Network-layer protocol
* *
* This is an ETH_P_XXX constant, in network-byte order * This is an ETH_P_XXX constant, in network-byte order
@ -122,9 +139,12 @@ struct net_protocol {
* *
*/ */
struct ll_protocol { struct ll_protocol {
/** Protocol name */
const char *name;
/** /**
* Perform link-layer routing * Perform link-layer routing
* *
* @v netdev Network device
* @v nethdr Generic network-layer header * @v nethdr Generic network-layer header
* @ret llhdr Generic link-layer header * @ret llhdr Generic link-layer header
* @ret rc Return status code * @ret rc Return status code
@ -137,7 +157,8 @@ struct ll_protocol {
* return an error (after transmitting an ARP request, if * return an error (after transmitting an ARP request, if
* applicable). * applicable).
*/ */
int ( * route ) ( const struct net_header *nethdr, int ( * route ) ( struct net_device *netdev,
const struct net_header *nethdr,
struct ll_header *llhdr ); struct ll_header *llhdr );
/** /**
* Fill media-specific link-layer header * Fill media-specific link-layer header
@ -164,6 +185,19 @@ struct ll_protocol {
void ( * parse_llh ) ( const struct pk_buff *pkb, void ( * parse_llh ) ( const struct pk_buff *pkb,
struct ll_header *llhdr ); 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 /** Link-layer protocol
* *
* This is an ARPHRD_XXX constant, in network byte order. * This is an ARPHRD_XXX constant, in network byte order.
@ -290,13 +324,30 @@ free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
/* Nothing to do */ /* Nothing to do */
} }
/**
* 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 * Register a link-layer protocol
* *
* @v protocol Link-layer protocol * @v protocol Link-layer protocol
*/ */
#define LL_PROTOCOL( 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 * Register a network-layer protocol
@ -304,7 +355,7 @@ free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
* @v protocol Network-layer protocol * @v protocol Network-layer protocol
*/ */
#define NET_PROTOCOL( 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 * 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 * @v net_address Network-layer address
*/ */
#define STATIC_SINGLE_NETDEV_ADDRESS( 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 void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb );
extern struct net_device * net_find_address ( struct net_protocol *net_proto,
void *net_addr );
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_transmit ( struct pk_buff *pkb );
extern int net_poll ( void ); 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 ); extern struct pk_buff * net_rx_dequeue ( void );
#endif /* _GPXE_NETDEVICE_H */ #endif /* _GPXE_NETDEVICE_H */

View File

@ -91,6 +91,7 @@ arp_find_entry ( struct ll_protocol *ll_protocol,
/** /**
* Look up media-specific link-layer address in the ARP cache * Look up media-specific link-layer address in the ARP cache
* *
* @v netdev Network device
* @v nethdr Generic network-layer header * @v nethdr Generic network-layer header
* @ret llhdr Generic link-layer header * @ret llhdr Generic link-layer header
* @ret rc Return status code * @ret rc Return status code
@ -102,9 +103,11 @@ arp_find_entry ( struct ll_protocol *ll_protocol,
* llhdr. * llhdr.
* *
* If no address is found in the ARP cache, an ARP request will be * 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 net_protocol *net_protocol = nethdr->net_protocol;
struct ll_protocol *ll_protocol = llhdr->ll_protocol; struct ll_protocol *ll_protocol = llhdr->ll_protocol;
const struct arp_entry *arp; 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, arp = arp_find_entry ( ll_protocol, net_protocol,
nethdr->dest_net_addr ); nethdr->dest_net_addr );
if ( arp ) { 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, memcpy ( llhdr->dest_ll_addr, arp->ll_addr,
sizeof ( llhdr->dest_ll_addr ) ); sizeof ( llhdr->dest_ll_addr ) );
return 0; return 0;
} }
DBG ( "ARP cache miss: %s %s\n", net_protocol->name,
net_protocol->ntoa ( nethdr->dest_net_addr ) );
/* Allocate ARP packet */ /* 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 ) ); 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
if ( ! pkb ) if ( ! pkb )
return -ENOMEM; return -ENOMEM;
pkb->net_protocol = &arp_protocol; pkb->net_protocol = &arp_protocol;
pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
/* Build up ARP request */ /* Build up ARP request */
arphdr = pkb_put ( pkb, sizeof ( *arphdr ) ); 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 ); nethdr->dest_net_addr, net_protocol->net_addr_len );
/* Transmit ARP request */ /* Transmit ARP request */
if ( ( rc = net_transmit ( pkb ) ) != 0 ) { if ( ( rc = net_transmit_via ( pkb, netdev ) ) != 0 ) {
free_pkb ( pkb ); free_pkb ( pkb );
return rc; return rc;
} }
@ -175,7 +184,7 @@ static int arp_rx ( struct pk_buff *pkb ) {
/* Identify link-layer and network-layer protocols */ /* Identify link-layer and network-layer protocols */
ll_protocol = pkb->ll_protocol; ll_protocol = pkb->ll_protocol;
net_protocol = net_find_protocol ( arphdr->ar_pro ); net_protocol = find_net_protocol ( arphdr->ar_pro );
if ( ! net_protocol ) if ( ! net_protocol )
goto done; goto done;
@ -192,10 +201,14 @@ static int arp_rx ( struct pk_buff *pkb ) {
memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ), memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
arphdr->ar_hln ); arphdr->ar_hln );
merge = 1; 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 */ /* 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 ) if ( ! netdev )
goto done; goto done;
@ -208,6 +221,9 @@ static int arp_rx ( struct pk_buff *pkb ) {
arphdr->ar_hln ); arphdr->ar_hln );
memcpy ( arp->net_addr, arp_sender_pa ( arphdr ), memcpy ( arp->net_addr, arp_sender_pa ( arphdr ),
arphdr->ar_pln); 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 */ /* 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; goto done;
/* Change request to a reply, and send it */ /* 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 ); arphdr->ar_op = htons ( ARPOP_REPLY );
memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ), memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
arphdr->ar_hln + arphdr->ar_pln ); arphdr->ar_hln + arphdr->ar_pln );
memcpy ( arp_target_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln ); 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; pkb = NULL;
done: done:
@ -243,18 +262,33 @@ static int arp_route ( const struct pk_buff *pkb,
arphdr->ar_hln ); arphdr->ar_hln );
memcpy ( nethdr->dest_net_addr, arp_target_ha ( arphdr ), memcpy ( nethdr->dest_net_addr, arp_target_ha ( arphdr ),
arphdr->ar_hln ); arphdr->ar_hln );
nethdr->dest_flags = NETADDR_FL_RAW; nethdr->flags = PKT_FL_RAW_ADDR;
if ( arphdr->ar_op == htons ( ARPOP_REQUEST ) ) if ( arphdr->ar_op == htons ( ARPOP_REQUEST ) )
nethdr->dest_flags |= NETADDR_FL_BROADCAST; nethdr->flags |= PKT_FL_BROADCAST;
return 0; 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 */ /** ARP protocol */
struct net_protocol arp_protocol = { struct net_protocol arp_protocol = {
.name = "ARP",
.net_proto = htons ( ETH_P_ARP ), .net_proto = htons ( ETH_P_ARP ),
.rx = arp_rx, .rx = arp_rx,
.route = arp_route, .route = arp_route,
.ntoa = arp_ntoa,
}; };
NET_PROTOCOL ( arp_protocol ); NET_PROTOCOL ( arp_protocol );

View File

@ -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 * is sent for the requested network-layer address and -ENOENT is
* returned. * 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 ) { struct ll_header *llhdr ) {
int rc; 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 */ /* Work out the destination MAC address */
if ( nethdr->dest_flags & NETADDR_FL_RAW ) { if ( nethdr->flags & PKT_FL_BROADCAST ) {
memcpy ( llhdr->dest_ll_addr, nethdr->dest_net_addr, ETH_ALEN);
} else if ( nethdr->dest_flags & NETADDR_FL_BROADCAST ) {
memcpy ( llhdr->dest_ll_addr, eth_broadcast, ETH_ALEN ); 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 /* IP multicast is a special case; there exists a
* direct mapping from IP address to MAC address * 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]; llhdr->dest_ll_addr[5] = nethdr->dest_net_addr[3];
} else { } else {
/* Otherwise, look up the address using ARP */ /* Otherwise, look up the address using ARP */
if ( ( rc = arp_resolve ( nethdr, llhdr ) ) != 0 ) if ( ( rc = arp_resolve ( netdev, nethdr, llhdr ) ) != 0 )
return rc; return rc;
} }
@ -116,22 +121,40 @@ static void eth_parse_llh ( const struct pk_buff *pkb,
llhdr->net_proto = ethhdr->h_protocol; llhdr->net_proto = ethhdr->h_protocol;
if ( memcmp ( ethhdr->h_dest, eth_broadcast, ETH_ALEN ) == 0 ) { 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 ) { } else if ( ethhdr->h_dest[0] & 0x01 ) {
llhdr->dest_flags = NETADDR_FL_MULTICAST; llhdr->flags = PKT_FL_MULTICAST;
} else { } 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 */ /** Ethernet protocol */
struct ll_protocol ethernet_protocol = { struct ll_protocol ethernet_protocol = {
.name = "Ethernet",
.ll_proto = htons ( ARPHRD_ETHER ), .ll_proto = htons ( ARPHRD_ETHER ),
.ll_addr_len = ETH_ALEN, .ll_addr_len = ETH_ALEN,
.ll_header_len = ETH_HLEN, .ll_header_len = ETH_HLEN,
.route = eth_route, .route = eth_route,
.fill_llh = eth_fill_llh, .fill_llh = eth_fill_llh,
.parse_llh = eth_parse_llh, .parse_llh = eth_parse_llh,
.ntoa = eth_ntoa,
}; };
LL_PROTOCOL ( ethernet_protocol ); LL_PROTOCOL ( ethernet_protocol );

View File

@ -1,6 +1,7 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <byteswap.h> #include <byteswap.h>
#include <vsprintf.h>
#include <gpxe/in.h> #include <gpxe/in.h>
@ -153,7 +154,8 @@ static int ipv4_rx ( struct pk_buff *pkb ) {
/* Transfer to uIP buffer. Horrendously space-inefficient, /* Transfer to uIP buffer. Horrendously space-inefficient,
* but will do as a proof-of-concept for now. * 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 */ /* Hand to uIP for processing */
uip_input (); uip_input ();
@ -198,22 +200,40 @@ static int ipv4_route ( const struct pk_buff *pkb,
} }
/* Set broadcast and multicast flags as applicable */ /* Set broadcast and multicast flags as applicable */
nethdr->dest_flags = 0; nethdr->flags = 0;
if ( dest->s_addr == htonl ( INADDR_BROADCAST ) ) { 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 ) ) { } else if ( IN_MULTICAST ( dest->s_addr ) ) {
nethdr->dest_flags = NETADDR_FL_MULTICAST; nethdr->flags = PKT_FL_MULTICAST;
} }
return 0; 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 */ /** IPv4 protocol */
struct net_protocol 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 ), .net_addr_len = sizeof ( struct in_addr ),
.rx = ipv4_rx, .rx = ipv4_rx,
.route = ipv4_route, .route = ipv4_route,
.ntoa = ipv4_ntoa,
}; };
NET_PROTOCOL ( ipv4_protocol ); NET_PROTOCOL ( ipv4_protocol );
@ -221,6 +241,18 @@ NET_PROTOCOL ( ipv4_protocol );
/** IPv4 address for the static single net device */ /** IPv4 address for the static single net device */
struct net_address static_single_ipv4_address = { struct net_address static_single_ipv4_address = {
.net_protocol = &ipv4_protocol, .net_protocol = &ipv4_protocol,
#warning "Remove this static-IP hack"
.net_addr = { 0x0a, 0xfe, 0xfe, 0x01 },
}; };
STATIC_SINGLE_NETDEV_ADDRESS ( static_single_ipv4_address ); 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 ) } },
};

View File

@ -60,6 +60,22 @@ static struct net_address static_single_netdev_addresses_end[0]
/** Recevied packet queue */ /** Recevied packet queue */
static LIST_HEAD ( rx_queue ); 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 * Identify network protocol
* *
@ -69,7 +85,7 @@ static LIST_HEAD ( rx_queue );
* Identify a network-layer protocol from a protocol number, which * Identify a network-layer protocol from a protocol number, which
* must be an ETH_P_XXX constant in network-byte order. * 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; struct net_protocol *net_protocol;
for ( net_protocol = net_protocols ; net_protocol < net_protocols_end ; 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 * Note that even with a static single network device, this function
* can still return NULL. * can still return NULL.
*/ */
struct net_device * net_find_address ( struct net_protocol *net_protocol, struct net_device *
void *net_addr ) { find_netdev_by_net_addr ( struct net_protocol *net_protocol,
void *net_addr ) {
struct net_address *net_address; struct net_address *net_address;
struct net_device *netdev = &static_single_netdev; struct net_device *netdev = &static_single_netdev;
@ -106,9 +123,77 @@ struct net_device * net_find_address ( struct net_protocol *net_protocol,
net_protocol->net_addr_len ) == 0 ) ) net_protocol->net_addr_len ) == 0 ) )
return netdev; return netdev;
} }
return NULL; return NULL;
} }
/**
* 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 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_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;
int rc;
/* Perform network-layer routing */
net_protocol = pkb->net_protocol;
nethdr.net_protocol = net_protocol;
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, 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;
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 ) {
DBG ( "Device failed to transmit packet\n" );
return rc;
}
DBG ( "Packet transmitted\n" );
return 0;
}
/** /**
* Transmit packet * Transmit packet
* *
@ -120,46 +205,7 @@ struct net_device * net_find_address ( struct net_protocol *net_protocol,
* buffer. * buffer.
*/ */
int net_transmit ( struct pk_buff *pkb ) { int net_transmit ( struct pk_buff *pkb ) {
struct net_protocol *net_protocol; return net_transmit_via ( pkb, NULL );
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;
/* Identify transmitting network device */
netdev = net_find_address ( net_protocol, nethdr.source_net_addr );
if ( ! netdev )
goto err;
/* 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;
/* 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;
return 0;
err:
free_pkb ( pkb );
return rc;
} }
/** /**
@ -174,26 +220,12 @@ int net_transmit ( struct pk_buff *pkb ) {
int net_poll ( void ) { int net_poll ( void ) {
struct net_device *netdev = &static_single_netdev; struct net_device *netdev = &static_single_netdev;
DBG ( "Polling network\n" );
netdev->poll ( netdev ); netdev->poll ( netdev );
return ( ! list_empty ( &rx_queue ) ); 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 * Remove packet from receive queue
* *
@ -225,22 +257,26 @@ void net_run ( void ) {
ll_protocol->parse_llh ( pkb, &llhdr ); ll_protocol->parse_llh ( pkb, &llhdr );
/* Identify network-layer protocol */ /* Identify network-layer protocol */
net_protocol = net_find_protocol ( llhdr.net_proto ); net_protocol = find_net_protocol ( llhdr.net_proto );
if ( ! net_protocol ) { if ( ! net_protocol ) {
DBG ( "Unknown network-layer protocol %02x\n", DBG ( "Unknown network-layer protocol %x\n",
ntohs ( llhdr.net_proto ) ); ntohs ( llhdr.net_proto ) );
free_pkb ( pkb ); free_pkb ( pkb );
continue; continue;
} }
pkb->net_protocol = net_protocol;
/* Strip off link-layer header */ /* Strip off link-layer header */
pkb_pull ( pkb, ll_protocol->ll_header_len ); pkb_pull ( pkb, ll_protocol->ll_header_len );
/* Hand off to network layer */ /* Hand off to network layer */
if ( net_protocol->rx ( pkb ) != 0 ) { if ( net_protocol->rx ( pkb ) != 0 ) {
DBG ( "Network-layer protocol refused packet\n" );
free_pkb ( pkb ); free_pkb ( pkb );
continue; continue;
} }
DBG ( "Processed received packet\n" );
} }
} }