mirror of
				https://github.com/xcat2/xNBA.git
				synced 2025-10-31 11:22:29 +00:00 
			
		
		
		
	Network layer now works as a proof of concept
This commit is contained in:
		| @@ -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 */ | ||||
|   | ||||
| @@ -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. | ||||
| @@ -290,13 +324,30 @@ free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) { | ||||
| 	/* 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 | ||||
|  * | ||||
|  * @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 */ | ||||
|   | ||||
| @@ -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 ); | ||||
|   | ||||
| @@ -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 ); | ||||
|   | ||||
| @@ -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 ) } }, | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -60,6 +60,22 @@ static struct net_address static_single_netdev_addresses_end[0] | ||||
| /** Recevied packet 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 | ||||
|  * | ||||
| @@ -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,9 +123,77 @@ struct net_device * net_find_address ( struct net_protocol *net_protocol, | ||||
| 				net_protocol->net_addr_len ) == 0 ) ) | ||||
| 			return netdev; | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
|  * | ||||
| @@ -120,46 +205,7 @@ struct net_device * net_find_address ( struct net_protocol *net_protocol, | ||||
|  * buffer. | ||||
|  */ | ||||
| int net_transmit ( struct pk_buff *pkb ) { | ||||
| 	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; | ||||
|  | ||||
| 	/* 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; | ||||
| 	return net_transmit_via ( pkb, NULL ); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -174,26 +220,12 @@ 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 | ||||
|  * | ||||
| @@ -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" ); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user