kconfig: use pkg-config for ncurses detection
[akaros.git] / kern / src / net / ipaux.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <slab.h>
30 #include <kmalloc.h>
31 #include <kref.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <assert.h>
35 #include <error.h>
36 #include <cpio.h>
37 #include <pmap.h>
38 #include <smp.h>
39 #include <net/ip.h>
40 #include <endian.h>
41
42 /*
43  *  well known IP addresses
44  */
45 uint8_t IPv4_loopback[IPaddrlen] = {
46         0, 0, 0, 0,
47         0, 0, 0, 0,
48         0, 0, 0xff, 0xff,
49         0x7f, 0x00, 0x00, 0x01
50 };
51
52 uint8_t IPv4_zeroes[IPaddrlen] = {
53         0, 0, 0, 0,
54         0, 0, 0, 0,
55         0, 0, 0xff, 0xff,
56         0x00, 0x00, 0x00, 0x00
57 };
58
59 uint8_t IPv4bcast[IPaddrlen] = {
60         0, 0, 0, 0,
61         0, 0, 0, 0,
62         0, 0, 0xff, 0xff,
63         0xff, 0xff, 0xff, 0xff
64 };
65
66 uint8_t IPv4allsys[IPaddrlen] = {
67         0, 0, 0, 0,
68         0, 0, 0, 0,
69         0, 0, 0xff, 0xff,
70         0xe0, 0, 0, 0x01
71 };
72
73 uint8_t IPv4allrouter[IPaddrlen] = {
74         0, 0, 0, 0,
75         0, 0, 0, 0,
76         0, 0, 0xff, 0xff,
77         0xe0, 0, 0, 0x02
78 };
79
80 uint8_t IPallbits[IPaddrlen] = {
81         0xff, 0xff, 0xff, 0xff,
82         0xff, 0xff, 0xff, 0xff,
83         0xff, 0xff, 0xff, 0xff,
84         0xff, 0xff, 0xff, 0xff
85 };
86
87 uint8_t IPnoaddr[IPaddrlen];
88
89 /*
90  *  prefix of all v4 addresses
91  */
92 uint8_t v4prefix[IPaddrlen] = {
93         0, 0, 0, 0,
94         0, 0, 0, 0,
95         0, 0, 0xff, 0xff,
96         0, 0, 0, 0
97 };
98
99 char *v6hdrtypes[Maxhdrtype] = {
100         [HBH] "HopbyHop",
101         [ICMP] "ICMP",
102         [IGMP] "IGMP",
103         [GGP] "GGP",
104         [IPINIP] "IP",
105         [ST] "ST",
106         [TCP] "TCP",
107         [UDP] "UDP",
108         [ISO_TP4] "ISO_TP4",
109         [RH] "Routinghdr",
110         [FH] "Fraghdr",
111         [IDRP] "IDRP",
112         [RSVP] "RSVP",
113         [AH] "Authhdr",
114         [ESP] "ESP",
115         [ICMPv6] "ICMPv6",
116         [NNH] "Nonexthdr",
117         [ISO_IP] "ISO_IP",
118         [IGRP] "IGRP",
119         [OSPF] "OSPF",
120 };
121
122 /*
123  *  well known IPv6 addresses
124  */
125 uint8_t v6Unspecified[IPaddrlen] = {
126         0, 0, 0, 0,
127         0, 0, 0, 0,
128         0, 0, 0, 0,
129         0, 0, 0, 0
130 };
131
132 uint8_t v6loopback[IPaddrlen] = {
133         0, 0, 0, 0,
134         0, 0, 0, 0,
135         0, 0, 0, 0,
136         0, 0, 0, 0x01
137 };
138
139 uint8_t v6linklocal[IPaddrlen] = {
140         0xfe, 0x80, 0, 0,
141         0, 0, 0, 0,
142         0, 0, 0, 0,
143         0, 0, 0, 0
144 };
145
146 uint8_t v6linklocalmask[IPaddrlen] = {
147         0xff, 0xff, 0xff, 0xff,
148         0xff, 0xff, 0xff, 0xff,
149         0, 0, 0, 0,
150         0, 0, 0, 0
151 };
152
153 int v6llpreflen = 8;                    // link-local prefix length
154 uint8_t v6sitelocal[IPaddrlen] = {
155         0xfe, 0xc0, 0, 0,
156         0, 0, 0, 0,
157         0, 0, 0, 0,
158         0, 0, 0, 0
159 };
160
161 uint8_t v6sitelocalmask[IPaddrlen] = {
162         0xff, 0xff, 0xff, 0xff,
163         0xff, 0xff, 0xff, 0xff,
164         0, 0, 0, 0,
165         0, 0, 0, 0
166 };
167
168 int v6slpreflen = 6;                    // site-local prefix length
169 uint8_t v6glunicast[IPaddrlen] = {
170         0x08, 0, 0, 0,
171         0, 0, 0, 0,
172         0, 0, 0, 0,
173         0, 0, 0, 0
174 };
175
176 uint8_t v6multicast[IPaddrlen] = {
177         0xff, 0, 0, 0,
178         0, 0, 0, 0,
179         0, 0, 0, 0,
180         0, 0, 0, 0
181 };
182
183 uint8_t v6multicastmask[IPaddrlen] = {
184         0xff, 0, 0, 0,
185         0, 0, 0, 0,
186         0, 0, 0, 0,
187         0, 0, 0, 0
188 };
189
190 int v6mcpreflen = 1;                    // multicast prefix length
191 uint8_t v6allnodesN[IPaddrlen] = {
192         0xff, 0x01, 0, 0,
193         0, 0, 0, 0,
194         0, 0, 0, 0,
195         0, 0, 0, 0x01
196 };
197
198 uint8_t v6allnodesNmask[IPaddrlen] = {
199         0xff, 0xff, 0, 0,
200         0, 0, 0, 0,
201         0, 0, 0, 0,
202         0, 0, 0, 0
203 };
204
205 int v6aNpreflen = 2;                    // all nodes (N) prefix
206 uint8_t v6allnodesL[IPaddrlen] = {
207         0xff, 0x02, 0, 0,
208         0, 0, 0, 0,
209         0, 0, 0, 0,
210         0, 0, 0, 0x01
211 };
212
213 uint8_t v6allnodesLmask[IPaddrlen] = {
214         0xff, 0xff, 0, 0,
215         0, 0, 0, 0,
216         0, 0, 0, 0,
217         0, 0, 0, 0
218 };
219
220 int v6aLpreflen = 2;                    // all nodes (L) prefix
221 uint8_t v6allroutersN[IPaddrlen] = {
222         0xff, 0x01, 0, 0,
223         0, 0, 0, 0,
224         0, 0, 0, 0,
225         0, 0, 0, 0x02
226 };
227
228 uint8_t v6allroutersL[IPaddrlen] = {
229         0xff, 0x02, 0, 0,
230         0, 0, 0, 0,
231         0, 0, 0, 0,
232         0, 0, 0, 0x02
233 };
234
235 uint8_t v6allroutersS[IPaddrlen] = {
236         0xff, 0x05, 0, 0,
237         0, 0, 0, 0,
238         0, 0, 0, 0,
239         0, 0, 0, 0x02
240 };
241
242 uint8_t v6solicitednode[IPaddrlen] = {
243         0xff, 0x02, 0, 0,
244         0, 0, 0, 0,
245         0, 0, 0, 0x01,
246         0xff, 0, 0, 0
247 };
248
249 uint8_t v6solicitednodemask[IPaddrlen] = {
250         0xff, 0xff, 0xff, 0xff,
251         0xff, 0xff, 0xff, 0xff,
252         0xff, 0xff, 0xff, 0xff,
253         0xff, 0x0, 0x0, 0x0
254 };
255
256 int v6snpreflen = 13;
257
258 uint16_t ptclcsum_one(struct block *bp, int offset, int len)
259 {
260         uint8_t *addr;
261         uint32_t losum, hisum;
262         uint16_t csum;
263         int odd, blocklen, x, i, boff;
264         struct extra_bdata *ebd;
265
266         hisum = 0;
267         losum = 0;
268         odd = 0;
269
270         if (offset < BHLEN(bp)) {
271                 x = MIN(len, BHLEN(bp) - offset);
272                 odd = (odd + x) & 1;
273                 addr = bp->rp + offset;
274                 losum = ptclbsum(addr, x);
275                 len -= x;
276                 offset = 0;
277         } else {
278                 offset -= BHLEN(bp);
279         }
280         for (int i = 0; (i < bp->nr_extra_bufs) && len; i++) {
281                 ebd = &bp->extra_data[i];
282                 boff = MIN(offset, ebd->len);
283                 if (offset) {
284                         offset -= boff;
285                         if (offset)
286                                 continue;
287                 }
288                 x = MIN(len, ebd->len - boff);
289                 addr = (void *)(ebd->base + ebd->off);
290                 if (odd)
291                         hisum += ptclbsum(addr, x);
292                 else
293                         losum += ptclbsum(addr, x);
294                 odd = (odd + x) & 1;
295                 len -= x;
296         }
297         losum += hisum >> 8;
298         losum += (hisum & 0xff) << 8;
299         while ((csum = losum >> 16) != 0)
300                 losum = csum + (losum & 0xffff);
301
302         return losum & 0xffff;
303 }
304
305 uint16_t ptclcsum(struct block *bp, int offset, int len)
306 {
307         uint8_t *addr;
308         uint32_t losum, hisum;
309         uint16_t csum;
310         int odd, blocklen, x;
311
312         /* Correct to front of data area */
313         while (bp != NULL && offset && offset >= BLEN(bp)) {
314                 offset -= BLEN(bp);
315                 bp = bp->next;
316         }
317         if (bp == NULL)
318                 return 0;
319
320         addr = bp->rp + offset;
321         blocklen = BLEN(bp) - offset;
322
323         if (bp->next == NULL && bp->extra_len == 0) {
324                 if (blocklen < len)
325                         len = blocklen;
326                 return ~ptclbsum(addr, len) & 0xffff;
327         }
328
329         losum = 0;
330         hisum = 0;
331
332         odd = 0;
333         while (len) {
334                 x = MIN(blocklen, len);
335                 csum = ptclcsum_one(bp, offset, x);
336                 if (odd)
337                         hisum += csum;
338                 else
339                         losum += csum;
340                 odd = (odd + x) & 1;
341                 len -= x;
342
343                 bp = bp->next;
344                 if (bp == NULL)
345                         break;
346                 blocklen = BLEN(bp);
347                 offset = 0;
348         }
349
350         losum += hisum >> 8;
351         losum += (hisum & 0xff) << 8;
352         while ((csum = losum >> 16) != 0)
353                 losum = csum + (losum & 0xffff);
354
355         return ~losum & 0xffff;
356 }
357
358 enum {
359         Isprefix = 16,
360 };
361
362 static uint8_t prefixvals[256] = {
363         [0x00] 0 | Isprefix,
364         [0x80] 1 | Isprefix,
365         [0xC0] 2 | Isprefix,
366         [0xE0] 3 | Isprefix,
367         [0xF0] 4 | Isprefix,
368         [0xF8] 5 | Isprefix,
369         [0xFC] 6 | Isprefix,
370         [0xFE] 7 | Isprefix,
371         [0xFF] 8 | Isprefix,
372 };
373
374 #define CLASS(p) ((*( uint8_t *)(p))>>6)
375
376 extern char *v4parseip(uint8_t * to, char *from)
377 {
378         int i;
379         char *p;
380
381         p = from;
382         for (i = 0; i < 4 && *p; i++) {
383                 to[i] = strtoul(p, &p, 0);
384                 if (*p == '.')
385                         p++;
386         }
387         switch (CLASS(to)) {
388         case 0: /* class A - 1 uint8_t net */
389         case 1:
390                 if (i == 3) {
391                         to[3] = to[2];
392                         to[2] = to[1];
393                         to[1] = 0;
394                 } else if (i == 2) {
395                         to[3] = to[1];
396                         to[1] = 0;
397                 }
398                 break;
399         case 2: /* class B - 2 uint8_t net */
400                 if (i == 3) {
401                         to[3] = to[2];
402                         to[2] = 0;
403                 }
404                 break;
405         }
406         return p;
407 }
408
409 int isv4(uint8_t * ip)
410 {
411         unsigned short *ips = (unsigned short *)ip;
412         return 0xffff == ips[5];
413 }
414
415 /*
416  *  the following routines are unrolled with no memset's to speed
417  *  up the usual case.  They assume IP addresses are naturally aligned.
418  */
419 void v4tov6(uint8_t * v6, uint8_t * v4)
420 {
421         uint32_t *v6p = (uint32_t *)v6;
422         uint32_t *v4p = (uint32_t *)v4;
423
424         v6p[0] = 0;
425         v6p[1] = 0;
426         v6p[2] = (unsigned int)PP_NTOHL(0xffff);
427         v6p[3] = v4p[0];
428 }
429
430 int v6tov4(uint8_t * v4, uint8_t * v6)
431 {
432
433         uint32_t *v6p = (uint32_t *)v6;
434         uint32_t *v4p = (uint32_t *)v4;
435
436         if (v6p[0] == 0 && v6p[1] == 0 &&
437             v6p[2] == (unsigned int)PP_NTOHL(0xffff)) {
438                 v4p[0] = v6p[3];
439                 return 0;
440         } else {
441                 v4p[0] = 0;
442                 return -1;
443         }
444 }
445
446 uint32_t parseip(uint8_t * to, char *from)
447 {
448         int i, elipsis = 0, v4 = 1;
449         uint32_t x;
450         char *p, *op;
451
452         memset(to, 0, IPaddrlen);
453         p = from;
454         for (i = 0; i < 16 && *p; i += 2) {
455                 op = p;
456                 x = strtoul(p, &p, 16);
457                 if (*p == '.' || (*p == 0 && i == 0)) {
458                         p = v4parseip(to + i, op);
459                         i += 4;
460                         break;
461                 } else {
462                         to[i] = x >> 8;
463                         to[i + 1] = x;
464                 }
465                 if (*p == ':') {
466                         v4 = 0;
467                         if (*++p == ':') {
468                                 elipsis = i + 2;
469                                 p++;
470                         }
471                 }
472         }
473         if (i < 16) {
474                 memmove(&to[elipsis + 16 - i], &to[elipsis], i - elipsis);
475                 memset(&to[elipsis], 0, 16 - i);
476         }
477         if (v4) {
478                 to[10] = to[11] = 0xff;
479                 return nhgetl(to + 12);
480         } else
481                 return 6;
482 }
483
484 /*
485  *  hack to allow ip v4 masks to be entered in the old
486  *  style
487  */
488 uint32_t parseipmask(uint8_t * to, char *from)
489 {
490         uint32_t x;
491         int i;
492         uint8_t *p;
493
494         if (*from == '/') {
495                 /* as a number of prefix bits */
496                 i = atoi(from + 1);
497                 if (i < 0)
498                         i = 0;
499                 if (i > 128)
500                         i = 128;
501                 memset(to, 0, IPaddrlen);
502                 for (p = to; i >= 8; i -= 8)
503                         *p++ = 0xff;
504                 if (i > 0)
505                         *p = ~((1 << (8 - i)) - 1);
506                 x = nhgetl(to + IPv4off);
507         } else {
508                 /* as a straight bit mask */
509                 x = parseip(to, from);
510                 if (memcmp(to, v4prefix, IPv4off) == 0)
511                         memset(to, 0xff, IPv4off);
512         }
513         return x;
514 }
515
516 void maskip(uint8_t * from, uint8_t * mask, uint8_t * to)
517 {
518         int i;
519
520         for (i = 0; i < IPaddrlen; i++)
521                 to[i] = from[i] & mask[i];
522 }
523
524 uint8_t classmask[4][16] = {
525         {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
526          0xff, 0x00, 0x00, 0x00}
527         ,
528         {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
529          0xff, 0x00, 0x00, 0x00}
530         ,
531         {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
532          0xff, 0xff, 0x00, 0x00}
533         ,
534
535         {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
536          0xff, 0xff, 0xff, 0x00}
537         ,
538 };
539
540 uint8_t *defmask(uint8_t * ip)
541 {
542         if (isv4(ip))
543                 return classmask[ip[IPv4off] >> 6];
544         else {
545                 if (ipcmp(ip, v6loopback) == 0)
546                         return IPallbits;
547                 else if (memcmp(ip, v6linklocal, v6llpreflen) == 0)
548                         return v6linklocalmask;
549                 else if (memcmp(ip, v6sitelocal, v6slpreflen) == 0)
550                         return v6sitelocalmask;
551                 else if (memcmp(ip, v6solicitednode, v6snpreflen) == 0)
552                         return v6solicitednodemask;
553                 else if (memcmp(ip, v6multicast, v6mcpreflen) == 0)
554                         return v6multicastmask;
555                 return IPallbits;
556         }
557 }
558
559 void ipv62smcast(uint8_t * smcast, uint8_t * a)
560 {
561         assert(IPaddrlen == 16);
562         memmove(smcast, v6solicitednode, IPaddrlen);
563         smcast[13] = a[13];
564         smcast[14] = a[14];
565         smcast[15] = a[15];
566 }
567
568 /*
569  *  parse a hex mac address
570  */
571 int parsemac(uint8_t * to, char *from, int len)
572 {
573         char nip[4];
574         char *p;
575         int i;
576
577         p = from;
578         memset(to, 0, len);
579         for (i = 0; i < len; i++) {
580                 if (p[0] == '\0' || p[1] == '\0')
581                         break;
582
583                 nip[0] = p[0];
584                 nip[1] = p[1];
585                 nip[2] = '\0';
586                 p += 2;
587
588                 to[i] = strtoul(nip, 0, 16);
589                 if (*p == ':')
590                         p++;
591         }
592         return i;
593 }
594
595 /*
596  *  hashing tcp, udp, ... connections
597  *  gcc weirdness: it gave a bogus result until ron split the %= out.
598  */
599 uint32_t iphash(uint8_t * sa, uint16_t sp, uint8_t * da, uint16_t dp)
600 {
601         uint32_t ret;
602
603         ret = (sa[IPaddrlen - 1] << 24) ^ (sp << 16) ^ (da[IPaddrlen - 1] << 8)
604                 ^ dp;
605         ret %= Nhash;
606         return ret;
607 }
608
609 void iphtadd(struct Ipht *ht, struct conv *c)
610 {
611         uint32_t hv;
612         struct Iphash *h;
613
614         hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
615         h = kzmalloc(sizeof(*h), 0);
616         if (ipcmp(c->raddr, IPnoaddr) != 0)
617                 h->match = IPmatchexact;
618         else {
619                 if (ipcmp(c->laddr, IPnoaddr) != 0) {
620                         if (c->lport == 0)
621                                 h->match = IPmatchaddr;
622                         else
623                                 h->match = IPmatchpa;
624                 } else {
625                         if (c->lport == 0)
626                                 h->match = IPmatchany;
627                         else
628                                 h->match = IPmatchport;
629                 }
630         }
631         h->c = c;
632
633         spin_lock(&ht->lock);
634         h->next = ht->tab[hv];
635         ht->tab[hv] = h;
636         spin_unlock(&ht->lock);
637 }
638
639 void iphtrem(struct Ipht *ht, struct conv *c)
640 {
641         uint32_t hv;
642         struct Iphash **l, *h;
643
644         hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
645         spin_lock(&ht->lock);
646         for (l = &ht->tab[hv]; (*l) != NULL; l = &(*l)->next)
647                 if ((*l)->c == c) {
648                         h = *l;
649                         (*l) = h->next;
650                         kfree(h);
651                         break;
652                 }
653         spin_unlock(&ht->lock);
654 }
655
656 /* look for a matching conversation with the following precedence
657  *      connected && raddr,rport,laddr,lport
658  *      announced && laddr,lport
659  *      announced && *,lport
660  *      announced && laddr,*
661  *      announced && *,*
662  */
663 struct conv *iphtlook(struct Ipht *ht, uint8_t * sa, uint16_t sp, uint8_t * da,
664                                           uint16_t dp)
665 {
666         uint32_t hv;
667         struct Iphash *h;
668         struct conv *c;
669
670         /* exact 4 pair match (connection) */
671         hv = iphash(sa, sp, da, dp);
672         spin_lock(&ht->lock);
673         for (h = ht->tab[hv]; h != NULL; h = h->next) {
674                 if (h->match != IPmatchexact)
675                         continue;
676                 c = h->c;
677                 if (sp == c->rport && dp == c->lport
678                     && ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0) {
679                         spin_unlock(&ht->lock);
680                         return c;
681                 }
682         }
683
684         /* match local address and port */
685         hv = iphash(IPnoaddr, 0, da, dp);
686         for (h = ht->tab[hv]; h != NULL; h = h->next) {
687                 if (h->match != IPmatchpa)
688                         continue;
689                 c = h->c;
690                 if (dp == c->lport && ipcmp(da, c->laddr) == 0) {
691                         spin_unlock(&ht->lock);
692                         return c;
693                 }
694         }
695
696         /* match just port */
697         hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
698         for (h = ht->tab[hv]; h != NULL; h = h->next) {
699                 if (h->match != IPmatchport)
700                         continue;
701                 c = h->c;
702                 if (dp == c->lport) {
703                         spin_unlock(&ht->lock);
704                         return c;
705                 }
706         }
707
708         /* match local address */
709         hv = iphash(IPnoaddr, 0, da, 0);
710         for (h = ht->tab[hv]; h != NULL; h = h->next) {
711                 if (h->match != IPmatchaddr)
712                         continue;
713                 c = h->c;
714                 if (ipcmp(da, c->laddr) == 0) {
715                         spin_unlock(&ht->lock);
716                         return c;
717                 }
718         }
719
720         /* look for something that matches anything */
721         hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
722         for (h = ht->tab[hv]; h != NULL; h = h->next) {
723                 if (h->match != IPmatchany)
724                         continue;
725                 c = h->c;
726                 spin_unlock(&ht->lock);
727                 return c;
728         }
729         spin_unlock(&ht->lock);
730         return NULL;
731 }
732
733 void dump_ipht(struct Ipht *ht)
734 {
735         struct Iphash *h;
736         struct conv *c;
737
738         spin_lock(&ht->lock);
739         for (int i = 0; i < Nipht; i++) {
740                 for (h = ht->tab[i]; h != NULL; h = h->next) {
741                         c = h->c;
742                         printk("Conv proto %s, idx %d: local %I:%d, remote %I:%d\n",
743                                c->p->name, c->x, c->laddr, c->lport, c->raddr,
744                                c->rport);
745                 }
746         }
747         spin_unlock(&ht->lock);
748 }