initial tcp commit!
[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 <net/tcp_impl.h>
9 #include <ros/errno.h>
10 #include <arch/nic_common.h>
11
12 /* statically configured next gateway */
13 const uint8_t GTWAY[6] = {0xda, 0x76, 0xe7, 0x4c, 0xca, 0x7e};
14
15 /* TODO: ip id unique for all ip packets? or is it unique for a flow? */
16 // can do atomic increment at a minimum
17 static uint16_t ip_id = 0;
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, 
55                                                         uint8_t ttl, uint8_t tos, uint8_t proto) {
56         struct pbuf *q;
57         struct ip_hdr *iphdr;   
58         /* TODO: Check for IP_HDRINCL */
59         if (dest->s_addr == IP_HDRINCL) {
60                 /*send right away since */
61                 warn("header included in the ip packets");
62                 return -1;
63         }
64         if (pbuf_header(p, IP_HDR_SZ)) {
65                 warn("buffer ran out");
66                 /* unsuccessful, needs to allocate */   
67                 return -ENOBUFS;
68         }
69         iphdr = (struct ip_hdr *) p->payload;
70
71         /* successful */
72         iphdr->version = IPPROTO_IPV4;
73         /* assume no IP options */
74         iphdr->hdr_len = IP_HDR_SZ >> 2;
75         if (tos != 0) {
76                 iphdr->tos = htons(tos);
77         }
78         else {
79                 iphdr->tos = 0;
80         }
81         iphdr->packet_len = htons(p->tot_len);
82         // TODO: NET_LOCK
83         iphdr->id = htons (ip_id); // 1
84         ip_id++;
85         iphdr->flags_frags = htons(0); // 4000  may fragment
86         iphdr->protocol = proto;
87         iphdr->ttl = ttl; //DEFAULT_TTL;
88         /* Eventually if we support more than one device this may change */
89         printk("src ip %x, dest ip %x \n", src->s_addr, dest->s_addr);
90         iphdr->src_addr = htonl(src->s_addr);
91         iphdr->dst_addr = (dest->s_addr);
92         /* force hardware checksum
93          * TODO: provide option to do both hardware/software checksum
94          */
95         /* Since the IP header is set already, we can compute the checksum. */
96         /* TODO: Use the card to calculate the checksum */
97         iphdr->checksum = 0;
98         iphdr->checksum = ip_checksum(iphdr); //7ab6
99         if (p->tot_len > DEFAULT_MTU) /*MAX MTU? header included */
100                 return -1;//ip_frag(p, dest);
101         else
102                 return eth_send(p, dest);
103 }
104
105 int ip_input(struct pbuf *p) {
106         uint32_t iphdr_hlen, iphdr_len;
107         struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
108         //printk("start of ip %p \n", p->payload);
109         //print_pbuf(p);
110         /* use that info to build arp table */
111   if (iphdr->version != 4) {
112                 warn("ip version not 4!\n");
113     pbuf_free(p);
114                 return -1;
115         }
116         iphdr_hlen = iphdr->hdr_len * 4;
117         iphdr_len = ntohs(iphdr->packet_len);
118         // printk("ip input coming from %x of size %d", ntohs(iphdr->dst_addr), iphdr_len);
119   /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
120   if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
121     if (iphdr_hlen > p->len) {
122         warn("IP header (len 0x%X) does not fit in first pbuf (len %X), IP packet dropped.\n",
123         iphdr_hlen, p->len);
124     }
125     if (iphdr_len > p->tot_len) {
126         warn("IP (len %X) is longer than pbuf (len %X), IP packet dropped.\n",
127         iphdr_len, p->tot_len);
128     }
129     /* free (drop) packet pbufs */
130     pbuf_free(p);
131     return -1;
132   }
133         if (ip_checksum(iphdr) != 0) {
134                 warn("checksum failed \n");
135                 pbuf_free(p);
136                 return -1;
137         }
138
139         /* check if it is destined for me? */
140         /* XXX: IP address for the interface is IP_ANY */
141         if (ntohl(iphdr->dst_addr) != LOCAL_IP_ADDR.s_addr){
142                 printk("dest ip in network order%x\n", ntohl(iphdr->dst_addr));
143                 printk("dest ip in network order%x\n", LOCAL_IP_ADDR.s_addr);
144                 warn("ip mismatch \n");
145                 pbuf_free(p);
146                 /* TODO:forward packets */
147                 // ip_forward(p, iphdr, inp);
148         }
149
150         if ((ntohs(iphdr->flags_frags) & (IP_OFFMASK | IP_MF)) != 0){
151                 panic ("ip fragment detected\n");
152                 pbuf_free(p);
153         }
154
155         //printk ("loc head %p, loc protocol %p\n", iphdr, &iphdr->protocol);
156         /* currently a noop, compared to the memory wasted, cutting out ipheader is not really saving much */
157         // pbuf_realloc(p, iphdr_len);
158         switch (iphdr->protocol) {
159                 case IPPROTO_UDP:
160                         return udp_input(p);
161                 case IPPROTO_TCP:
162                         tcp_input(p);
163                         // XXX: error handling for tcp
164                         return 0;
165                 default:
166                         printk("IP protocol type %02x\n", iphdr->protocol);
167                         warn("protocol not supported! \n");
168         }
169         return -1;
170 }
171
172 void print_ipheader(struct ip_hdr* iph){
173
174         
175 }
176
177
178