diff --git a/src/include/gpxe/arp.h b/src/include/gpxe/arp.h index 27591d3f..a1f9e349 100644 --- a/src/include/gpxe/arp.h +++ b/src/include/gpxe/arp.h @@ -8,11 +8,12 @@ */ struct net_device; -struct net_header; -struct ll_header; +struct net_protocol; extern int arp_resolve ( struct net_device *netdev, - const struct net_header *nethdr, - struct ll_header *llhdr ); + struct net_protocol *net_protocol, + const void *dest_net_addr, + const void *source_net_addr, + void *dest_ll_addr ); #endif /* _GPXE_ARP_H */ diff --git a/src/include/gpxe/ip.h b/src/include/gpxe/ip.h index 44aee7d1..8eac31a6 100644 --- a/src/include/gpxe/ip.h +++ b/src/include/gpxe/ip.h @@ -11,4 +11,10 @@ struct net_protocol; extern struct net_protocol ipv4_protocol; +extern int add_ipv4_address ( struct net_device *netdev, + struct in_addr address, struct in_addr netmask, + struct in_addr gateway ); +extern void del_ipv4_address ( struct net_device *netdev ); +extern int ipv4_uip_transmit ( struct pk_buff *pkb ); + #endif /* _GPXE_IP_H */ diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index 1879bf1b..68226dc2 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -86,22 +86,6 @@ struct ll_header { struct net_protocol { /** Protocol name */ const char *name; - /** - * Perform network-layer routing - * - * @v pkb Packet buffer - * @v nethdr Generic network-layer header - * @ret rc Return status code - * - * 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 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 ); /** * Process received packet * @@ -141,36 +125,21 @@ struct ll_protocol { /** Protocol name */ const char *name; /** - * Perform link-layer routing + * Transmit network-layer packet via network device * - * @v netdev Network device - * @v nethdr Generic network-layer header - * @ret llhdr Generic link-layer header - * @ret rc Return status code * - * This method should construct the generic link-layer header - * based on the generic network-layer header. + * @v pkb Packet buffer + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v ll_dest Link-layer destination address + * @ret rc Return status code * - * If a link-layer header cannot be constructed (e.g. because - * of a missing ARP cache entry), then this method should - * return an error (after transmitting an ARP request, if - * applicable). + * This method should prepend in the link-layer header + * (e.g. the Ethernet DIX header) and transmit the packet. */ - int ( * route ) ( struct net_device *netdev, - const struct net_header *nethdr, - struct ll_header *llhdr ); - /** - * Fill media-specific link-layer header - * - * @v llhdr Generic link-layer header - * @v pkb Packet buffer - * - * This method should fill in the link-layer header in the - * packet buffer based on information in the generic - * link-layer header. - */ - void ( * fill_llh ) ( const struct ll_header *llhdr, - struct pk_buff *pkb ); + int ( * transmit ) ( struct pk_buff *pkb, struct net_device *netdev, + struct net_protocol *net_protocol, + const void *ll_dest ); /** * Parse media-specific link-layer header * @@ -204,8 +173,8 @@ struct ll_protocol { uint16_t ll_proto; /** Link-layer address length */ uint8_t ll_addr_len; - /** Link-layer header length */ - uint8_t ll_header_len; + /** Link-layer broadcast address */ + const uint8_t *ll_broadcast; }; /** @@ -288,31 +257,6 @@ extern struct net_device static_single_netdev; static_single_netdev.priv = priv_data; \ &static_single_netdev; } ) -/** - * Register network device - * - * @v netdev Network device - * @ret rc Return status code - * - * Adds the network device to the list of network devices. - */ -static inline int -register_netdev ( struct net_device *netdev __attribute__ (( unused )) ) { - return 0; -} - -/** - * Unregister network device - * - * @v netdev Network device - * - * Removes the network device from the list of network devices. - */ -static inline void -unregister_netdev ( struct net_device *netdev __attribute__ (( unused )) ) { - /* Nothing to do */ -} - /** * Free network device * @@ -339,6 +283,27 @@ static inline int netdev_transmit ( struct net_device *netdev, return netdev->transmit ( netdev, pkb ); } +/** + * Transmit network-layer packet + * + * @v pkb Packet buffer + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v ll_dest Destination link-layer address + * @ret rc Return status code + * + * Prepends link-layer headers to the packet buffer and transmits the + * packet via the specified network device. This function takes + * ownership of the packet buffer. + */ +static inline int net_transmit ( struct pk_buff *pkb, + struct net_device *netdev, + struct net_protocol *net_protocol, + const void *ll_dest ) { + return netdev->ll_protocol->transmit ( pkb, netdev, net_protocol, + ll_dest ); +} + /** * Register a link-layer protocol * @@ -363,14 +328,14 @@ static inline int netdev_transmit ( struct net_device *netdev, #define STATIC_SINGLE_NETDEV_ADDRESS( address ) \ struct net_address address __table ( sgl_netdev_addresses, 01 ) +extern int register_netdev ( struct net_device *netdev ); +extern void unregister_netdev ( struct net_device *netdev ); 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 struct pk_buff * net_rx_dequeue ( void ); extern int net_rx_process ( struct pk_buff *pkb ); diff --git a/src/net/aoe.c b/src/net/aoe.c index cfb833f2..693b3605 100644 --- a/src/net/aoe.c +++ b/src/net/aoe.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -116,7 +117,7 @@ static int aoe_send_command ( struct aoe_session *aoe ) { /* Send packet */ start_timer ( &aoe->timer ); - return net_transmit_via ( pkb, aoe->netdev ); + return net_transmit ( pkb, aoe->netdev, &aoe_protocol, aoe->target ); } /** @@ -251,38 +252,11 @@ static int aoe_rx ( struct pk_buff *pkb ) { return rc; } -/** - * Perform AoE network-layer routing - * - * @v pkb Packet buffer - * @ret source Network-layer source address - * @ret dest Network-layer destination address - * @ret rc Return status code - */ -static int aoe_route ( const struct pk_buff *pkb __unused, - struct net_header *nethdr ) { - struct aoehdr *aoehdr = pkb->data; - struct aoe_session *aoe; - - list_for_each_entry ( aoe, &aoe_sessions, list ) { - if ( ( ntohs ( aoehdr->major ) == aoe->major ) && - ( aoehdr->minor == aoe->minor ) ) { - nethdr->flags = PKT_FL_RAW_ADDR; - memcpy ( nethdr->dest_net_addr, aoe->target, - sizeof ( aoe->target ) ); - return 0; - } - } - - return -EHOSTUNREACH; -} - /** AoE protocol */ struct net_protocol aoe_protocol = { .name = "AoE", .net_proto = htons ( ETH_P_AOE ), .rx_process = aoe_rx, - .route = aoe_route, }; NET_PROTOCOL ( aoe_protocol ); @@ -293,7 +267,8 @@ NET_PROTOCOL ( aoe_protocol ); * @v aoe AoE session */ void aoe_open ( struct aoe_session *aoe ) { - memset ( aoe->target, 0xff, sizeof ( aoe->target ) ); + memcpy ( aoe->target, ethernet_protocol.ll_broadcast, + sizeof ( aoe->target ) ); aoe->tag = AOE_TAG_MAGIC; aoe->timer.expired = aoe_timer_expired; list_add ( &aoe->list, &aoe_sessions ); diff --git a/src/net/arp.c b/src/net/arp.c index af7d6e12..66f9bd4c 100644 --- a/src/net/arp.c +++ b/src/net/arp.c @@ -92,42 +92,42 @@ 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 + * @v net_protocol Network-layer protocol + * @v dest_net_addr Destination network-layer address + * @v source_net_addr Source network-layer address + * @ret dest_ll_addr Destination link layer address * @ret rc Return status code * * This function will use the ARP cache to look up the link-layer - * address for the link-layer protocol specified in @c llhdr and the - * network-layer protocol and address as specified in @c nethdr. If + * address for the link-layer protocol associated with the network + * device and the given network-layer protocol and addresses. If * found, the destination link-layer address will be filled in in @c - * llhdr. + * dest_ll_addr. * * If no address is found in the ARP cache, an ARP request will be * transmitted on the specified network device and -ENOENT will be * returned. */ -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; +int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol, + const void *dest_net_addr, const void *source_net_addr, + void *dest_ll_addr ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; const struct arp_entry *arp; struct pk_buff *pkb; struct arphdr *arphdr; int rc; /* Look for existing entry in ARP table */ - arp = arp_find_entry ( ll_protocol, net_protocol, - nethdr->dest_net_addr ); + arp = arp_find_entry ( ll_protocol, net_protocol, 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 ) ); + memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len); return 0; } DBG ( "ARP cache miss: %s %s\n", net_protocol->name, - net_protocol->ntoa ( nethdr->dest_net_addr ) ); + net_protocol->ntoa ( dest_net_addr ) ); /* Allocate ARP packet */ pkb = alloc_pkb ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) + @@ -145,16 +145,17 @@ int arp_resolve ( struct net_device *netdev, const struct net_header *nethdr, arphdr->ar_pln = net_protocol->net_addr_len; arphdr->ar_op = htons ( ARPOP_REQUEST ); memcpy ( pkb_put ( pkb, ll_protocol->ll_addr_len ), - llhdr->source_ll_addr, ll_protocol->ll_addr_len ); + netdev->ll_addr, ll_protocol->ll_addr_len ); memcpy ( pkb_put ( pkb, net_protocol->net_addr_len ), - nethdr->source_net_addr, net_protocol->net_addr_len ); + source_net_addr, net_protocol->net_addr_len ); memset ( pkb_put ( pkb, ll_protocol->ll_addr_len ), 0, ll_protocol->ll_addr_len ); memcpy ( pkb_put ( pkb, net_protocol->net_addr_len ), - nethdr->dest_net_addr, net_protocol->net_addr_len ); + dest_net_addr, net_protocol->net_addr_len ); /* Transmit ARP request */ - if ( ( rc = net_transmit_via ( pkb, netdev ) ) != 0 ) + if ( ( rc = net_transmit ( pkb, netdev, &arp_protocol, + ll_protocol->ll_broadcast ) ) != 0 ) return rc; return -ENOENT; @@ -235,10 +236,10 @@ static int arp_rx ( struct pk_buff *pkb ) { 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 ); + memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln ); /* Send reply */ - net_transmit_via ( pkb, netdev ); + net_transmit ( pkb, netdev, &arp_protocol, arp_target_ha (arphdr ) ); pkb = NULL; done: @@ -246,29 +247,6 @@ static int arp_rx ( struct pk_buff *pkb ) { return 0; } -/** - * Perform ARP network-layer routing - * - * @v pkb Packet buffer - * @ret source Network-layer source address - * @ret dest Network-layer destination address - * @ret rc Return status code - */ -static int arp_route ( const struct pk_buff *pkb, - struct net_header *nethdr ) { - struct arphdr *arphdr = pkb->data; - - memcpy ( nethdr->source_net_addr, arp_sender_ha ( arphdr ), - arphdr->ar_hln ); - memcpy ( nethdr->dest_net_addr, arp_target_ha ( arphdr ), - arphdr->ar_hln ); - nethdr->flags = PKT_FL_RAW_ADDR; - if ( arphdr->ar_op == htons ( ARPOP_REQUEST ) ) - nethdr->flags |= PKT_FL_BROADCAST; - - return 0; -} - /** * Transcribe ARP address * @@ -287,7 +265,6 @@ struct net_protocol arp_protocol = { .name = "ARP", .net_proto = htons ( ETH_P_ARP ), .rx_process = arp_rx, - .route = arp_route, .ntoa = arp_ntoa, }; diff --git a/src/net/ethernet.c b/src/net/ethernet.c index cadcb674..f10bc60f 100644 --- a/src/net/ethernet.c +++ b/src/net/ethernet.c @@ -25,7 +25,6 @@ #include #include #include -#include #include /** @file @@ -38,70 +37,24 @@ static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /** - * Perform Ethernet routing + * Transmit Ethernet packet * - * @v nethdr Generic network-layer header - * @ret llhdr Generic link-layer header - * @ret rc Return status code + * @v pkb Packet buffer + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v ll_dest Link-layer destination address * - * Constructs the generic link-layer header based on the generic - * network-layer header, i.e. maps network-layer addresses (e.g. IPv4 - * addresses) to MAC addresses. - * - * If the destination MAC address cannot be determined, an ARP request - * is sent for the requested network-layer address and -ENOENT is - * returned. + * Prepends the Ethernet link-layer header and transmits the packet. */ -static int eth_route ( struct net_device *netdev, - const struct net_header *nethdr, - struct ll_header *llhdr ) { - int rc; +static int eth_transmit ( struct pk_buff *pkb, struct net_device *netdev, + struct net_protocol *net_protocol, + const void *ll_dest ) { + struct ethhdr *ethhdr = pkb_push ( pkb, ETH_HLEN ); - /* 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->flags & PKT_FL_BROADCAST ) { - memcpy ( llhdr->dest_ll_addr, eth_broadcast, ETH_ALEN ); - } 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 - */ - assert ( nethdr->net_protocol->net_proto == htons(ETH_P_IP) ); - llhdr->dest_ll_addr[0] = 0x01; - llhdr->dest_ll_addr[1] = 0x00; - llhdr->dest_ll_addr[2] = 0x5e; - llhdr->dest_ll_addr[3] = nethdr->dest_net_addr[1] & 0x7f; - llhdr->dest_ll_addr[4] = nethdr->dest_net_addr[2]; - llhdr->dest_ll_addr[5] = nethdr->dest_net_addr[3]; - } else { - /* Otherwise, look up the address using ARP */ - if ( ( rc = arp_resolve ( netdev, nethdr, llhdr ) ) != 0 ) - return rc; - } - - return 0; -} - -/** - * Fill in Ethernet link-layer header - * - * @v pkb Packet buffer - * @v llhdr Generic link-layer header - * - * Fills in the Ethernet link-layer header in the packet buffer based - * on information in the generic link-layer header. - */ -static void eth_fill_llh ( const struct ll_header *llhdr, - struct pk_buff *pkb ) { - struct ethhdr *ethhdr = pkb->data; - - memcpy ( ethhdr->h_dest, llhdr->dest_ll_addr, ETH_ALEN ); - memcpy ( ethhdr->h_source, llhdr->source_ll_addr, ETH_ALEN ); - ethhdr->h_protocol = llhdr->net_proto; + memcpy ( ethhdr->h_dest, ll_dest, ETH_ALEN ); + memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN ); + ethhdr->h_protocol = net_protocol->net_proto; + return netdev_transmit ( netdev, pkb ); } /** @@ -138,7 +91,7 @@ static void eth_parse_llh ( const struct pk_buff *pkb, */ 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; + const uint8_t *eth_addr = ll_addr; sprintf ( buf, "%02x:%02x:%02x:%02x:%02x:%02x", eth_addr[0], eth_addr[1], eth_addr[2], @@ -148,14 +101,13 @@ static const char * eth_ntoa ( const void *ll_addr ) { /** 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, + .name = "Ethernet", + .ll_proto = htons ( ARPHRD_ETHER ), + .ll_addr_len = ETH_ALEN, + .ll_broadcast = eth_broadcast, + .transmit = eth_transmit, + .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 ddc8281d..ae3404cc 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -2,9 +2,11 @@ #include #include #include +#include #include +#include #include - +#include #include @@ -13,6 +15,7 @@ #include #include #include "uip/uip.h" +#include /** @file * @@ -27,121 +30,144 @@ struct net_protocol ipv4_protocol; -/** An IPv4 routing table entry */ -struct ipv4_route { - /** Network address */ - struct in_addr network; +/** An IPv4 address/routing table entry */ +struct ipv4_miniroute { + /** List of miniroutes */ + struct list_head list; + /** Network device */ + struct net_device *netdev; + /** IPv4 address */ + struct in_addr address; /** Subnet mask */ struct in_addr netmask; /** Gateway address */ struct in_addr gateway; - /** Gateway device */ - struct in_addr gatewaydev; }; -enum { - STATIC_SINGLE_NETDEV_ROUTE = 0, - DEFAULT_ROUTE, - NUM_ROUTES -}; - -/** IPv4 routing table */ -static struct ipv4_route routing_table[NUM_ROUTES]; - -#define routing_table_end ( routing_table + NUM_ROUTES ) - -#if 0 -/** - * Set IP address - * - */ -void set_ipaddr ( struct in_addr address ) { - union { - struct in_addr address; - uint16_t uip_address[2]; - } u; - - u.address = address; - uip_sethostaddr ( u.uip_address ); -} +/** List of IPv4 miniroutes */ +static LIST_HEAD ( miniroutes ); /** - * Set netmask + * Add IPv4 interface + * + * @v netdev Network device + * @v address IPv4 address + * @v netmask Subnet mask + * @v gateway Gateway address (or @c INADDR_NONE for no gateway) + * @ret rc Return status code * */ -void set_netmask ( struct in_addr address ) { - union { - struct in_addr address; - uint16_t uip_address[2]; - } u; +int add_ipv4_address ( struct net_device *netdev, struct in_addr address, + struct in_addr netmask, struct in_addr gateway ) { + struct ipv4_miniroute *miniroute; - u.address = address; - uip_setnetmask ( u.uip_address ); -} - -/** - * Set default gateway - * - */ -void set_gateway ( struct in_addr address ) { - union { - struct in_addr address; - uint16_t uip_address[2]; - } u; - - u.address = address; - uip_setdraddr ( u.uip_address ); -} - -/** - * Run the TCP/IP stack - * - * Call this function in a loop in order to allow TCP/IP processing to - * take place. This call takes the stack through a single iteration; - * it will typically be used in a loop such as - * - * @code - * - * struct tcp_connection *my_connection; - * ... - * tcp_connect ( my_connection ); - * while ( ! my_connection->finished ) { - * run_tcpip(); - * } - * - * @endcode - * - * where @c my_connection->finished is set by one of the connection's - * #tcp_operations methods to indicate completion. - */ -void run_tcpip ( void ) { - void *data; - size_t len; - uint16_t type; - int i; + /* Allocate and populate miniroute structure */ + miniroute = malloc ( sizeof ( *miniroute ) ); + if ( ! miniroute ) + return -ENOMEM; + miniroute->netdev = netdev; + miniroute->address = address; + miniroute->netmask = netmask; + miniroute->gateway = gateway; - if ( netdev_poll ( 1, &data, &len ) ) { - /* We have data */ - memcpy ( uip_buf, data, len ); - uip_len = len; - type = ntohs ( *( ( uint16_t * ) ( uip_buf + 12 ) ) ); - if ( type == UIP_ETHTYPE_ARP ) { - uip_arp_arpin(); - } else { - uip_arp_ipin(); - uip_input(); - } - if ( uip_len > 0 ) - uip_transmit(); + /* Add to end of list if we have a gateway, otherwise to start + * of list. + */ + if ( gateway.s_addr != INADDR_NONE ) { + list_add_tail ( &miniroute->list, &miniroutes ); } else { - for ( i = 0 ; i < UIP_CONNS ; i++ ) { - uip_periodic ( i ); - if ( uip_len > 0 ) - uip_transmit(); + list_add ( &miniroute->list, &miniroutes ); + } + return 0; +} + +/** + * Remove IPv4 interface + * + * @v netdev Network device + */ +void del_ipv4_address ( struct net_device *netdev ) { + struct ipv4_miniroute *miniroute; + + list_for_each_entry ( miniroute, &miniroutes, list ) { + if ( miniroute->netdev == netdev ) { + list_del ( &miniroute->list ); + break; } } } -#endif + +/** + * Transmit packet constructed by uIP + * + * @v pkb Packet buffer + * @ret rc Return status code + * + */ +int ipv4_uip_transmit ( struct pk_buff *pkb ) { + struct iphdr *iphdr = pkb->data; + struct ipv4_miniroute *miniroute; + struct net_device *netdev = NULL; + struct in_addr next_hop; + struct in_addr source; + uint8_t ll_dest_buf[MAX_LL_ADDR_LEN]; + const uint8_t *ll_dest = ll_dest_buf; + int rc; + + /* Use routing table to identify next hop and transmitting netdev */ + next_hop = iphdr->dest; + list_for_each_entry ( miniroute, &miniroutes, list ) { + if ( ( ( ( iphdr->dest.s_addr ^ miniroute->address.s_addr ) & + miniroute->netmask.s_addr ) == 0 ) || + ( miniroute->gateway.s_addr != INADDR_NONE ) ) { + netdev = miniroute->netdev; + source = miniroute->address; + if ( miniroute->gateway.s_addr != INADDR_NONE ) + next_hop = miniroute->gateway; + break; + } + } + + /* Abort if no network device identified */ + if ( ! netdev ) { + DBG ( "No route to %s\n", inet_ntoa ( iphdr->dest ) ); + rc = -EHOSTUNREACH; + goto err; + } + + /* Determine link-layer destination address */ + if ( next_hop.s_addr == INADDR_BROADCAST ) { + /* Broadcast address */ + ll_dest = netdev->ll_protocol->ll_broadcast; + } else if ( IN_MULTICAST ( next_hop.s_addr ) ) { + /* Special case: IPv4 multicast over Ethernet. This + * code may need to be generalised once we find out + * what happens for other link layers. + */ + uint8_t *next_hop_bytes = ( uint8_t * ) &next_hop; + ll_dest_buf[0] = 0x01; + ll_dest_buf[0] = 0x00; + ll_dest_buf[0] = 0x5e; + ll_dest_buf[3] = next_hop_bytes[1] & 0x7f; + ll_dest_buf[4] = next_hop_bytes[2]; + ll_dest_buf[5] = next_hop_bytes[3]; + } else { + /* Unicast address: resolve via ARP */ + if ( ( rc = arp_resolve ( netdev, &ipv4_protocol, &next_hop, + &source, ll_dest_buf ) ) != 0 ) { + DBG ( "No ARP entry for %s\n", + inet_ntoa ( iphdr->dest ) ); + goto err; + } + } + + /* Hand off to link layer */ + return net_transmit ( pkb, netdev, &ipv4_protocol, ll_dest ); + + err: + free_pkb ( pkb ); + return rc; +} /** * Process incoming IP packets @@ -167,51 +193,25 @@ static int ipv4_rx ( struct pk_buff *pkb ) { pkb = alloc_pkb ( MAX_LL_HEADER_LEN + uip_len ); if ( ! pkb ) return -ENOMEM; - pkb->net_protocol = &ipv4_protocol; pkb_reserve ( pkb, MAX_LL_HEADER_LEN ); memcpy ( pkb_put ( pkb, uip_len ), uip_buf, uip_len ); - net_transmit ( pkb ); + ipv4_uip_transmit ( pkb ); } return 0; } /** - * Perform IP layer routing + * Convert IPv4 address to dotted-quad notation * - * @v pkb Packet buffer - * @ret source Network-layer source address - * @ret dest Network-layer destination address - * @ret rc Return status code + * @v in IP address + * @ret string IP address in dotted-quad notation */ -static int ipv4_route ( const struct pk_buff *pkb, - struct net_header *nethdr ) { - struct iphdr *iphdr = pkb->data; - struct in_addr *source = ( struct in_addr * ) nethdr->source_net_addr; - struct in_addr *dest = ( struct in_addr * ) nethdr->dest_net_addr; - struct ipv4_route *route; - - /* Route IP packet according to routing table */ - source->s_addr = INADDR_NONE; - dest->s_addr = iphdr->dest.s_addr; - for ( route = routing_table ; route < routing_table_end ; route++ ) { - if ( ( dest->s_addr & route->netmask.s_addr ) - == route->network.s_addr ) { - source->s_addr = route->gatewaydev.s_addr; - if ( route->gateway.s_addr ) - dest->s_addr = route->gateway.s_addr; - break; - } - } - - /* Set broadcast and multicast flags as applicable */ - nethdr->flags = 0; - if ( dest->s_addr == htonl ( INADDR_BROADCAST ) ) { - nethdr->flags = PKT_FL_BROADCAST; - } else if ( IN_MULTICAST ( dest->s_addr ) ) { - nethdr->flags = PKT_FL_MULTICAST; - } - - return 0; +char * inet_ntoa ( struct in_addr in ) { + static char buf[16]; /* "xxx.xxx.xxx.xxx" */ + uint8_t *bytes = ( uint8_t * ) ∈ + + sprintf ( buf, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3] ); + return buf; } /** @@ -222,12 +222,7 @@ static int ipv4_route ( const struct pk_buff *pkb, * */ 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; + return inet_ntoa ( * ( ( struct in_addr * ) net_addr ) ); } /** IPv4 protocol */ @@ -236,7 +231,6 @@ struct net_protocol ipv4_protocol = { .net_proto = htons ( ETH_P_IP ), .net_addr_len = sizeof ( struct in_addr ), .rx_process = ipv4_rx, - .route = ipv4_route, .ntoa = ipv4_ntoa, }; @@ -251,12 +245,3 @@ struct net_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 ) } }, -}; - diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 3d4640a8..1825a55b 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -62,6 +62,50 @@ static struct net_address static_single_netdev_addresses_end[0] /** Recevied packet queue */ static LIST_HEAD ( rx_queue ); +#warning "Remove this static IP address hack" +#include +#include + +/** + * Register network device + * + * @v netdev Network device + * @ret rc Return status code + * + * Adds the network device to the list of network devices. + */ +int register_netdev ( struct net_device *netdev ) { + +#warning "Remove this static IP address hack" + { + const struct in_addr static_address = { htonl ( 0x0afefe01 ) }; + const struct in_addr static_netmask = { htonl ( 0xffffff00 ) }; + const struct in_addr static_gateway = { INADDR_NONE }; + int rc; + + if ( ( rc = add_ipv4_address ( netdev, static_address, + static_netmask, + static_gateway ) ) != 0 ) + return rc; + } + + return 0; +} + +/** + * Unregister network device + * + * @v netdev Network device + * + * Removes the network device from the list of network devices. + */ +void unregister_netdev ( struct net_device *netdev ) { + +#warning "Remove this static IP address hack" + del_ipv4_address ( netdev ); + +} + /** * Add packet to receive queue * @@ -128,88 +172,6 @@ find_netdev_by_net_addr ( struct net_protocol *net_protocol, 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. This - * function takes 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 ) ); - free_pkb ( pkb ); - 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 ) ); - free_pkb ( pkb ); - 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 ) ); - free_pkb ( pkb ); - return rc; - } - - /* Prepend link-layer header */ - pkb_push ( pkb, ll_protocol->ll_header_len ); - ll_protocol->fill_llh ( &llhdr, pkb ); - - /* Hand off packet to network device */ - if ( ( rc = netdev->transmit ( netdev, pkb ) ) != 0 ) { - DBG ( "Device failed to transmit packet\n" ); - return rc; - } - - DBG ( "Packet transmitted\n" ); - return 0; -} - -/** - * Transmit packet - * - * @v pkb Packet buffer - * @ret rc Return status code - * - * Transmits the packet via the appropriate network device. This - * function takes ownership of the packet buffer. - */ -int net_transmit ( struct pk_buff *pkb ) { - return net_transmit_via ( pkb, NULL ); -} - /** * Poll for packet on all network devices * @@ -277,7 +239,8 @@ int net_rx_process ( struct pk_buff *pkb ) { pkb->net_protocol = net_protocol; /* Strip off link-layer header */ - pkb_pull ( pkb, ll_protocol->ll_header_len ); +#warning "Temporary hack" + pkb_pull ( pkb, ETH_HLEN ); /* Hand off to network layer */ if ( ( rc = net_protocol->rx_process ( pkb ) ) != 0 ) { diff --git a/src/net/tcp.c b/src/net/tcp.c index 06ab2eea..5027678b 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -176,9 +176,8 @@ static void tcp_periodic ( void ) { pkb_reserve ( pkb, MAX_LL_HEADER_LEN ); pkb_put ( pkb, uip_len ); memcpy ( pkb->data, uip_buf, uip_len ); - pkb->net_protocol = &ipv4_protocol; - - net_transmit ( pkb ); + + ipv4_uip_transmit ( pkb ); } } }