Set errno when only errstr was called
[akaros.git] / kern / src / net.c
1 /* Copyright (c) 2010 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Arch independent networking infrastructure */
6
7 /* Computes an IP checksum over buf.  The checksum is the one's-comp of the
8  * one's complement 16 bit sum of the payload.  Anything above 16 bits gets
9  * added back to the lower 16 bits, which is what the mask and add is doing.
10  * Check out http://www.netfor2.com/checksum.html for more info.
11  *
12  * If you want to start with a sum from something else (like the UDP
13  * pseudo-header), pass it in as init_sum. */
14
15 #include <net.h>
16 #include <stdio.h>
17 #include <arch/types.h>
18
19 #ifndef FOLD_U32T
20 #define FOLD_U32T(u)          (((u) >> 16) + ((u) & 0x0000ffffUL))
21 #endif
22
23 /* New version of ip_checksum, notice this version does not change it into 
24  * network order. It is useful to keep it in host order for further processing
25  */ 
26 uint16_t __ip_checksum(void *dataptr, unsigned int len, uint32_t sum)
27 {
28   uint8_t *pb = (uint8_t *)dataptr;
29   uint16_t *ps, t = 0;
30   int odd = ((uintptr_t)pb & 1);
31
32   /* Get aligned to uint16_t */
33         // this means pb started on some weird address..
34         // but in our world this should never happen.. since the payload should always be aligned..
35         // right..
36
37   if (odd && len > 0) {
38                 // change the second half of t to what pb is
39                 // and advance pb
40     ((uint8_t *)&t)[1] = *pb++;
41     len--;
42   }
43
44   /* Add the bulk of the data */
45   ps = (uint16_t *)(void *)pb;
46   while (len > 1) {
47     sum += *ps++;
48     len -= 2;
49   }
50
51   /* Consume left-over byte, if any */
52   if (len > 0) {
53     ((uint8_t *)&t)[0] = *(uint8_t *)ps;
54   }
55
56   /* Add end bytes */
57   sum += t;
58
59   /* Fold 32-bit sum to 16 bits
60      calling this twice is propably faster than if statements... */
61   sum = FOLD_U32T(sum);
62   sum = FOLD_U32T(sum);
63
64   /* Swap if alignment was odd */
65   if (odd) {
66     sum = byte_swap16(sum);
67   }
68
69   return (uint16_t)sum;
70 }
71
72 /* Computes the checksum for the IP header.  We could write it in, but for now
73  * we'll return the checksum (in host-ordering) and have the caller store the
74  * value.  The retval is in host ordering. */
75 uint16_t ip_checksum(struct ip_hdr *ip_hdr)
76 {
77         unsigned int ip_hdr_len = ip_hdr->hdr_len * sizeof(uint32_t);
78         return ~__ip_checksum(ip_hdr, ip_hdr_len, 0);
79 }
80
81 /* Computes the checksum for the UDP header.  We could write it in, but for now
82  * we'll return the checksum (in host-ordering) and have the caller store the
83  * value.  Note that the UDP header needs info from the IP header (strictly
84  * speaking, just the src and destination IPs).  
85  * LEGACY: only used for packet that are not in pbuf formats*/
86 uint16_t udp_checksum(struct ip_hdr *ip_hdr, struct udp_hdr *udp_hdr)
87 {
88         /* Add up the info for the UDP pseudo-header */
89         uint32_t udp_pseudosum = 0;
90         uint16_t udp_len = ntohs(udp_hdr->length);
91         udp_pseudosum += (ip_hdr->src_addr & 0xffff);
92         udp_pseudosum += (ip_hdr->src_addr >> 16);
93         udp_pseudosum += (ip_hdr->dst_addr & 0xffff);
94         udp_pseudosum += (ip_hdr->dst_addr >> 16);
95         udp_pseudosum += (ip_hdr->protocol);
96         udp_pseudosum += udp_hdr->length;
97         return ~(__ip_checksum(udp_hdr, udp_len, udp_pseudosum));
98 }
99
100 /* ip addresses need to be network order, protolen and proto are HO */
101 uint16_t inet_chksum_pseudo(struct pbuf *p, uint32_t src, uint32_t dest, uint8_t proto, uint16_t proto_len) {
102   uint32_t acc;
103   uint32_t addr;
104   struct pbuf *q;
105   uint8_t swapped;
106
107   acc = 0;
108   swapped = 0;
109   /* iterate through all pbuf in chain */
110   for(q = p; q != NULL; q = STAILQ_NEXT(q, next)) {
111     acc += __ip_checksum(q->payload, q->len, 0);
112     acc = FOLD_U32T(acc);
113     if (q->len % 2 != 0) {
114       swapped = 1 - swapped;
115       acc = byte_swap16(acc);
116     }
117   }
118
119   if (swapped) {
120     acc = byte_swap16(acc);
121   }
122
123   addr = (src);
124   acc += (addr & 0xffffUL);
125   acc += ((addr >> 16) & 0xffffUL);
126   addr = (dest);
127   acc += (addr & 0xffffUL);
128   acc += ((addr >> 16) & 0xffffUL);
129   acc += (uint32_t)htons((uint16_t)proto);
130   acc += (uint32_t)htons(proto_len);
131
132   /* Fold 32-bit sum to 16 bits
133      calling this twice is propably faster than if statements... */
134   acc = FOLD_U32T(acc);
135   acc = FOLD_U32T(acc);
136   return (uint16_t)~(acc & 0xffffUL);
137 }
138
139 /* Print out a network packet in the same format as tcpdump, making it easier 
140  * to compare */
141 void dumppacket(unsigned char *buff, size_t len)
142 {
143         int i;
144         for (i=0; i<len; i++) {
145                 if (i%16 == 0)
146                         printk("0x%x\t", i/16);
147                 printk("%02x", buff[i]);
148                 if (i%2 != 0)
149                         printk(" ");
150                 if ((i+1)%16 == 0)
151                         printk("\n");
152         }
153 }