Udp packet can now be delivered to the application and sent correctly.
[akaros.git] / kern / src / net / ip.c
1 #include <ros/common.h>
2 #include <assert.h>
3 #include <socket.h>
4 #include <bits/netinet.h>
5 #include <net.h>
6 #include <net/ip.h>
7 #include <net/udp.h>
8 #include <ros/errno.h>
9 #include <arch/nic_common.h>
10
11 /* statically configured next gateway */
12 const uint8_t GTWAY[6] = {0xda, 0x76, 0xe7, 0x4c, 0xca, 0x7e};
13
14 /* TODO: ip id unique for all ip packets? or is it unique for a flow? */
15 // can do atomic increment at a minimum
16 static uint16_t ip_id = 0;
17 struct in_addr global_ip = {IP_ADDR};
18
19 /* TODO: build arp table, and look up */
20 int eth_send(struct pbuf *p, struct in_addr *dest) {
21         uint32_t bytes_sent; 
22         printk("size of pbuf_header movement %d\n", sizeof(struct ethernet_hdr));
23         if (pbuf_header(p, sizeof(struct ethernet_hdr)) != 0){
24                 warn("eth_send buffer ran out");
25                 /* unsuccessful, needs to allocate */   
26                 return -ENOBUFS;
27         }
28
29         struct ethernet_hdr *ethhdr = (struct ethernet_hdr *)p->payload; 
30         // TODO: for now just forward to gateway
31         memcpy(ethhdr->dst_mac, GTWAY, 6);
32         memcpy(ethhdr->src_mac, device_mac, 6);
33         ethhdr->eth_type = htons(IP_ETH_TYPE);
34         /* The reason for not sending to send_nic for each pbuf in the chain
35          * is so that we can send from multi-buffer later.
36          */
37         if (send_pbuf){
38                 bytes_sent = send_pbuf(p);
39                 return bytes_sent;
40         }
41         else {
42                 warn("no pbuf send function \n");
43                 return -1;
44         }
45         /* is the address local , if no, search for MAC of the gateway and dest to gateway */
46         /* if address is local, use arp etc */
47
48 }
49
50 /* while it would be nice to write a generic send_pbuf it is impossible to do so in
51  * efficiently.
52  */
53 /* Assume no ip options */
54 int ip_output(struct pbuf *p, struct in_addr *src, struct in_addr *dest, uint8_t proto) {
55         struct pbuf *q;
56         struct ip_hdr *iphdr;   
57         /* TODO: Check for IP_HDRINCL */
58         if (dest->s_addr == IP_HDRINCL) {
59                 /*send right away since */
60                 warn("header included in the ip packets");
61                 return -1;
62         }
63         if (pbuf_header(p, IP_HDR_SZ)) {
64                 warn("buffer ran out");
65                 /* unsuccessful, needs to allocate */   
66                 return -ENOBUFS;
67         }
68         iphdr = (struct ip_hdr *) p->payload;
69
70         /* successful */
71         iphdr->version = IPPROTO_IPV4;
72         /* assume no IP options */
73         iphdr->hdr_len = IP_HDR_SZ >> 2;
74         iphdr->tos = 0;
75         iphdr->packet_len = htons(p->tot_len);
76         // TODO: NET_LOCK
77         iphdr->id = htons (ip_id); // 1
78         ip_id++;
79         iphdr->flags_frags = htons(0); // 4000  may fragment
80         iphdr->protocol = proto;
81         iphdr->ttl = DEFAULT_TTL;
82         /* Eventually if we support more than one device this may change */
83         printk("src ip %x, dest ip %x \n", src->s_addr, dest->s_addr);
84         iphdr->src_addr = htonl(src->s_addr);
85         iphdr->dst_addr = (dest->s_addr);
86         /* force hardware checksum
87          * TODO: provide option to do both hardware/software checksum
88          */
89         /* Since the IP header is set already, we can compute the checksum. */
90         /* TODO: Use the card to calculate the checksum */
91         iphdr->checksum = 0;
92         iphdr->checksum = ip_checksum(iphdr); //7ab6
93         if (p->tot_len > DEFAULT_MTU) /*MAX MTU? header included */
94                 return -1;//ip_frag(p, dest);
95         else
96                 return eth_send(p, dest);
97 }
98
99 int ip_input(struct pbuf *p) {
100         uint32_t iphdr_hlen, iphdr_len;
101         struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
102         printk("start of ip %p \n", p->payload);
103         print_pbuf(p);
104         /* use that info to build arp table */
105   if (iphdr->version != 4) {
106                 warn("ip version not 4!\n");
107     pbuf_free(p);
108                 return -1;
109         }
110         iphdr_hlen = iphdr->hdr_len * 4;
111         iphdr_len = ntohs(iphdr->packet_len);
112         printk("ip input coming from %x of size %d", ntohs(iphdr->dst_addr), iphdr_len);
113   /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
114   if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
115     if (iphdr_hlen > p->len) {
116         warn("IP header (len 0x%X) does not fit in first pbuf (len %X), IP packet dropped.\n",
117         iphdr_hlen, p->len);
118     }
119     if (iphdr_len > p->tot_len) {
120         warn("IP (len %X) is longer than pbuf (len %X), IP packet dropped.\n",
121         iphdr_len, p->tot_len);
122     }
123     /* free (drop) packet pbufs */
124     pbuf_free(p);
125     return -1;
126   }
127         if (ip_checksum(iphdr) != 0) {
128                 warn("checksum failed \n");
129                 pbuf_free(p);
130                 return -1;
131         }
132
133         /* check if it is destined for me? */
134         /* XXX: IP address for the interface is IP_ANY */
135         if (ntohl(iphdr->dst_addr) != global_ip.s_addr){
136                 printk("dest ip in network order%x\n", ntohl(iphdr->dst_addr));
137                 printk("dest ip in network order%x\n", global_ip.s_addr);
138                 warn("ip mismatch \n");
139                 pbuf_free(p);
140                 /* TODO:forward packets */
141                 // ip_forward(p, iphdr, inp);
142         }
143
144         if ((ntohs(iphdr->flags_frags) & (IP_OFFMASK | IP_MF)) != 0){
145                 panic ("ip fragment detected\n");
146                 pbuf_free(p);
147         }
148
149         printk ("loc head %p, loc protocol %p\n", iphdr, &iphdr->protocol);
150         /* currently a noop, compared to the memory wasted, cutting out ipheader is not really saving much */
151         // pbuf_realloc(p, iphdr_len);
152         switch (iphdr->protocol) {
153                 case IPPROTO_UDP:
154                         return udp_input(p);
155                 case IPPROTO_TCP:
156                 default:
157                         printk("IP protocol type %02x\n", iphdr->protocol);
158                         warn("protocol not supported! \n");
159         }
160         return -1;
161 }
162
163 void print_ipheader(struct ip_hdr* iph){
164
165         
166 }
167
168
169