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