diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2010-06-02 15:22:26 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2010-06-17 08:28:16 +0200 |
commit | 97070487fa67d0a8b04c4e109966bb4c1b40212e (patch) | |
tree | 26c7c116514840d9ac1dcf055030e9706a89ef1a /include | |
parent | 994f95c073caf4df62d1271aef4112ce8aaa8add (diff) | |
download | barebox-97070487fa67d0a8b04c4e109966bb4c1b40212e.tar.gz barebox-97070487fa67d0a8b04c4e109966bb4c1b40212e.tar.xz |
net: Implement a new network stack
The old network stack has some bad limitations:
- network commands are required to call NetLoop() which only returns when
the network layer wants to. Instead we now use a net_poll() function which
returns after handling one packet (or immediately if no packet is
available).
- There can be only one packet handler which makes it impossible to handle
multiple connections
- CamelCaseMakesItHardToRead
The new network stack is implemented as a parallel universe. Currently all
commands still use the old stack. They are converted in subsequent patches.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'include')
-rw-r--r-- | include/net.h | 341 |
1 files changed, 338 insertions, 3 deletions
diff --git a/include/net.h b/include/net.h index de78293840..0ee7ecb8a6 100644 --- a/include/net.h +++ b/include/net.h @@ -15,6 +15,7 @@ #include <driver.h> #include <linux/types.h> #include <param.h> +#include <malloc.h> #include <asm/byteorder.h> /* for nton* / ntoh* stuff */ @@ -186,8 +187,6 @@ typedef struct uchar ar_data[0]; } ARP_t; -#define ARP_HDR_SIZE (8+20) /* Size assuming ethernet */ - /* * ICMP stuff (just enough to handle (host) redirect messages) */ @@ -199,7 +198,7 @@ typedef struct #define ICMP_REDIR_NET 0 /* Redirect Net */ #define ICMP_REDIR_HOST 1 /* Redirect Host */ -typedef struct icmphdr { +typedef struct { uchar type; uchar code; ushort checksum; @@ -415,4 +414,340 @@ void eth_set_current(struct eth_device *eth); struct eth_device *eth_get_current(void); struct eth_device *eth_get_byname(char *name); +/* + * Ethernet header + */ +struct ethernet { + uint8_t et_dest[6]; /* Destination node */ + uint8_t et_src[6]; /* Source node */ + uint16_t et_protlen; /* Protocol or length */ +} __attribute__ ((packed)); + +#define ETHER_HDR_SIZE 14 /* Ethernet header size */ + +#define PROT_IP 0x0800 /* IP protocol */ +#define PROT_ARP 0x0806 /* IP ARP protocol */ +#define PROT_RARP 0x8035 /* IP ARP protocol */ +#define PROT_VLAN 0x8100 /* IEEE 802.1q protocol */ + +#define IPPROTO_ICMP 1 /* Internet Control Message Protocol */ +#define IPPROTO_UDP 17 /* User Datagram Protocol */ + +/* + * Internet Protocol (IP) header. + */ +struct iphdr { + uint8_t hl_v; + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + uint32_t saddr; + uint32_t daddr; + /* The options start here. */ +} __attribute__ ((packed)); + +struct udphdr { + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_ulen; /* udp length */ + uint16_t uh_sum; /* udp checksum */ +} __attribute__ ((packed)); + +/* + * Address Resolution Protocol (ARP) header. + */ +struct arprequest +{ + uint16_t ar_hrd; /* Format of hardware address */ +#define ARP_ETHER 1 /* Ethernet hardware address */ + uint16_t ar_pro; /* Format of protocol address */ + uint8_t ar_hln; /* Length of hardware address */ + uint8_t ar_pln; /* Length of protocol address */ + uint16_t ar_op; /* Operation */ +#define ARPOP_REQUEST 1 /* Request to resolve address */ +#define ARPOP_REPLY 2 /* Response to previous request */ + +#define RARPOP_REQUEST 3 /* Request to resolve address */ +#define RARPOP_REPLY 4 /* Response to previous request */ + + /* + * The remaining fields are variable in size, according to + * the sizes above, and are defined as appropriate for + * specific hardware/protocol combinations. + */ + uint8_t ar_data[0]; +} __attribute__ ((packed)); + +#define ARP_HDR_SIZE (8 + 20) /* Size assuming ethernet */ + +/* + * ICMP stuff (just enough to handle (host) redirect messages) + */ +#define ICMP_ECHO_REPLY 0 /* Echo reply */ +#define ICMP_REDIRECT 5 /* Redirect (change route) */ +#define ICMP_ECHO_REQUEST 8 /* Echo request */ + +/* Codes for REDIRECT. */ +#define ICMP_REDIR_NET 0 /* Redirect Net */ +#define ICMP_REDIR_HOST 1 /* Redirect Host */ + +struct icmphdr { + uint8_t type; + uint8_t code; + uint16_t checksum; + union { + struct { + uint16_t id; + uint16_t sequence; + } echo; + uint32_t gateway; + struct { + uint16_t __unused; + uint16_t mtu; + } frag; + } un; +} __attribute__ ((packed)); + + +/* + * Maximum packet size; used to allocate packet storage. + * TFTP packets can be 524 bytes + IP header + ethernet header. + * Lets be conservative, and go for 38 * 16. (Must also be + * a multiple of 32 bytes). + */ +#define PKTSIZE 1518 + +/**********************************************************************/ +/* + * Globals. + * + * Note: + * + * All variables of type IPaddr_t are stored in NETWORK byte order + * (big endian). + */ + +extern unsigned char *NetRxPackets[PKTBUFSRX];/* Receive packets */ + +void net_set_ip(IPaddr_t ip); +void net_set_serverip(IPaddr_t ip); +void net_set_netmask(IPaddr_t ip); +void net_set_gateway(IPaddr_t ip); +IPaddr_t net_get_ip(void); +IPaddr_t net_get_serverip(void); + +/* Do the work */ +void net_poll(void); + +static inline struct iphdr *net_eth_to_iphdr(char *pkt) +{ + return (struct iphdr *)(pkt + ETHER_HDR_SIZE); +} + +static inline struct udphdr *net_eth_to_udphdr(char *pkt) +{ + return (struct udphdr *)(net_eth_to_iphdr(pkt) + 1); +} + +static inline struct icmphdr *net_eth_to_icmphdr(char *pkt) +{ + return (struct icmphdr *)(net_eth_to_iphdr(pkt) + 1); +} + +static inline char *net_eth_to_icmp_payload(char *pkt) +{ + return (char *)(net_eth_to_icmphdr(pkt) + 1); +} + +static inline char *net_eth_to_udp_payload(char *pkt) +{ + return (char *)(net_eth_to_udphdr(pkt) + 1); +} + +static inline int net_eth_to_udplen(char *pkt) +{ + struct udphdr *udp = net_eth_to_udphdr(pkt); + return ntohs(udp->uh_ulen) - 8; +} + +int net_checksum_ok(unsigned char *, int); /* Return true if cksum OK */ +uint16_t net_checksum(unsigned char *, int); /* Calculate the checksum */ + +void NetReceive(unsigned char *, int); + +/* Print an IP address on the console */ +void print_IPaddr (IPaddr_t); + +/* + * The following functions are a bit ugly, but necessary to deal with + * alignment restrictions on ARM. + * + * We're using inline functions, which had the smallest memory + * footprint in our tests. + */ +/* return IP *in network byteorder* */ +static inline IPaddr_t net_read_ip(void *from) +{ + IPaddr_t ip; + memcpy((void*)&ip, from, sizeof(ip)); + return ip; +} + +/* return uint32 *in network byteorder* */ +static inline uint32_t net_read_uint32(uint32_t *from) +{ + ulong l; + memcpy((void*)&l, (void*)from, sizeof(l)); + return l; +} + +/* write IP *in network byteorder* */ +static inline void net_write_ip(void *to, IPaddr_t ip) +{ + memcpy(to, (void*)&ip, sizeof(ip)); +} + +/* copy IP */ +static inline void net_copy_ip(void *to, void *from) +{ + memcpy(to, from, sizeof(IPaddr_t)); +} + +/* copy ulong */ +static inline void net_copy_uint32(uint32_t *to, uint32_t *from) +{ + memcpy(to, from, sizeof(uint32_t)); +} + +/* Convert an IP address to a string */ +char *ip_to_string (IPaddr_t x, char *s); + +/* Convert a string to ip address */ +int string_to_ip(const char *s, IPaddr_t *ip); + +IPaddr_t getenv_ip(const char *name); +int setenv_ip(const char *name, IPaddr_t ip); + +int string_to_ethaddr(const char *str, char *enetaddr); +void ethaddr_to_string(const unsigned char *enetaddr, char *str); + +/** + * is_zero_ether_addr - Determine if give Ethernet address is all zeros. + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Return true if the address is all zeroes. + */ +static inline int is_zero_ether_addr(const u8 *addr) +{ + return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]); +} + +/** + * is_multicast_ether_addr - Determine if the Ethernet address is a multicast. + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Return true if the address is a multicast address. + * By definition the broadcast address is also a multicast address. + */ +static inline int is_multicast_ether_addr(const u8 *addr) +{ + return (0x01 & addr[0]); +} + +/** + * is_local_ether_addr - Determine if the Ethernet address is locally-assigned one (IEEE 802). + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Return true if the address is a local address. + */ +static inline int is_local_ether_addr(const u8 *addr) +{ + return (0x02 & addr[0]); +} + +/** + * is_broadcast_ether_addr - Determine if the Ethernet address is broadcast + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Return true if the address is the broadcast address. + */ +static inline int is_broadcast_ether_addr(const u8 *addr) +{ + return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff; +} + +/** + * is_valid_ether_addr - Determine if the given Ethernet address is valid + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not + * a multicast address, and is not FF:FF:FF:FF:FF:FF. + * + * Return true if the address is valid. + */ +static inline int is_valid_ether_addr(const u8 *addr) +{ + /* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to + * explicitly check for it here. */ + return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr); +} + +typedef void rx_handler_f(char *packet, unsigned int len); + +void eth_set_current(struct eth_device *eth); +struct eth_device *eth_get_current(void); +struct eth_device *eth_get_byname(char *name); +void net_update_env(void); + +/** + * net_receive - Pass a received packet from an ethernet driver to the protocol stack + * @pkt: Pointer to the packet + * @len: length of the packet + * + * Return 0 if the packet is successfully handled. Can be ignored + */ +int net_receive(unsigned char *pkt, int len); + +struct net_connection { + struct ethernet *et; + struct iphdr *ip; + struct udphdr *udp; + struct icmphdr *icmp; + unsigned char *packet; + struct list_head list; + rx_handler_f *handler; + int proto; +}; + +static inline char *net_alloc_packet(void) +{ + return memalign(32, PKTSIZE); +} + +struct net_connection *net_udp_new(IPaddr_t dest, uint16_t dport, + rx_handler_f *handler); + +struct net_connection *net_icmp_new(IPaddr_t dest, rx_handler_f *handler); + +void net_unregister(struct net_connection *con); + +static inline int net_udp_bind(struct net_connection *con, int sport) +{ + con->udp->uh_sport = ntohs(sport); + return 0; +} + +static inline unsigned char *net_udp_get_payload(struct net_connection *con) +{ + return con->packet + sizeof(struct ethernet) + sizeof(struct iphdr) + + sizeof(struct udphdr); +} + +int net_udp_send(struct net_connection *con, int len); +int net_icmp_send(struct net_connection *con, int len); + #endif /* __NET_H__ */ |