blob: b2ade7dd262ca6f31f5fb78030e7c6812add7076 [file] [log] [blame]
#include <ros/common.h>
#include <assert.h>
#include <socket.h>
#include <bits/netinet.h>
#include <net.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/tcp_impl.h>
#include <ros/errno.h>
#include <net/nic_common.h>
/* statically configured next gateway */
const uint8_t GTWAY[6] = {0xda, 0x76, 0xe7, 0x4c, 0xca, 0x7e};
/* TODO: ip id unique for all ip packets? or is it unique for a flow? */
// can do atomic increment at a minimum
static uint16_t ip_id = 0;
/* TODO: build arp table, and look up */
int eth_send(struct pbuf *p, struct in_addr *dest) {
uint32_t bytes_sent;
printk("size of pbuf_header movement %d\n", sizeof(struct ethernet_hdr));
if (pbuf_header(p, sizeof(struct ethernet_hdr)) != 0){
warn("eth_send buffer ran out");
/* unsuccessful, needs to allocate */
return -ENOBUFS;
}
struct ethernet_hdr *ethhdr = (struct ethernet_hdr *)p->payload;
// TODO: for now just forward to gateway
memcpy(ethhdr->dst_mac, GTWAY, 6);
memcpy(ethhdr->src_mac, device_mac, 6);
ethhdr->eth_type = htons(IP_ETH_TYPE);
/* The reason for not sending to send_nic for each pbuf in the chain
* is so that we can send from multi-buffer later.
*/
if (send_pbuf){
bytes_sent = send_pbuf(p);
return bytes_sent;
}
else {
warn("no pbuf send function \n");
return -1;
}
/* is the address local , if no, search for MAC of the gateway and dest to gateway */
/* if address is local, use arp etc */
}
/* while it would be nice to write a generic send_pbuf it is impossible to do so in
* efficiently.
*/
/* Assume no ip options */
int ip_output(struct pbuf *p, struct in_addr *src, struct in_addr *dest,
uint8_t ttl, uint8_t tos, uint8_t proto) {
struct pbuf *q;
struct ip_hdr *iphdr;
printk ("ip output reached\n");
/* TODO: Check for IP_HDRINCL */
if (dest->s_addr == IP_HDRINCL) {
/*send right away since */
warn("header included in the ip packets");
return -1;
}
if (pbuf_header(p, IP_HDR_SZ)) {
warn("buffer ran out");
/* unsuccessful, needs to allocate */
return -ENOBUFS;
}
iphdr = (struct ip_hdr *) p->payload;
/* successful */
iphdr->version = IPPROTO_IPV4;
/* assume no IP options */
iphdr->hdr_len = IP_HDR_SZ >> 2;
if (tos != 0) {
iphdr->tos = htons(tos);
}
else {
iphdr->tos = 0;
}
iphdr->packet_len = htons(p->tot_len);
// TODO: NET_LOCK
iphdr->id = htons (ip_id); // 1
ip_id++;
iphdr->flags_frags = htons(0); // 4000 may fragment
iphdr->protocol = proto;
iphdr->ttl = ttl; //DEFAULT_TTL;
/* Eventually if we support more than one device this may change */
printk("src ip %x, dest ip %x \n", src->s_addr, dest->s_addr);
iphdr->src_addr = htonl(src->s_addr);
iphdr->dst_addr = (dest->s_addr);
/* force hardware checksum
* TODO: provide option to do both hardware/software checksum
*/
/* Since the IP header is set already, we can compute the checksum. */
/* TODO: Use the card to calculate the checksum */
iphdr->checksum = 0;
iphdr->checksum = ip_checksum(iphdr); //7ab6
if (p->tot_len > DEFAULT_MTU) /*MAX MTU? header included */
return -1;//ip_frag(p, dest);
else
return eth_send(p, dest);
}
int ip_input(struct pbuf *p) {
uint32_t iphdr_hlen, iphdr_len;
struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
//printk("start of ip %p \n", p->payload);
//print_pbuf(p);
/* use that info to build arp table */
if (iphdr->version != 4) {
warn("ip version not 4!\n");
pbuf_free(p);
return -1;
}
iphdr_hlen = iphdr->hdr_len * 4;
iphdr_len = ntohs(iphdr->packet_len);
// printk("ip input coming from %x of size %d", ntohs(iphdr->dst_addr), iphdr_len);
/* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
if (iphdr_hlen > p->len) {
warn("IP header (len 0x%X) does not fit in first pbuf (len %X), IP packet dropped.\n",
iphdr_hlen, p->len);
}
if (iphdr_len > p->tot_len) {
warn("IP (len %X) is longer than pbuf (len %X), IP packet dropped.\n",
iphdr_len, p->tot_len);
}
/* free (drop) packet pbufs */
pbuf_free(p);
return -1;
}
if (ip_checksum(iphdr) != 0) {
warn("checksum failed \n");
pbuf_free(p);
return -1;
}
/* check if it is destined for me? */
/* XXX: IP address for the interface is IP_ANY */
if (ntohl(iphdr->dst_addr) != LOCAL_IP_ADDR.s_addr){
printk("dest ip in network order%x\n", ntohl(iphdr->dst_addr));
printk("dest ip in network order%x\n", LOCAL_IP_ADDR.s_addr);
warn("ip mismatch \n");
pbuf_free(p);
/* TODO:forward packets */
// ip_forward(p, iphdr, inp);
}
if ((ntohs(iphdr->flags_frags) & (IP_OFFMASK | IP_MF)) != 0){
panic ("ip fragment detected\n");
pbuf_free(p);
}
//printk ("loc head %p, loc protocol %p\n", iphdr, &iphdr->protocol);
/* currently a noop, compared to the memory wasted, cutting out ipheader is not really saving much */
// pbuf_realloc(p, iphdr_len);
switch (iphdr->protocol) {
case IPPROTO_UDP:
return udp_input(p);
case IPPROTO_TCP:
tcp_input(p);
// XXX: error handling for tcp
return 0;
default:
printk("IP protocol type %02x\n", iphdr->protocol);
warn("protocol not supported! \n");
}
return -1;
}
void print_ipheader(struct ip_hdr* iph){
}