]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ip/ipaux.c
devip: cleanup tcp.c
[plan9front.git] / sys / src / 9 / ip / ipaux.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "../port/error.h"
7 #include        "ip.h"
8 #include        "ipv6.h"
9
10 char *v6hdrtypes[Maxhdrtype] =
11 {
12         [HBH]           "HopbyHop",
13         [ICMP]          "ICMP",
14         [IGMP]          "IGMP",
15         [GGP]           "GGP",
16         [IPINIP]        "IP",
17         [ST]            "ST",
18         [TCP]           "TCP",
19         [UDP]           "UDP",
20         [ISO_TP4]       "ISO_TP4",
21         [RH]            "Routinghdr",
22         [FH]            "Fraghdr",
23         [IDRP]          "IDRP",
24         [RSVP]          "RSVP",
25         [AH]            "Authhdr",
26         [ESP]           "ESP",
27         [ICMPv6]        "ICMPv6",
28         [NNH]           "Nonexthdr",
29         [ISO_IP]        "ISO_IP",
30         [IGRP]          "IGRP",
31         [OSPF]          "OSPF",
32 };
33
34 /*
35  *  well known IPv6 addresses
36  */
37 uchar v6Unspecified[IPaddrlen] = {
38         0, 0, 0, 0,
39         0, 0, 0, 0,
40         0, 0, 0, 0,
41         0, 0, 0, 0
42 };
43 uchar v6loopback[IPaddrlen] = {
44         0, 0, 0, 0,
45         0, 0, 0, 0,
46         0, 0, 0, 0,
47         0, 0, 0, 0x01
48 };
49
50 uchar v6linklocal[IPaddrlen] = {
51         0xfe, 0x80, 0, 0,
52         0, 0, 0, 0,
53         0, 0, 0, 0,
54         0, 0, 0, 0
55 };
56 uchar v6linklocalmask[IPaddrlen] = {
57         0xff, 0xff, 0xff, 0xff,
58         0xff, 0xff, 0xff, 0xff,
59         0, 0, 0, 0,
60         0, 0, 0, 0
61 };
62 int v6llpreflen = 8;    /* link-local prefix length in bytes */
63
64 uchar v6multicast[IPaddrlen] = {
65         0xff, 0, 0, 0,
66         0, 0, 0, 0,
67         0, 0, 0, 0,
68         0, 0, 0, 0
69 };
70 uchar v6multicastmask[IPaddrlen] = {
71         0xff, 0, 0, 0,
72         0, 0, 0, 0,
73         0, 0, 0, 0,
74         0, 0, 0, 0
75 };
76 int v6mcpreflen = 1;    /* multicast prefix length */
77
78 uchar v6allnodesN[IPaddrlen] = {
79         0xff, 0x01, 0, 0,
80         0, 0, 0, 0,
81         0, 0, 0, 0,
82         0, 0, 0, 0x01
83 };
84 uchar v6allroutersN[IPaddrlen] = {
85         0xff, 0x01, 0, 0,
86         0, 0, 0, 0,
87         0, 0, 0, 0,
88         0, 0, 0, 0x02
89 };
90 uchar v6allnodesNmask[IPaddrlen] = {
91         0xff, 0xff, 0, 0,
92         0, 0, 0, 0,
93         0, 0, 0, 0,
94         0, 0, 0, 0
95 };
96 int v6aNpreflen = 2;    /* all nodes (N) prefix */
97
98 uchar v6allnodesL[IPaddrlen] = {
99         0xff, 0x02, 0, 0,
100         0, 0, 0, 0,
101         0, 0, 0, 0,
102         0, 0, 0, 0x01
103 };
104 uchar v6allroutersL[IPaddrlen] = {
105         0xff, 0x02, 0, 0,
106         0, 0, 0, 0,
107         0, 0, 0, 0,
108         0, 0, 0, 0x02
109 };
110 uchar v6allnodesLmask[IPaddrlen] = {
111         0xff, 0xff, 0, 0,
112         0, 0, 0, 0,
113         0, 0, 0, 0,
114         0, 0, 0, 0
115 };
116 int v6aLpreflen = 2;    /* all nodes (L) prefix */
117
118 uchar v6solicitednode[IPaddrlen] = {
119         0xff, 0x02, 0, 0,
120         0, 0, 0, 0,
121         0, 0, 0, 0x01,
122         0xff, 0, 0, 0
123 };
124 uchar v6solicitednodemask[IPaddrlen] = {
125         0xff, 0xff, 0xff, 0xff,
126         0xff, 0xff, 0xff, 0xff,
127         0xff, 0xff, 0xff, 0xff,
128         0xff, 0x0, 0x0, 0x0
129 };
130 int v6snpreflen = 13;
131
132 ushort
133 ptclcsum(Block *bp, int offset, int len)
134 {
135         uchar *addr;
136         ulong losum, hisum;
137         ushort csum;
138         int odd, blocklen, x;
139
140         /* Correct to front of data area */
141         while(bp != nil && offset && offset >= BLEN(bp)) {
142                 offset -= BLEN(bp);
143                 bp = bp->next;
144         }
145         if(bp == nil)
146                 return 0;
147
148         addr = bp->rp + offset;
149         blocklen = BLEN(bp) - offset;
150
151         if(bp->next == nil) {
152                 if(blocklen < len)
153                         len = blocklen;
154                 return ~ptclbsum(addr, len) & 0xffff;
155         }
156
157         losum = 0;
158         hisum = 0;
159
160         odd = 0;
161         while(len) {
162                 x = blocklen;
163                 if(len < x)
164                         x = len;
165
166                 csum = ptclbsum(addr, x);
167                 if(odd)
168                         hisum += csum;
169                 else
170                         losum += csum;
171                 odd = (odd+x) & 1;
172                 len -= x;
173
174                 bp = bp->next;
175                 if(bp == nil)
176                         break;
177                 blocklen = BLEN(bp);
178                 addr = bp->rp;
179         }
180
181         losum += hisum>>8;
182         losum += (hisum&0xff)<<8;
183         while((csum = losum>>16) != 0)
184                 losum = csum + (losum & 0xffff);
185
186         return ~losum & 0xffff;
187 }
188
189 enum
190 {
191         Isprefix= 16,
192 };
193
194 #define CLASS(p) ((*(uchar*)(p))>>6)
195
196 void
197 ipv62smcast(uchar *smcast, uchar *a)
198 {
199         assert(IPaddrlen == 16);
200         memmove(smcast, v6solicitednode, IPaddrlen);
201         smcast[13] = a[13];
202         smcast[14] = a[14];
203         smcast[15] = a[15];
204 }
205
206
207 /*
208  *  parse a hex mac address
209  */
210 int
211 parsemac(uchar *to, char *from, int len)
212 {
213         char nip[4];
214         char *p;
215         int i;
216
217         p = from;
218         memset(to, 0, len);
219         for(i = 0; i < len; i++){
220                 if(p[0] == '\0' || p[1] == '\0')
221                         break;
222
223                 nip[0] = p[0];
224                 nip[1] = p[1];
225                 nip[2] = '\0';
226                 p += 2;
227
228                 to[i] = strtoul(nip, 0, 16);
229                 if(*p == ':')
230                         p++;
231         }
232         return i;
233 }
234
235 /*
236  *  hashing tcp, udp, ... connections
237  */
238 ulong
239 iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
240 {
241         return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nipht;
242 }
243
244 void
245 iphtadd(Ipht *ht, Conv *c)
246 {
247         ulong hv;
248         Iphash *h;
249
250         hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
251         h = smalloc(sizeof(*h));
252         if(ipcmp(c->raddr, IPnoaddr) != 0)
253                 h->match = IPmatchexact;
254         else {
255                 if(ipcmp(c->laddr, IPnoaddr) != 0){
256                         if(c->lport == 0)
257                                 h->match = IPmatchaddr;
258                         else
259                                 h->match = IPmatchpa;
260                 } else {
261                         if(c->lport == 0)
262                                 h->match = IPmatchany;
263                         else
264                                 h->match = IPmatchport;
265                 }
266         }
267         h->c = c;
268
269         lock(ht);
270         h->next = ht->tab[hv];
271         ht->tab[hv] = h;
272         unlock(ht);
273 }
274
275 void
276 iphtrem(Ipht *ht, Conv *c)
277 {
278         ulong hv;
279         Iphash **l, *h;
280
281         hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
282         lock(ht);
283         for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->next)
284                 if((*l)->c == c){
285                         h = *l;
286                         (*l) = h->next;
287                         free(h);
288                         break;
289                 }
290         unlock(ht);
291 }
292
293 /* look for a matching conversation with the following precedence
294  *      connected && raddr,rport,laddr,lport
295  *      announced && laddr,lport
296  *      announced && *,lport
297  *      announced && laddr,*
298  *      announced && *,*
299  */
300 Conv*
301 iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
302 {
303         ulong hv;
304         Iphash *h;
305         Conv *c;
306
307         /* exact 4 pair match (connection) */
308         hv = iphash(sa, sp, da, dp);
309         lock(ht);
310         for(h = ht->tab[hv]; h != nil; h = h->next){
311                 if(h->match != IPmatchexact)
312                         continue;
313                 c = h->c;
314                 if(sp == c->rport && dp == c->lport
315                 && ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
316                         unlock(ht);
317                         return c;
318                 }
319         }
320
321         /* match local address and port */
322         hv = iphash(IPnoaddr, 0, da, dp);
323         for(h = ht->tab[hv]; h != nil; h = h->next){
324                 if(h->match != IPmatchpa)
325                         continue;
326                 c = h->c;
327                 if(dp == c->lport && ipcmp(da, c->laddr) == 0){
328                         unlock(ht);
329                         return c;
330                 }
331         }
332
333         /* match just port */
334         hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
335         for(h = ht->tab[hv]; h != nil; h = h->next){
336                 if(h->match != IPmatchport)
337                         continue;
338                 c = h->c;
339                 if(dp == c->lport){
340                         unlock(ht);
341                         return c;
342                 }
343         }
344
345         /* match local address */
346         hv = iphash(IPnoaddr, 0, da, 0);
347         for(h = ht->tab[hv]; h != nil; h = h->next){
348                 if(h->match != IPmatchaddr)
349                         continue;
350                 c = h->c;
351                 if(ipcmp(da, c->laddr) == 0){
352                         unlock(ht);
353                         return c;
354                 }
355         }
356
357         /* look for something that matches anything */
358         hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
359         for(h = ht->tab[hv]; h != nil; h = h->next){
360                 if(h->match != IPmatchany)
361                         continue;
362                 c = h->c;
363                 unlock(ht);
364                 return c;
365         }
366         unlock(ht);
367         return nil;
368 }
369
370 int
371 convipvers(Conv *c)
372 {
373         if(isv4(c->raddr) && isv4(c->laddr) || ipcmp(c->raddr, IPnoaddr) == 0)
374                 return V4;
375         else
376                 return V6;
377 }