akaros/kern/src/net/ipaux.c
<<
>>
Prefs
   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 */
  45uint8_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
  52uint8_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
  59uint8_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
  66uint8_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
  73uint8_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
  80uint8_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
  87uint8_t IPnoaddr[IPaddrlen];
  88
  89/*
  90 *  prefix of all v4 addresses
  91 */
  92uint8_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
  99char *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 */
 125uint8_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
 132uint8_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
 139uint8_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
 146uint8_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
 153int v6llpreflen = 8;                    // link-local prefix length
 154uint8_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
 161uint8_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
 168int v6slpreflen = 6;                    // site-local prefix length
 169uint8_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
 176uint8_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
 183uint8_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
 190int v6mcpreflen = 1;                    // multicast prefix length
 191uint8_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
 198uint8_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
 205int v6aNpreflen = 2;                    // all nodes (N) prefix
 206uint8_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
 213uint8_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
 220int v6aLpreflen = 2;                    // all nodes (L) prefix
 221uint8_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
 228uint8_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
 235uint8_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
 242uint8_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
 249uint8_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
 256int v6snpreflen = 13;
 257
 258uint16_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
 305uint16_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
 358enum {
 359        Isprefix = 16,
 360};
 361
 362static 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
 376extern 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
 409int 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 */
 419void 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
 430int 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
 446uint32_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 */
 488uint32_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
 516void 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
 524uint8_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
 540uint8_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
 559void 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 */
 571int 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 */
 599uint32_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
 609void 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
 639void 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 */
 663struct 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
 733void 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}
 749