diff --git a/src/include/gpxe/interface.h b/src/include/gpxe/interface.h new file mode 100644 index 00000000..d0f68b84 --- /dev/null +++ b/src/include/gpxe/interface.h @@ -0,0 +1,90 @@ +#ifndef _GPXE_INTERFACE_H +#define _GPXE_INTERFACE_H + +/** @file + * + * Transport-network layer interface + * + */ + +#include +#include +#include + +struct pk_buff; +struct net_protocol; +struct trans_protocol; +struct tcpip_net_protocol; + +/** + * A transport-layer protocol + */ +struct trans_protocol { + /** Protocol name */ + const char *name; + /** + * Process received packet + * + * @v pkb Packet buffer + * @v netdev Network device + * @v ll_source Link-layer source address + * + * This method takes ownership of the packet buffer. + */ + void ( * rx ) ( struct pk_buff *pkb, struct in_addr *src_net_addr, struct in_addr *dest_net_addr ); + /** + * Transport-layer protocol number + * + * This is a constant of the type IP_XXX + */ + uint8_t trans_proto; +}; + +/** + * A TCPIP supporting protocol + */ +struct tcpip_net_protocol { + /** Network protocol */ + struct net_protocol *net_protocol; + /** Network address family */ + sa_family_t sa_family; + /** Complete transport-layer checksum calculation + * + * @v pkb Packet buffer + * @v trans_proto Transport-layer protocol number + * + * This function expects a network-layer datagram in its packet with the protocol field in the + * IP header to be filled up. It constructs a psuedo-header using the information provided in + * the IP header and computes the checksum over the pseudo-header. The checksum offset in the + * transport layer header can be determined without the need of an offset value as + * + * void *csum_offset = pkb->data + NET_HLEN + csum_offset ( trans_proto ); + * + * where, + * csum_offset ( IP_TCP ) = 16 + * csum_offset ( IP_UDP ) = 6 + */ + void ( * tx_csum ) ( struct pk_buff *pkb ); +}; + +/** + * Register a transport-layer protocol + * + * @v protocol Transport-layer protocol + */ +#define TRANS_PROTOCOL( protocol ) \ + struct trans_protocol protocol __table ( trans_protocols, 01 ) + +#define TCPIP_NET_PROTOCOL( protocol ) \ + struct tcpip_net_protocol protocol __table ( tcpip_net_protocols, 01 ) + +extern void trans_rx ( struct pk_buff *pkb, uint8_t trans_proto, struct in_addr *src, struct in_addr *dest ); +extern int trans_tx ( struct pk_buff *pkb, uint8_t trans_proto, struct sockaddr *dest ); + +extern uint16_t calc_chksum ( void *data, size_t len ); + +/** Do we need these functions? -Nikhil, 24-6-06 */ +extern struct trans_protocol * find_trans_protocol ( uint8_t trans_proto ); +extern struct tcpip_net_protocol * find_tcpip_net_protocol ( sa_family_t sa_family ); + +#endif /* _GPXE_INTERFACE_H */ diff --git a/src/net/interface.c b/src/net/interface.c new file mode 100644 index 00000000..f028d6a5 --- /dev/null +++ b/src/net/interface.c @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Transport-network layer interface + * + * This file contains functions and utilities for the transport-network layer interface + */ + +/** Registered protocols that support TCPIP */ +static struct tcpip_net_protocol tcpip_net_protocols[0] __table_start ( tcpip_net_protocols ); +static struct tcpip_net_protocol tcpip_net_protocols_end[0] __table_end ( tcpip_net_protocols ); + +struct trans_protocol; + +/** Registered transport-layer protocols */ +static struct trans_protocol trans_protocols[0] __table_start ( trans_protocols ); +static struct trans_protocol trans_protocols_end[0] __table_end ( trans_protocols ); + +/** Identify TCPIP net protocol + * + * @v sa_family Network address family + * @ret tcpip Protocol supporting TCPIP, or NULL + */ +static struct tcpip_net_protocol * tcpip_find_protocol ( sa_family_t sa_family ) { + struct tcpip_net_protocol *tcpip; + + for ( tcpip = tcpip_net_protocols; tcpip < tcpip_net_protocols_end; tcpip++ ) { + if ( tcpip->sa_family == sa_family ) { + return tcpip; + } + } + return NULL; +} + +/** Identify transport-layer protocol + * + * @v trans_proto Transport-layer protocol number, IP_XXX + * @ret trans_protocol Transport-layer protocol, or NULL + */ +struct trans_protocol* find_trans_protocol ( uint8_t trans_proto ) { + struct trans_protocol *trans_protocol; + + for ( trans_protocol = trans_protocols; trans_protocol <= trans_protocols_end; ++trans_protocol ) { + if ( trans_protocol->trans_proto == trans_proto ) { + return trans_protocol; + } + } + return NULL; +} + +/** Process a received packet + * + * @v pkb Packet buffer + * @v trans_proto Transport-layer protocol number + * @v src Source network-layer address + * @v dest Destination network-layer address + * + * This function expects a transport-layer segment from the network-layer + */ +void trans_rx ( struct pk_buff *pkb, uint8_t trans_proto, struct in_addr *src, struct in_addr *dest ) { + struct trans_protocol *trans_protocol; + + /* Identify the transport layer protocol */ + for ( trans_protocol = trans_protocols; trans_protocol <= trans_protocols_end; ++trans_protocol ) { + if ( trans_protocol->trans_proto == trans_proto ) { + DBG ( "Packet sent to %s module", trans_protocol->name ); + trans_protocol->rx ( pkb, src, dest ); + } + } +} + +/** Transmit a transport-layer segment + * + * @v pkb Packet buffer + * @v trans_proto Transport-layer protocol + * @v sock Destination socket address + * @ret Status + */ +int trans_tx ( struct pk_buff *pkb, uint8_t trans_proto, struct sockaddr *sock ) { + + /* Identify the network layer protocol and send it using xxx_tx() */ + switch ( sock->sa_family ) { + case AF_INET: /* IPv4 network family */ + return ipv4_tx ( pkb, trans_proto, &sock->sin.sin_addr ); + case AF_INET6: /* IPv6 network family */ + return ipv6_tx ( pkb, trans_proto, &sock->sin6.sin6_addr ); + default: + DBG ( "Network family %d not supported", sock->sa_family ); + } + return -EPROTONOSUPPORT; +} + +/** + * Calculate internet checksum + * + * @v data Pointer to the data + * @v len Length of data to be checksummed + * @ret chksum 16 bit internet checksum + * + * This function calculates the internet checksum (refer RFC1071) for len bytes beginning at the location data + */ +uint16_t calc_chksum ( void *data, size_t len ) { + register long sum = 0; + uint16_t checksum; + unsigned short *temp; + while ( len > 1 ) { + temp = (unsigned short*) data++; + sum += *temp; + len -= 2; + } + if ( len > 0 ) { + sum += *(unsigned char *)data; + } + while ( sum >> 16 ) { + sum = ( sum & 0xffff ) + ( sum >> 16 ); + } + checksum = ~sum; + return checksum; +} + +