181634Sbrian/*-
281634Sbrian * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
381634Sbrian * All rights reserved.
481634Sbrian *
581634Sbrian * Redistribution and use in source and binary forms, with or without
681634Sbrian * modification, are permitted provided that the following conditions
781634Sbrian * are met:
881634Sbrian * 1. Redistributions of source code must retain the above copyright
981634Sbrian *    notice, this list of conditions and the following disclaimer.
1081634Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1181634Sbrian *    notice, this list of conditions and the following disclaimer in the
1281634Sbrian *    documentation and/or other materials provided with the distribution.
1381634Sbrian *
1481634Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1581634Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1681634Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1781634Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1881634Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1981634Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2081634Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2181634Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2281634Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2381634Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2481634Sbrian * SUCH DAMAGE.
2581634Sbrian *
2681634Sbrian * $FreeBSD$
2781634Sbrian */
2881634Sbrian
2981634Sbrian#include <sys/types.h>
3081634Sbrian#include <sys/socket.h>
3196732Sbrian#ifdef __OpenBSD__
3296732Sbrian#include <net/if_types.h>
3396732Sbrian#include <net/route.h>
3496732Sbrian#endif
3581634Sbrian#include <netinet/in.h>
3681634Sbrian#include <netinet/in_systm.h>
3781634Sbrian#include <netinet/ip.h>
3881634Sbrian#include <arpa/inet.h>
3981634Sbrian#include <sys/un.h>
4081634Sbrian
4181634Sbrian#include <netdb.h>
4281634Sbrian#include <stdio.h>
4381634Sbrian#include <stdlib.h>
4481634Sbrian#include <string.h>
4581634Sbrian#include <termios.h>
4681634Sbrian
4781634Sbrian#include "log.h"
4881634Sbrian#include "ncpaddr.h"
4981634Sbrian#include "timer.h"
5081634Sbrian#include "fsm.h"
5181634Sbrian#include "defs.h"
5281634Sbrian#include "slcompress.h"
5381634Sbrian#include "iplist.h"
5481634Sbrian#include "throughput.h"
5581634Sbrian#include "mbuf.h"
5681634Sbrian#include "ipcp.h"
5781634Sbrian#include "descriptor.h"
5881634Sbrian#include "layer.h"
5981634Sbrian#include "lqr.h"
6081634Sbrian#include "hdlc.h"
6181634Sbrian#include "lcp.h"
6281634Sbrian#include "ccp.h"
6381634Sbrian#include "link.h"
6481634Sbrian#include "mp.h"
6581634Sbrian#include "ipv6cp.h"
6681634Sbrian#include "ncp.h"
6781634Sbrian
6881634Sbrian
6981634Sbrian#define ncprange_ip4addr	u.ip4.ipaddr
7081634Sbrian#define ncprange_ip4mask	u.ip4.mask
7181634Sbrian#define ncprange_ip4width	u.ip4.width
7281634Sbrian#define ncpaddr_ip4addr		u.ip4addr
7381634Sbrian#ifndef NOINET6
7481634Sbrian#define ncprange_ip6addr	u.ip6.ipaddr
7581634Sbrian#define ncprange_ip6width	u.ip6.width
7681634Sbrian#define ncpaddr_ip6addr		u.ip6addr
7781634Sbrian#endif
7881634Sbrian
7981634Sbrian#define	NCP_ASCIIBUFFERSIZE	52
8081634Sbrian
8181634Sbrianstatic struct in_addr
8281634Sbrianbits2mask4(int bits)
8381634Sbrian{
8481634Sbrian  struct in_addr result;
8581634Sbrian  u_int32_t bit = 0x80000000;
8681634Sbrian
8781634Sbrian  result.s_addr = 0;
8881634Sbrian
8981634Sbrian  while (bits) {
9081634Sbrian    result.s_addr |= bit;
9181634Sbrian    bit >>= 1;
9281634Sbrian    bits--;
9381634Sbrian  }
9481634Sbrian
9581634Sbrian  result.s_addr = htonl(result.s_addr);
9681634Sbrian  return result;
9781634Sbrian}
9881634Sbrian
9981634Sbrianstatic int
10081634Sbrianmask42bits(struct in_addr mask)
10181634Sbrian{
10281634Sbrian  u_int32_t msk = ntohl(mask.s_addr);
10381634Sbrian  u_int32_t tst;
10481634Sbrian  int ret;
10581634Sbrian
10681634Sbrian  for (ret = 32, tst = 1; tst; ret--, tst <<= 1)
10781634Sbrian    if (msk & tst)
10881634Sbrian      break;
10981634Sbrian
11081634Sbrian  for (tst <<= 1; tst; tst <<= 1)
11181634Sbrian    if (!(msk & tst))
11281634Sbrian      break;
11381634Sbrian
11481634Sbrian  return tst ? -1 : ret;
11581634Sbrian}
11681634Sbrian
11781634Sbrian#ifndef NOINET6
11881634Sbrianstatic struct in6_addr
11981634Sbrianbits2mask6(int bits)
12081634Sbrian{
12181634Sbrian  struct in6_addr result;
12281634Sbrian  u_int32_t bit = 0x80;
12381634Sbrian  u_char *c = result.s6_addr;
12481634Sbrian
12581634Sbrian  memset(&result, '\0', sizeof result);
12681634Sbrian
12781634Sbrian  while (bits) {
12881634Sbrian    if (bit == 0) {
12981634Sbrian      bit = 0x80;
13081634Sbrian      c++;
13181634Sbrian    }
13281634Sbrian    *c |= bit;
13381634Sbrian    bit >>= 1;
13481634Sbrian    bits--;
13581634Sbrian  }
13681634Sbrian
13781634Sbrian  return result;
13881634Sbrian}
13981634Sbrian
14081634Sbrianstatic int
14181634Sbrianmask62bits(const struct in6_addr *mask)
14281634Sbrian{
14381634Sbrian  const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
14481634Sbrian  const u_char *c, *p, *end;
145115303Speter  int masklen, m;
14681634Sbrian
14781634Sbrian  p = (const u_char *)mask;
14881634Sbrian  for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++)
14981634Sbrian    masklen += 8;
15081634Sbrian
15181634Sbrian  if (p < end) {
152115303Speter    for (c = masks, m = 0; c < masks + sizeof masks; c++, m++)
15381634Sbrian      if (*c == *p) {
154115303Speter        masklen += m;
15581634Sbrian        break;
15681634Sbrian      }
15781634Sbrian  }
15881634Sbrian
15981634Sbrian  return masklen;
16081634Sbrian}
16181634Sbrian
162134789Sbrian#if 0
16381634Sbrianstatic void
16481634Sbrianadjust_linklocal(struct sockaddr_in6 *sin6)
16581634Sbrian{
16681634Sbrian    /* XXX: ?????!?!?!!!!!  This is horrible ! */
167102558Sbrian    /*
168102558Sbrian     * The kernel does not understand sin6_scope_id for routing at this moment.
169102558Sbrian     * We should rather keep the embedded ID.
170102558Sbrian     * jinmei@kame.net, 20011026
171102558Sbrian     */
17281634Sbrian    if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
17381634Sbrian        IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) {
17481634Sbrian      sin6->sin6_scope_id =
17581634Sbrian        ntohs(*(u_short *)&sin6->sin6_addr.s6_addr[2]);
17681634Sbrian      *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0;
17781634Sbrian    }
17881634Sbrian}
17981634Sbrian#endif
180134789Sbrian#endif
18181634Sbrian
18281634Sbrianvoid
18381634Sbrianncpaddr_init(struct ncpaddr *addr)
18481634Sbrian{
18581634Sbrian  addr->ncpaddr_family = AF_UNSPEC;
18681634Sbrian}
18781634Sbrian
18881634Sbrianint
18981739Sbrianncpaddr_isset(const struct ncpaddr *addr)
19081739Sbrian{
19181739Sbrian  return addr->ncpaddr_family != AF_UNSPEC;
19281739Sbrian}
19381739Sbrian
19481739Sbrianint
19581634Sbrianncpaddr_isdefault(const struct ncpaddr *addr)
19681634Sbrian{
19781634Sbrian  switch (addr->ncpaddr_family) {
19881634Sbrian  case AF_INET:
19981634Sbrian    if (addr->ncpaddr_ip4addr.s_addr == INADDR_ANY)
20081634Sbrian      return 1;
20181634Sbrian    break;
20281634Sbrian
20381634Sbrian#ifndef NOINET6
20481634Sbrian  case AF_INET6:
20581634Sbrian    if (IN6_IS_ADDR_UNSPECIFIED(&addr->ncpaddr_ip6addr))
20681634Sbrian      return 1;
20781634Sbrian    break;
20881634Sbrian#endif
20981634Sbrian  }
21081634Sbrian
21181634Sbrian  return 0;
21281634Sbrian}
21381634Sbrian
21481634Sbrianint
21581634Sbrianncpaddr_equal(const struct ncpaddr *addr, const struct ncpaddr *cmp)
21681634Sbrian{
21781634Sbrian  if (addr->ncpaddr_family != cmp->ncpaddr_family)
21881634Sbrian    return 0;
21981634Sbrian
22081634Sbrian  switch (addr->ncpaddr_family) {
22181634Sbrian  case AF_INET:
22281634Sbrian    return addr->ncpaddr_ip4addr.s_addr == cmp->ncpaddr_ip4addr.s_addr;
22381634Sbrian
22481634Sbrian#ifndef NOINET6
22581634Sbrian  case AF_INET6:
22681634Sbrian    return !memcmp(&addr->ncpaddr_ip6addr, &cmp->ncpaddr_ip6addr,
22781634Sbrian                   sizeof addr->ncpaddr_ip6addr);
22881634Sbrian#endif
22981634Sbrian
23081634Sbrian  case AF_UNSPEC:
23181634Sbrian    return 1;
23281634Sbrian  }
23381634Sbrian
23481634Sbrian  return 0;
23581634Sbrian}
23681634Sbrian
23781634Sbrianvoid
23881634Sbrianncpaddr_copy(struct ncpaddr *addr, const struct ncpaddr *from)
23981634Sbrian{
24081634Sbrian  switch (from->ncpaddr_family) {
24181634Sbrian  case AF_INET:
24281634Sbrian    addr->ncpaddr_family = AF_INET;
24381634Sbrian    addr->ncpaddr_ip4addr = from->ncpaddr_ip4addr;
24481634Sbrian    break;
24581634Sbrian#ifndef NOINET6
24681634Sbrian  case AF_INET6:
24781634Sbrian    addr->ncpaddr_family = AF_INET6;
24881634Sbrian    addr->ncpaddr_ip6addr = from->ncpaddr_ip6addr;
24981634Sbrian    break;
25081634Sbrian#endif
25181634Sbrian  default:
25281634Sbrian    addr->ncpaddr_family = AF_UNSPEC;
25381634Sbrian  }
25481634Sbrian}
25581634Sbrian
25681634Sbrianvoid
25781634Sbrianncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip)
25881634Sbrian{
25981634Sbrian  addr->ncpaddr_family = AF_INET;
26081634Sbrian  addr->ncpaddr_ip4addr.s_addr = ip;
26181634Sbrian}
26281634Sbrian
26381634Sbrianint
26481634Sbrianncpaddr_getip4addr(const struct ncpaddr *addr, u_int32_t *ip)
26581634Sbrian{
26681634Sbrian  if (addr->ncpaddr_family != AF_INET)
26781634Sbrian    return 0;
26881634Sbrian  *ip = addr->ncpaddr_ip4addr.s_addr;
26981634Sbrian  return 1;
27081634Sbrian}
27181634Sbrian
27281634Sbrianvoid
27381634Sbrianncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip)
27481634Sbrian{
27581634Sbrian  addr->ncpaddr_family = AF_INET;
27681634Sbrian  addr->ncpaddr_ip4addr = ip;
27781634Sbrian}
27881634Sbrian
27981634Sbrianint
28081634Sbrianncpaddr_getip4(const struct ncpaddr *addr, struct in_addr *ip)
28181634Sbrian{
28281634Sbrian  if (addr->ncpaddr_family != AF_INET)
28381634Sbrian    return 0;
28481634Sbrian  *ip = addr->ncpaddr_ip4addr;
28581634Sbrian  return 1;
28681634Sbrian}
28781634Sbrian
28881634Sbrian#ifndef NOINET6
28981634Sbrianvoid
29081634Sbrianncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6)
29181634Sbrian{
29281634Sbrian  addr->ncpaddr_family = AF_INET6;
29381634Sbrian  addr->ncpaddr_ip6addr = *ip6;
29481634Sbrian}
29581634Sbrian
29681634Sbrianint
29781634Sbrianncpaddr_getip6(const struct ncpaddr *addr, struct in6_addr *ip6)
29881634Sbrian{
29981634Sbrian  if (addr->ncpaddr_family != AF_INET6)
30081634Sbrian    return 0;
30181634Sbrian  *ip6 = addr->ncpaddr_ip6addr;
30281634Sbrian  return 1;
30381634Sbrian}
30481634Sbrian#endif
30581634Sbrian
30681634Sbrianvoid
30781634Sbrianncpaddr_getsa(const struct ncpaddr *addr, struct sockaddr_storage *host)
30881634Sbrian{
30981634Sbrian  struct sockaddr_in *host4 = (struct sockaddr_in *)host;
31081634Sbrian#ifndef NOINET6
31181634Sbrian  struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
31281634Sbrian#endif
31381634Sbrian
31481634Sbrian  memset(host, '\0', sizeof(*host));
31581634Sbrian
31681634Sbrian  switch (addr->ncpaddr_family) {
31781634Sbrian  case AF_INET:
31881634Sbrian    host4->sin_family = AF_INET;
31981634Sbrian    host4->sin_len = sizeof(*host4);
32081634Sbrian    host4->sin_addr = addr->ncpaddr_ip4addr;
32181634Sbrian    break;
32281634Sbrian
32381634Sbrian#ifndef NOINET6
32481634Sbrian  case AF_INET6:
32581634Sbrian    host6->sin6_family = AF_INET6;
32681634Sbrian    host6->sin6_len = sizeof(*host6);
32781634Sbrian    host6->sin6_addr = addr->ncpaddr_ip6addr;
32881634Sbrian    break;
32981634Sbrian#endif
33081634Sbrian
33181634Sbrian  default:
33281634Sbrian    host->ss_family = AF_UNSPEC;
33381634Sbrian    break;
33481634Sbrian  }
33581634Sbrian}
33681634Sbrian
33781634Sbrianvoid
33881634Sbrianncpaddr_setsa(struct ncpaddr *addr, const struct sockaddr *host)
33981634Sbrian{
34081634Sbrian  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
34181634Sbrian#ifndef NOINET6
34281634Sbrian  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
34381634Sbrian#endif
34481634Sbrian
34581634Sbrian  switch (host->sa_family) {
34681634Sbrian  case AF_INET:
34781634Sbrian    addr->ncpaddr_family = AF_INET;
34881634Sbrian    addr->ncpaddr_ip4addr = host4->sin_addr;
34981634Sbrian    break;
35081634Sbrian
35181634Sbrian#ifndef NOINET6
35281634Sbrian  case AF_INET6:
35381634Sbrian    if (IN6_IS_ADDR_V4MAPPED(&host6->sin6_addr)) {
35481634Sbrian      addr->ncpaddr_family = AF_INET;
35581634Sbrian      addr->ncpaddr_ip4addr.s_addr =
35681634Sbrian        *(const u_int32_t *)(host6->sin6_addr.s6_addr + 12);
35781634Sbrian    } else {
35881634Sbrian      addr->ncpaddr_family = AF_INET6;
35981634Sbrian      addr->ncpaddr_ip6addr = host6->sin6_addr;
36081634Sbrian    }
36181634Sbrian    break;
36281634Sbrian#endif
36381634Sbrian
36481634Sbrian  default:
36581634Sbrian    addr->ncpaddr_family = AF_UNSPEC;
36681634Sbrian  }
36781634Sbrian}
36881634Sbrian
36981634Sbrianstatic char *
37081634Sbrianncpaddr_ntowa(const struct ncpaddr *addr)
37181634Sbrian{
37281634Sbrian  static char res[NCP_ASCIIBUFFERSIZE];
37381634Sbrian#ifndef NOINET6
37481634Sbrian  struct sockaddr_in6 sin6;
37581634Sbrian#endif
37681634Sbrian
37781634Sbrian  switch (addr->ncpaddr_family) {
37881634Sbrian  case AF_INET:
37981634Sbrian    snprintf(res, sizeof res, "%s", inet_ntoa(addr->ncpaddr_ip4addr));
38081634Sbrian    return res;
38181634Sbrian
38281634Sbrian#ifndef NOINET6
38381634Sbrian  case AF_INET6:
38481634Sbrian    memset(&sin6, '\0', sizeof(sin6));
38581634Sbrian    sin6.sin6_len = sizeof(sin6);
38681634Sbrian    sin6.sin6_family = AF_INET6;
38781634Sbrian    sin6.sin6_addr = addr->ncpaddr_ip6addr;
388134789Sbrian#if 0
38981634Sbrian    adjust_linklocal(&sin6);
390134789Sbrian#endif
39181634Sbrian    if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
392102558Sbrian                    NULL, 0, NI_NUMERICHOST) != 0)
39381634Sbrian      break;
39481634Sbrian
39581634Sbrian    return res;
39681634Sbrian#endif
39781634Sbrian  }
39881634Sbrian
39981634Sbrian  snprintf(res, sizeof res, "<AF_UNSPEC>");
40081634Sbrian  return res;
40181634Sbrian}
40281634Sbrian
40381634Sbrianconst char *
40481634Sbrianncpaddr_ntoa(const struct ncpaddr *addr)
40581634Sbrian{
40681634Sbrian  return ncpaddr_ntowa(addr);
40781634Sbrian}
40881634Sbrian
40981634Sbrian
41081634Sbrianint
41181634Sbrianncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data)
41281634Sbrian{
41381634Sbrian  struct ncprange range;
41481634Sbrian
41581634Sbrian  if (!ncprange_aton(&range, ncp, data))
41681634Sbrian    return 0;
41798243Sbrian
418116654Sume  if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32 &&
419116654Sume      range.ncprange_ip4addr.s_addr != INADDR_ANY) {
42081634Sbrian    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data);
42181634Sbrian    return 0;
42281634Sbrian  }
42381634Sbrian
42481634Sbrian#ifndef NOINET6
425116654Sume  if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128 &&
426116654Sume      !IN6_IS_ADDR_UNSPECIFIED(&range.ncprange_ip6addr)) {
42781634Sbrian    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data);
42881634Sbrian    return 0;
42981634Sbrian  }
43081634Sbrian#endif
43181634Sbrian
43281634Sbrian  switch (range.ncprange_family) {
43381634Sbrian  case AF_INET:
43481634Sbrian    addr->ncpaddr_family = range.ncprange_family;
43581634Sbrian    addr->ncpaddr_ip4addr = range.ncprange_ip4addr;
43681634Sbrian    return 1;
43781634Sbrian
43881634Sbrian#ifndef NOINET6
43981634Sbrian  case AF_INET6:
44081634Sbrian    addr->ncpaddr_family = range.ncprange_family;
44181634Sbrian    addr->ncpaddr_ip6addr = range.ncprange_ip6addr;
44281634Sbrian    return 1;
44381634Sbrian#endif
44481634Sbrian  }
44581634Sbrian
44681634Sbrian  return 0;
44781634Sbrian}
44881634Sbrian
44981634Sbrianvoid
45081634Sbrianncprange_init(struct ncprange *range)
45181634Sbrian{
45281634Sbrian  range->ncprange_family = AF_UNSPEC;
45381634Sbrian}
45481634Sbrian
45581634Sbrianint
45681634Sbrianncprange_isset(const struct ncprange *range)
45781634Sbrian{
45881634Sbrian  return range->ncprange_family != AF_UNSPEC;
45981634Sbrian}
46081634Sbrian
46181634Sbrianint
46281634Sbrianncprange_equal(const struct ncprange *range, const struct ncprange *cmp)
46381634Sbrian{
46481634Sbrian  if (range->ncprange_family != cmp->ncprange_family)
46581634Sbrian    return 0;
46681634Sbrian
46781634Sbrian  switch (range->ncprange_family) {
46881634Sbrian  case AF_INET:
46981634Sbrian    if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr)
47081634Sbrian      return 0;
47181634Sbrian    return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr;
47281634Sbrian
47381634Sbrian#ifndef NOINET6
47481634Sbrian  case AF_INET6:
47581634Sbrian    if (range->ncprange_ip6width != cmp->ncprange_ip6width)
47681634Sbrian      return 0;
47781634Sbrian    return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr,
47881634Sbrian                   sizeof range->ncprange_ip6addr);
47981634Sbrian#endif
48081634Sbrian
48181634Sbrian  case AF_UNSPEC:
48281634Sbrian    return 1;
48381634Sbrian  }
48481634Sbrian
48581634Sbrian  return 0;
48681634Sbrian}
48781634Sbrian
48881634Sbrianint
48981634Sbrianncprange_isdefault(const struct ncprange *range)
49081634Sbrian{
49181634Sbrian  switch (range->ncprange_family) {
49281634Sbrian  case AF_INET:
49381634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_ANY)
49481634Sbrian      return 1;
49581634Sbrian    break;
49681634Sbrian
49781634Sbrian#ifndef NOINET6
49881634Sbrian  case AF_INET6:
49981634Sbrian    if (range->ncprange_ip6width == 0 &&
50081634Sbrian        IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
50181634Sbrian      return 1;
50281634Sbrian    break;
50381634Sbrian#endif
50481634Sbrian  }
50581634Sbrian
50681634Sbrian  return 0;
50781634Sbrian}
50881634Sbrian
50981634Sbrianvoid
51081634Sbrianncprange_setdefault(struct ncprange *range, int af)
51181634Sbrian{
51281634Sbrian  memset(range, '\0', sizeof *range);
51381634Sbrian  range->ncprange_family = af;
51481634Sbrian}
51581634Sbrian
51681634Sbrianint
51781634Sbrianncprange_contains(const struct ncprange *range, const struct ncpaddr *addr)
51881634Sbrian{
51981634Sbrian#ifndef NOINET6
52081634Sbrian  const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
52181634Sbrian  const u_char *addrp, *rangep;
52281634Sbrian  int bits;
52381634Sbrian#endif
52481634Sbrian
52581634Sbrian  if (range->ncprange_family != addr->ncpaddr_family)
52681634Sbrian    return 0;
52781634Sbrian
52881634Sbrian  switch (range->ncprange_family) {
52981634Sbrian  case AF_INET:
53081634Sbrian    return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
53181634Sbrian             range->ncprange_ip4mask.s_addr);
53281634Sbrian
53381634Sbrian#ifndef NOINET6
53481634Sbrian  case AF_INET6:
53581634Sbrian    rangep = (const u_char *)range->ncprange_ip6addr.s6_addr;
53681634Sbrian    addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr;
53781634Sbrian
53881634Sbrian    for (bits = range->ncprange_ip6width; bits > 0; bits -= 8)
53981634Sbrian      if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1])
54081634Sbrian        return 0;
54181634Sbrian
54281634Sbrian    return 1;
54381634Sbrian#endif
54481634Sbrian  }
54581634Sbrian
54681634Sbrian  return 0;
54781634Sbrian}
54881634Sbrian
54981634Sbrianint
55081634Sbrianncprange_containsip4(const struct ncprange *range, struct in_addr addr)
55181634Sbrian{
55281634Sbrian  switch (range->ncprange_family) {
55381634Sbrian  case AF_INET:
55481634Sbrian    return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
55581634Sbrian             range->ncprange_ip4mask.s_addr);
55681634Sbrian  }
55781634Sbrian
55881634Sbrian  return 0;
55981634Sbrian}
56081634Sbrian
56181634Sbrianvoid
56281634Sbrianncprange_copy(struct ncprange *range, const struct ncprange *from)
56381634Sbrian{
56481634Sbrian  switch (from->ncprange_family) {
56581634Sbrian  case AF_INET:
56681634Sbrian    range->ncprange_family = AF_INET;
56781634Sbrian    range->ncprange_ip4addr = from->ncprange_ip4addr;
56881634Sbrian    range->ncprange_ip4mask = from->ncprange_ip4mask;
56981634Sbrian    range->ncprange_ip4width = from->ncprange_ip4width;
57081634Sbrian    break;
57181634Sbrian
57281634Sbrian#ifndef NOINET6
57381634Sbrian  case AF_INET6:
57481634Sbrian    range->ncprange_family = AF_INET6;
57581634Sbrian    range->ncprange_ip6addr = from->ncprange_ip6addr;
57681634Sbrian    range->ncprange_ip6width = from->ncprange_ip6width;
57781634Sbrian    break;
57881634Sbrian#endif
57981634Sbrian
58081634Sbrian  default:
58181634Sbrian    range->ncprange_family = AF_UNSPEC;
58281634Sbrian  }
58381634Sbrian}
58481634Sbrian
58581634Sbrianvoid
58681634Sbrianncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width)
58781634Sbrian{
58881634Sbrian  ncprange_sethost(range, addr);
58981634Sbrian  ncprange_setwidth(range, width);
59081634Sbrian}
59181634Sbrian
59281634Sbrianvoid
59381634Sbrianncprange_sethost(struct ncprange *range, const struct ncpaddr *from)
59481634Sbrian{
59581634Sbrian  switch (from->ncpaddr_family) {
59681634Sbrian  case AF_INET:
59781634Sbrian    range->ncprange_family = AF_INET;
59881634Sbrian    range->ncprange_ip4addr = from->ncpaddr_ip4addr;
59986832Sbrian    if (from->ncpaddr_ip4addr.s_addr == INADDR_ANY) {
60086832Sbrian      range->ncprange_ip4mask.s_addr = INADDR_ANY;
60186832Sbrian      range->ncprange_ip4width = 0;
60286832Sbrian    } else {
60386832Sbrian      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
60486832Sbrian      range->ncprange_ip4width = 32;
60586832Sbrian    }
60681634Sbrian    break;
60781634Sbrian
60881634Sbrian#ifndef NOINET6
60981634Sbrian  case AF_INET6:
61081634Sbrian    range->ncprange_family = AF_INET6;
61181634Sbrian    range->ncprange_ip6addr = from->ncpaddr_ip6addr;
61281634Sbrian    range->ncprange_ip6width = 128;
61381634Sbrian    break;
61481634Sbrian#endif
61581634Sbrian
61681634Sbrian  default:
61781634Sbrian    range->ncprange_family = AF_UNSPEC;
61881634Sbrian  }
61981634Sbrian}
62081634Sbrian
62181634Sbrianint
62286815Sbrianncprange_ishost(const struct ncprange *range)
62386815Sbrian{
62486815Sbrian  switch (range->ncprange_family) {
62586815Sbrian  case AF_INET:
62686815Sbrian    return range->ncprange_ip4width == 32;
62786815Sbrian#ifndef NOINET6
62886815Sbrian  case AF_INET6:
62986815Sbrian    return range->ncprange_ip6width == 128;
63086815Sbrian#endif
63186815Sbrian  }
63286815Sbrian
63386815Sbrian  return (0);
63486815Sbrian}
63586815Sbrian
63686815Sbrianint
63781634Sbrianncprange_setwidth(struct ncprange *range, int width)
63881634Sbrian{
63981634Sbrian  switch (range->ncprange_family) {
64081634Sbrian  case AF_INET:
64181634Sbrian    if (width < 0 || width > 32)
64281634Sbrian      break;
64381634Sbrian    range->ncprange_ip4width = width;
64481634Sbrian    range->ncprange_ip4mask = bits2mask4(width);
64581634Sbrian    break;
64681634Sbrian
64781634Sbrian#ifndef NOINET6
64881634Sbrian  case AF_INET6:
64981634Sbrian    if (width < 0 || width > 128)
65081634Sbrian      break;
65181634Sbrian    range->ncprange_ip6width = width;
65281634Sbrian    break;
65381634Sbrian#endif
65481634Sbrian
65581634Sbrian  case AF_UNSPEC:
65681634Sbrian    return 1;
65781634Sbrian  }
65881634Sbrian
65981634Sbrian  return 0;
66081634Sbrian}
66181634Sbrian
66281634Sbrianvoid
66381634Sbrianncprange_setip4host(struct ncprange *range, struct in_addr from)
66481634Sbrian{
66581634Sbrian  range->ncprange_family = AF_INET;
66681634Sbrian  range->ncprange_ip4addr = from;
66786832Sbrian  if (from.s_addr == INADDR_ANY) {
66886832Sbrian    range->ncprange_ip4mask.s_addr = INADDR_ANY;
66986832Sbrian    range->ncprange_ip4width = 0;
67086832Sbrian  } else {
67186832Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
67286832Sbrian    range->ncprange_ip4width = 32;
67386832Sbrian  }
67481634Sbrian}
67581634Sbrian
67681634Sbrianvoid
67781634Sbrianncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk)
67881634Sbrian{
67981634Sbrian  range->ncprange_family = AF_INET;
68081634Sbrian  range->ncprange_ip4addr = from;
68181634Sbrian  range->ncprange_ip4mask = msk;
68281634Sbrian  range->ncprange_ip4width = mask42bits(msk);
68381634Sbrian}
68481634Sbrian
68581634Sbrian
68681634Sbrianint
68781634Sbrianncprange_setip4mask(struct ncprange *range, struct in_addr mask)
68881634Sbrian{
68981634Sbrian  if (range->ncprange_family != AF_INET)
69081634Sbrian    return 0;
69181634Sbrian  range->ncprange_ip4mask = mask;
69281634Sbrian  range->ncprange_ip4width = mask42bits(mask);
69381634Sbrian  return 1;
69481634Sbrian}
69581634Sbrian
69681634Sbrianvoid
69781634Sbrianncprange_setsa(struct ncprange *range, const struct sockaddr *host,
69881634Sbrian               const struct sockaddr *mask)
69981634Sbrian{
70081634Sbrian  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
70181634Sbrian  const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
70281634Sbrian#ifndef NOINET6
70381634Sbrian  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
70481634Sbrian  const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
70581634Sbrian#endif
70681634Sbrian
70781634Sbrian  switch (host->sa_family) {
70881634Sbrian  case AF_INET:
70981634Sbrian    range->ncprange_family = AF_INET;
71081634Sbrian    range->ncprange_ip4addr = host4->sin_addr;
71186832Sbrian    if (host4->sin_addr.s_addr == INADDR_ANY) {
71286832Sbrian      range->ncprange_ip4mask.s_addr = INADDR_ANY;
71386832Sbrian      range->ncprange_ip4width = 0;
71486832Sbrian    } else if (mask4 && mask4->sin_family == AF_INET) {
71581634Sbrian      range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr;
71681634Sbrian      range->ncprange_ip4width = mask42bits(mask4->sin_addr);
71781634Sbrian    } else {
71881634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
71981634Sbrian      range->ncprange_ip4width = 32;
72081634Sbrian    }
72181634Sbrian    break;
72281634Sbrian
72381634Sbrian#ifndef NOINET6
72481634Sbrian  case AF_INET6:
72581634Sbrian    range->ncprange_family = AF_INET6;
72681634Sbrian    range->ncprange_ip6addr = host6->sin6_addr;
727113110Sume    if (IN6_IS_ADDR_UNSPECIFIED(&host6->sin6_addr))
728113110Sume      range->ncprange_ip6width = 0;
729113110Sume    else
730113110Sume      range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128;
73181634Sbrian    break;
73281634Sbrian#endif
73381634Sbrian
73481634Sbrian  default:
73581634Sbrian    range->ncprange_family = AF_UNSPEC;
73681634Sbrian  }
73781634Sbrian}
73881634Sbrian
73981634Sbrianvoid
74081634Sbrianncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host,
74181634Sbrian               struct sockaddr_storage *mask)
74281634Sbrian{
74381634Sbrian  struct sockaddr_in *host4 = (struct sockaddr_in *)host;
74481634Sbrian  struct sockaddr_in *mask4 = (struct sockaddr_in *)mask;
74581634Sbrian#ifndef NOINET6
74681634Sbrian  struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
74781634Sbrian  struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask;
74881634Sbrian#endif
74981634Sbrian
75081634Sbrian  memset(host, '\0', sizeof(*host));
75181634Sbrian  if (mask)
75281634Sbrian    memset(mask, '\0', sizeof(*mask));
75381634Sbrian
75481634Sbrian  switch (range->ncprange_family) {
75581634Sbrian  case AF_INET:
75681634Sbrian    host4->sin_family = AF_INET;
75781634Sbrian    host4->sin_len = sizeof(*host4);
75881634Sbrian    host4->sin_addr = range->ncprange_ip4addr;
75981634Sbrian    if (mask4) {
76081634Sbrian      mask4->sin_family = AF_INET;
76181634Sbrian      mask4->sin_len = sizeof(*host4);
76281690Sbrian      mask4->sin_addr = range->ncprange_ip4mask;
76381634Sbrian    }
76481634Sbrian    break;
76581634Sbrian
76681634Sbrian#ifndef NOINET6
76781634Sbrian  case AF_INET6:
76881634Sbrian    host6->sin6_family = AF_INET6;
76981634Sbrian    host6->sin6_len = sizeof(*host6);
77081634Sbrian    host6->sin6_addr = range->ncprange_ip6addr;
77181634Sbrian    if (mask6) {
77281634Sbrian      mask6->sin6_family = AF_INET6;
77381634Sbrian      mask6->sin6_len = sizeof(*host6);
77481634Sbrian      mask6->sin6_addr = bits2mask6(range->ncprange_ip6width);
77581634Sbrian    }
77681634Sbrian    break;
77781634Sbrian#endif
77881634Sbrian
77981634Sbrian  default:
78081634Sbrian    host->ss_family = AF_UNSPEC;
78181634Sbrian    if (mask)
78281634Sbrian      mask->ss_family = AF_UNSPEC;
78381634Sbrian    break;
78481634Sbrian  }
78581634Sbrian}
78681634Sbrian
78781634Sbrianint
78881634Sbrianncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr)
78981634Sbrian{
79081634Sbrian  switch (range->ncprange_family) {
79181634Sbrian  case AF_INET:
79281634Sbrian    addr->ncpaddr_family = AF_INET;
79381634Sbrian    addr->ncpaddr_ip4addr = range->ncprange_ip4addr;
79481634Sbrian    return 1;
79581634Sbrian#ifndef NOINET6
79681634Sbrian  case AF_INET6:
79781634Sbrian    addr->ncpaddr_family = AF_INET6;
79881634Sbrian    addr->ncpaddr_ip6addr =  range->ncprange_ip6addr;
79981634Sbrian    return 1;
80081634Sbrian#endif
80181634Sbrian  }
80281634Sbrian
80381634Sbrian  return 0;
80481634Sbrian}
80581634Sbrian
80681634Sbrianint
80781634Sbrianncprange_getip4addr(const struct ncprange *range, struct in_addr *addr)
80881634Sbrian{
80981634Sbrian  if (range->ncprange_family != AF_INET)
81081634Sbrian    return 0;
81181634Sbrian
81281634Sbrian  *addr = range->ncprange_ip4addr;
81381634Sbrian  return 1;
81481634Sbrian}
81581634Sbrian
81681634Sbrianint
81781634Sbrianncprange_getip4mask(const struct ncprange *range, struct in_addr *mask)
81881634Sbrian{
81981634Sbrian  switch (range->ncprange_family) {
82081634Sbrian  case AF_INET:
82181634Sbrian    *mask = range->ncprange_ip4mask;
82281634Sbrian    return 1;
82381634Sbrian  }
82481634Sbrian
82581634Sbrian  return 0;
82681634Sbrian}
82781634Sbrian
82881634Sbrianint
82981634Sbrianncprange_getwidth(const struct ncprange *range, int *width)
83081634Sbrian{
83181634Sbrian  switch (range->ncprange_family) {
83281634Sbrian  case AF_INET:
83381634Sbrian    *width = range->ncprange_ip4width;
83481634Sbrian    return 1;
83581634Sbrian#ifndef NOINET6
83681634Sbrian  case AF_INET6:
83781634Sbrian    *width = range->ncprange_ip6width;
83881634Sbrian    return 1;
83981634Sbrian#endif
84081634Sbrian  }
84181634Sbrian
84281634Sbrian  return 0;
84381634Sbrian}
84481634Sbrian
84581634Sbrianconst char *
84681634Sbrianncprange_ntoa(const struct ncprange *range)
84781634Sbrian{
84881634Sbrian  char *res;
84981634Sbrian  struct ncpaddr addr;
85081634Sbrian  int len;
85181634Sbrian
85281634Sbrian  if (!ncprange_getaddr(range, &addr))
85381634Sbrian    return "<AF_UNSPEC>";
85481634Sbrian
85581634Sbrian  res = ncpaddr_ntowa(&addr);
85681634Sbrian  len = strlen(res);
85781634Sbrian  if (len >= NCP_ASCIIBUFFERSIZE - 1)
85881634Sbrian    return res;
85981634Sbrian
86081634Sbrian  switch (range->ncprange_family) {
86181634Sbrian  case AF_INET:
86281634Sbrian    if (range->ncprange_ip4width == -1) {
86381634Sbrian      /* A non-contiguous mask */
86481634Sbrian      for (; len >= 3; res[len -= 2] = '\0')
86581634Sbrian        if (strcmp(res + len - 2, ".0"))
86681634Sbrian          break;
86781634Sbrian      snprintf(res + len, sizeof res - len, "&0x%08lx",
86881924Sbrian               (unsigned long)ntohl(range->ncprange_ip4mask.s_addr));
86981634Sbrian    } else if (range->ncprange_ip4width < 32)
87081634Sbrian      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width);
87181634Sbrian
87281634Sbrian    return res;
87381634Sbrian
87481634Sbrian#ifndef NOINET6
87581634Sbrian  case AF_INET6:
87681634Sbrian    if (range->ncprange_ip6width != 128)
87781634Sbrian      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width);
87881634Sbrian
87981634Sbrian    return res;
88081634Sbrian#endif
88181634Sbrian  }
88281634Sbrian
88381634Sbrian  return "<AF_UNSPEC>";
88481634Sbrian}
88581634Sbrian
88681634Sbrian#ifndef NOINET6
88781634Sbrianint
88881634Sbrianncprange_scopeid(const struct ncprange *range)
88981634Sbrian{
89081634Sbrian  const struct in6_addr *sin6;
89181634Sbrian  int scopeid = -1;
89281634Sbrian
89381634Sbrian  if (range->ncprange_family == AF_INET6) {
89481634Sbrian    sin6 = &range->ncprange_ip6addr;
89581634Sbrian    if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6))
89681634Sbrian      if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0)
89781634Sbrian        scopeid = -1;
89881634Sbrian  }
89981634Sbrian
90081634Sbrian  return scopeid;
90181634Sbrian}
90281634Sbrian#endif
90381634Sbrian
90481634Sbrianint
90581634Sbrianncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data)
90681634Sbrian{
90781634Sbrian  int bits, len;
90881634Sbrian  char *wp;
90981634Sbrian  const char *cp;
91081634Sbrian  char *s;
91181634Sbrian
91281634Sbrian  len = strcspn(data, "/");
91381634Sbrian
91481634Sbrian  if (ncp && strncasecmp(data, "HISADDR", len) == 0) {
91581634Sbrian    range->ncprange_family = AF_INET;
91681634Sbrian    range->ncprange_ip4addr = ncp->ipcp.peer_ip;
91781634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
91881634Sbrian    range->ncprange_ip4width = 32;
91981634Sbrian    return 1;
92081634Sbrian#ifndef NOINET6
92181634Sbrian  } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) {
922112673Sume    range->ncprange_family = AF_INET6;
923112673Sume    range->ncprange_ip6addr = ncp->ipv6cp.hisaddr.ncpaddr_ip6addr;
924112673Sume    range->ncprange_ip6width = 128;
92581634Sbrian    return 1;
92681634Sbrian#endif
92781634Sbrian  } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) {
92881634Sbrian    range->ncprange_family = AF_INET;
92981634Sbrian    range->ncprange_ip4addr = ncp->ipcp.my_ip;
93081634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
93181634Sbrian    range->ncprange_ip4width = 32;
93281634Sbrian    return 1;
93381634Sbrian#ifndef NOINET6
93481634Sbrian  } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) {
935112673Sume    range->ncprange_family = AF_INET6;
936112673Sume    range->ncprange_ip6addr = ncp->ipv6cp.myaddr.ncpaddr_ip6addr;
937112673Sume    range->ncprange_ip6width = 128;
93881634Sbrian    return 1;
93981634Sbrian#endif
94081634Sbrian  } else if (ncp && strncasecmp(data, "DNS0", len) == 0) {
94181634Sbrian    range->ncprange_family = AF_INET;
94281634Sbrian    range->ncprange_ip4addr = ncp->ipcp.ns.dns[0];
94381634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
94481634Sbrian    range->ncprange_ip4width = 32;
94581634Sbrian    return 1;
94681634Sbrian  } else if (ncp && strncasecmp(data, "DNS1", len) == 0) {
94781634Sbrian    range->ncprange_family = AF_INET;
94881634Sbrian    range->ncprange_ip4addr = ncp->ipcp.ns.dns[1];
94981634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
95081634Sbrian    range->ncprange_ip4width = 32;
95181634Sbrian    return 1;
95281634Sbrian  }
95381634Sbrian
95481634Sbrian  s = (char *)alloca(len + 1);
95581634Sbrian  strncpy(s, data, len);
95681634Sbrian  s[len] = '\0';
95781634Sbrian  bits = -1;
95881634Sbrian
95981634Sbrian  if (data[len] != '\0') {
96081634Sbrian    bits = strtol(data + len + 1, &wp, 0);
96181634Sbrian    if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) {
96281634Sbrian      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
96381634Sbrian      return 0;
96481634Sbrian    }
96581634Sbrian  }
96681634Sbrian
96781634Sbrian  if ((cp = strchr(data, ':')) == NULL) {
96881634Sbrian    range->ncprange_family = AF_INET;
96981634Sbrian
97081634Sbrian    range->ncprange_ip4addr = GetIpAddr(s);
97181634Sbrian
97281634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_NONE) {
97381634Sbrian      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
97481634Sbrian      return 0;
97581634Sbrian    }
97681634Sbrian
97781634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_ANY) {
97881634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_ANY;
97981634Sbrian      range->ncprange_ip4width = 0;
98081690Sbrian    } else if (bits == -1) {
98181634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
98281634Sbrian      range->ncprange_ip4width = 32;
98381690Sbrian    } else if (bits > 32) {
98481690Sbrian      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
98581690Sbrian      return 0;
98681634Sbrian    } else {
98781634Sbrian      range->ncprange_ip4mask = bits2mask4(bits);
98881634Sbrian      range->ncprange_ip4width = bits;
98981634Sbrian    }
99081634Sbrian
99181634Sbrian    return 1;
99281634Sbrian#ifndef NOINET6
99381634Sbrian  } else if (strchr(cp + 1, ':') != NULL) {
99481634Sbrian    range->ncprange_family = AF_INET6;
99581634Sbrian
99681634Sbrian    if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) {
99781634Sbrian      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
99881634Sbrian      return 0;
99981634Sbrian    }
100081634Sbrian
100181634Sbrian    if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
100281634Sbrian      range->ncprange_ip6width = 0;
100381634Sbrian    else
100481634Sbrian      range->ncprange_ip6width = (bits == -1) ? 128 : bits;
100581634Sbrian    return 1;
100681634Sbrian#endif
100781634Sbrian  }
100881634Sbrian
100981634Sbrian  return 0;
101081634Sbrian}
1011