Commit 88a183c6 authored by Ondrej Zajicek's avatar Ondrej Zajicek
Browse files

Integrated IP functions.

parent f8fefde3
Loading
Loading
Loading
Loading
+10 −8
Original line number Diff line number Diff line
@@ -124,22 +124,24 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
}

{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
  ip4_addr a;
  if (!ip4_pton(yytext, &a))
    cf_error("Invalid IPv4 address %s", yytext);

#ifdef IPV6
  if (ipv4_pton_u32(yytext, &cf_lval.i32))
  cf_lval.i32 = ip4_to_u32(a);
  return RTRID;
  cf_error("Invalid IPv4 address %s", yytext);
#else
  if (ip_pton(yytext, &cf_lval.a))
  cf_lval.a = ipa_from_ip4(a);
  return IPA;
  cf_error("Invalid IP address %s", yytext);
#endif
}

({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
#ifdef IPV6
  if (ip_pton(yytext, &cf_lval.a))
  if (ipa_pton(yytext, &cf_lval.a))
    return IPA;
  cf_error("Invalid IP address %s", yytext);
  cf_error("Invalid IPv6 address %s", yytext);
#else
  cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported");
#endif
+1 −1
Original line number Diff line number Diff line
@@ -187,7 +187,7 @@ pxlen:
     $$ = $2;
   }
 | ':' ipa {
     $$ = ipa_mklen($2);
     $$ = ipa_masklen($2);
     if ($$ < 0) cf_error("Invalid netmask %I", $2);
   }
 ;
+0 −7
Original line number Diff line number Diff line
@@ -3,13 +3,6 @@ bitops.c
bitops.h
ip.h
ip.c
#ifdef IPV6
ipv6.c
ipv6.h
#else
ipv4.c
ipv4.h
#endif
lists.c
lists.h
md5.c
+353 −23
Original line number Diff line number Diff line
/*
 *	BIRD Library -- IP address routines common for IPv4 and IPv6
 *	BIRD Library -- IP address functions
 *
 *	(c) 1998--2000 Martin Mares <mj@ucw.cz>
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

#include "nest/bird.h"
#include "lib/ip.h"

/**
 * DOC: IP addresses
 *
@@ -18,6 +15,333 @@
 * they must be manipulated using the following functions and macros.
 */

#include <stdlib.h>

#include "nest/bird.h"
#include "lib/ip.h"


int
ip6_compare(ip6_addr a, ip6_addr b)
{
  int i;
  for (i=0; i<4; i++)
    if (a.addr[i] > b.addr[i])
      return 1;
    else if (a.addr[i] < b.addr[i])
      return -1;
  return 0;
}

ip6_addr
ip6_mkmask(uint n)
{
  ip6_addr a;
  int i;

  for (i=0; i<4; i++)
  {
    if (!n)
      a.addr[i] = 0;
    else if (n >= 32)
    {
      a.addr[i] = ~0;
      n -= 32;
    }
    else
    {
      a.addr[i] = u32_mkmask(n);
      n = 0;
    }
  }

  return a;
}

int
ip6_masklen(ip6_addr *a)
{
  int i, j, n;

  for (i=0, n=0; i<4; i++, n+=32)
    if (a->addr[i] != ~0U)
    {
      j = u32_masklen(a->addr[i]);
      if (j < 0)
	return j;
      n += j;
      while (++i < 4)
	if (a->addr[i])
	  return -1;
      break;
    }

  return n;
}

int
ip4_classify(ip4_addr ad)
{
  u32 a = _I(ad);
  u32 b = a >> 24U;

  if (b && b <= 0xdf)
  {
    if (b == 0x7f)
      return IADDR_HOST | SCOPE_HOST;
    else if ((b == 0x0a) ||
	     ((a & 0xffff0000) == 0xc0a80000) ||
	     ((a & 0xfff00000) == 0xac100000))
      return IADDR_HOST | SCOPE_SITE;
    else
      return IADDR_HOST | SCOPE_UNIVERSE;
  }

  if (b >= 0xe0 && b <= 0xef)
    return IADDR_MULTICAST | SCOPE_UNIVERSE;

  if (a == 0xffffffff)
    return IADDR_BROADCAST | SCOPE_LINK;

  return IADDR_INVALID;
}

int
ip6_classify(ip6_addr *a)
{
  u32 x = a->addr[0];

  if ((x & 0xe0000000) == 0x20000000)		/* 2000::/3  Aggregatable Global Unicast Address */
    return IADDR_HOST | SCOPE_UNIVERSE;
  if ((x & 0xffc00000) == 0xfe800000)		/* fe80::/10 Link-Local Address */
    return IADDR_HOST | SCOPE_LINK;
  if ((x & 0xffc00000) == 0xfec00000)		/* fec0::/10 Site-Local Address */
    return IADDR_HOST | SCOPE_SITE;
  if ((x & 0xfe000000) == 0xfc000000)		/* fc00::/7  Unique Local Unicast Address (RFC 4193) */
    return IADDR_HOST | SCOPE_SITE;
  if ((x & 0xff000000) == 0xff000000)		/* ff00::/8  Multicast Address */
  {
    uint scope = (x >> 16) & 0x0f;
    switch (scope)
    {
    case 1:  return IADDR_MULTICAST | SCOPE_HOST;
    case 2:  return IADDR_MULTICAST | SCOPE_LINK;
    case 5:  return IADDR_MULTICAST | SCOPE_SITE;
    case 8:  return IADDR_MULTICAST | SCOPE_ORGANIZATION;
    case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE;
    default: return IADDR_MULTICAST | SCOPE_UNDEFINED;
    }
  }

  if (!x && !a->addr[1])
  {
    u32 a2 = a->addr[2];
    u32 a3 = a->addr[3];

    if (a2 == 0 && a3 == 1)
      return IADDR_HOST | SCOPE_HOST;		/* Loopback address */
    if (a2 == 0)
      return ip4_classify(_MI4(a3));		/* IPv4 compatible addresses */
    if (a2 == 0xffff)
      return ip4_classify(_MI4(a3));		/* IPv4 mapped addresses */

    return IADDR_INVALID;
  }

  return IADDR_HOST | SCOPE_UNDEFINED;
}



/*
 *  Conversion of IPv6 address to presentation format and vice versa.
 *  Heavily inspired by routines written by Paul Vixie for the BIND project
 *  and of course by RFC 2373.
 */


char *
ip4_ntop(ip4_addr a, char *b)
{
  u32 x = _I(a);
  return b + bsprintf(b, "%d.%d.%d.%d", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff);
}


char *
ip6_ntop(ip6_addr a, char *b)
{
  u16 words[8];
  int bestpos, bestlen, curpos, curlen, i;

  /* First of all, preprocess the address and find the longest run of zeros */
  bestlen = bestpos = curpos = curlen = 0;
  for (i=0; i<8; i++)
  {
    u32 x = a.addr[i/2];
    words[i] = ((i%2) ? x : (x >> 16)) & 0xffff;
    if (words[i])
      curlen = 0;
    else
    {
      if (!curlen)
	curpos = i;
      curlen++;
      if (curlen > bestlen)
      {
	bestpos = curpos;
	bestlen = curlen;
      }
    }
  }

  if (bestlen < 2)
    bestpos = -1;

  /* Is it an encapsulated IPv4 address? */
  if (!bestpos && ((bestlen == 5 && a.addr[2] == 0xffff) || (bestlen == 6)))
  {
    u32 x = a.addr[3];
    b += bsprintf(b, "::%s%d.%d.%d.%d",
		  a.addr[2] ? "ffff:" : "",
		  (x >> 24) & 0xff,
		  (x >> 16) & 0xff,
		  (x >> 8) & 0xff,
		  x & 0xff);
    return b;
  }

  /* Normal IPv6 formatting, compress the largest sequence of zeros */
  for (i=0; i<8; i++)
  {
    if (i == bestpos)
    {
      i += bestlen - 1;
      *b++ = ':';
      if (i == 7)
	*b++ = ':';
    }
    else
    {
      if (i)
	*b++ = ':';
      b += bsprintf(b, "%x", words[i]);
    }
  }
  *b = 0;
  return b;
}

int
ip4_pton(char *a, ip4_addr *o)
{
  int i;
  unsigned long int l;
  u32 ia = 0;

  i=4;
  while (i--)
  {
    char *d, *c = strchr(a, '.');
    if (!c != !i)
      return 0;
    l = strtoul(a, &d, 10);
    if (d != c && *d || l > 255)
      return 0;
    ia = (ia << 8) | l;
    if (c)
      c++;
    a = c;
  }
  *o = ip4_from_u32(ia);
  return 1;
}

int
ip6_pton(char *a, ip6_addr *o)
{
  u16 words[8];
  int i, j, k, l, hfil;
  char *start;

  if (a[0] == ':')			/* Leading :: */
  {
    if (a[1] != ':')
      return 0;
    a++;
  }

  hfil = -1;
  i = 0;
  while (*a)
  {
    if (*a == ':')			/* :: */
    {
      if (hfil >= 0)
	return 0;

      hfil = i;
      a++;
      continue;
    }

    j = 0;
    l = 0;
    start = a;
    for (;;)
    {
      if (*a >= '0' && *a <= '9')
	k = *a++ - '0';
      else if (*a >= 'A' && *a <= 'F')
	k = *a++ - 'A' + 10;
      else if (*a >= 'a' && *a <= 'f')
	k = *a++ - 'a' + 10;
      else
	break;

      j = (j << 4) + k;
      if (j >= 0x10000 || ++l > 4)
	return 0;
    }

    if (*a == ':' && a[1])
      a++;
    else if (*a == '.' && (i == 6 || i < 6 && hfil >= 0))
    {				/* Embedded IPv4 address */
      ip4_addr x;
      if (!ip4_pton(start, &x))
	return 0;
      words[i++] = _I(x) >> 16;
      words[i++] = _I(x);
      break;
    }
    else if (*a)
      return 0;

    if (i >= 8)
      return 0;

    words[i++] = j;
  }

  /* Replace :: with an appropriate number of zeros */
  if (hfil >= 0)
  {
    j = 8 - i;
    for (i=7; i-j >= hfil; i--)
      words[i] = words[i-j];
    for (; i>=hfil; i--)
      words[i] = 0;
  }

  /* Convert the address to ip6_addr format */
  for (i=0; i<4; i++)
    o->addr[i] = (words[2*i] << 16) | words[2*i+1];

  return 1;
}


/**
 * ip_scope_text - get textual representation of address scope
 * @scope: scope (%SCOPE_xxx)
@@ -25,7 +349,7 @@
 * Returns a pointer to a textual name of the scope given.
 */
char *
ip_scope_text(unsigned scope)
ip_scope_text(uint scope)
{
  static char *scope_table[] = { "host", "link", "site", "org", "univ", "undef" };

@@ -35,6 +359,23 @@ ip_scope_text(unsigned scope)
    return scope_table[scope];
}

ip4_addr
ip4_class_mask(ip4_addr ad)
{
  u32 m, a = _I(ad);

  if (a < 0x80000000)
    m = 0xff000000;
  else if (a < 0xc0000000)
    m = 0xffff0000;
  else
    m = 0xffffff00;
  if (a & ~m)
    m = 0xffffffff;

  return _MI4(m);
}

#if 0
/**
 * ipa_equal - compare two IP addresses for equality
@@ -102,14 +443,14 @@ ip_addr ipa_not(ip_addr x) { DUMMY }
ip_addr ipa_mkmask(int x) { DUMMY }

/**
 * ipa_mkmask - calculate netmask length
 * ipa_masklen - calculate netmask length
 * @x: IP address
 *
 * This function checks whether @x represents a valid netmask and
 * returns the size of the associate network prefix or -1 for invalid
 * mask.
 */
int ipa_mklen(ip_addr x) { DUMMY }
int ipa_masklen(ip_addr x) { DUMMY }

/**
 * ipa_hash - hash IP addresses
@@ -151,8 +492,8 @@ void ipa_ntoh(ip_addr x) { DUMMY }
int ipa_classify(ip_addr x) { DUMMY }

/**
 * ipa_class_mask - guess netmask according to address class
 * @x: IP address
 * ip4_class_mask - guess netmask according to address class
 * @x: IPv4 address
 *
 * This function (available in IPv4 version only) returns a
 * network mask according to the address class of @x. Although
@@ -160,7 +501,7 @@ int ipa_classify(ip_addr x) { DUMMY }
 * routing protocols transferring no prefix lengths nor netmasks
 * and this function could be useful to them.
 */
ip_addr ipa_class_mask(ip_addr x) { DUMMY }
ip4_addr ip4_class_mask(ip4_addr x) { DUMMY }

/**
 * ipa_from_u32 - convert IPv4 address to an integer
@@ -193,7 +534,7 @@ ip_addr ipa_to_u32(u32 x) { DUMMY }
int ipa_compare(ip_addr x, ip_addr y) { DUMMY }

/**
 * ipa_build - build an IPv6 address from parts
 * ipa_build6 - build an IPv6 address from parts
 * @a1: part #1
 * @a2: part #2
 * @a3: part #3
@@ -203,18 +544,7 @@ int ipa_compare(ip_addr x, ip_addr y) { DUMMY }
 * address. It's used for example when a protocol wants to bind its
 * socket to a hard-wired multicast address.
 */
ip_addr ipa_build(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY }

/**
 * ipa_absolutize - convert link scope IPv6 address to universe scope
 * @x: link scope IPv6 address
 * @y: universe scope IPv6 prefix of the interface
 *
 * This function combines a link-scope IPv6 address @x with the universe
 * scope prefix @x of the network assigned to an interface to get a
 * universe scope form of @x.
 */
ip_addr ipa_absolutize(ip_addr x, ip_addr y) { DUMMY }
ip_addr ipa_build6(u32 a1, u32 a2, u32 a3, u32 a4) { DUMMY }

/**
 * ip_ntop - convert IP address to textual representation
+443 −28
Original line number Diff line number Diff line
@@ -9,32 +9,274 @@
#ifndef _BIRD_IP_H_
#define _BIRD_IP_H_

#ifndef IPV6
#include "ipv4.h"
#include "lib/endian.h"
#include "lib/string.h"
#include "lib/bitops.h"
#include "lib/unaligned.h"


#define IP4_OSPF_ALL_ROUTERS	ipa_build4(224, 0, 0, 5)
#define IP4_OSPF_DES_ROUTERS	ipa_build4(224, 0, 0, 6)

#define IP6_ALL_NODES		ipa_build6(0xFF020000, 0, 0, 1)
#define IP6_ALL_ROUTERS		ipa_build6(0xFF020000, 0, 0, 2)
#define IP6_OSPF_ALL_ROUTERS	ipa_build6(0xFF020000, 0, 0, 5)
#define IP6_OSPF_DES_ROUTERS	ipa_build6(0xFF020000, 0, 0, 6)
#define IP6_RIP_ROUTERS		ipa_build6(0xFF020000, 0, 0, 9)

#define IP4_NONE		_MI4(0)
#define IP6_NONE		_MI6(0,0,0,0)

#define IP4_MIN_MTU		576
#define IP6_MIN_MTU		1280

#define IP_PREC_INTERNET_CONTROL 0xc0


#ifdef IPV6
#define MAX_PREFIX_LENGTH 128
#define BITS_PER_IP_ADDRESS 128
#define STD_ADDRESS_P_LENGTH 39
#define SIZE_OF_IP_HEADER 40
#else
#include "ipv6.h"
#define MAX_PREFIX_LENGTH 32
#define BITS_PER_IP_ADDRESS 32
#define STD_ADDRESS_P_LENGTH 15
#define SIZE_OF_IP_HEADER 24
#endif


#ifdef DEBUGGING

typedef struct ip4_addr {
  u32 addr;
} ip4_addr;

#define _MI4(x) ((struct ip4_addr) { x })
#define _I(x) (x).addr

#else

typedef u32 ip4_addr;

#define _MI4(x) (x)
#define _I(x) (x)

#endif


typedef struct ip6_addr {
  u32 addr[4];
} ip6_addr;

#define _MI6(a,b,c,d) ((struct ip6_addr) {{ a, b, c, d }})
#define _I0(a) ((a).addr[0])
#define _I1(a) ((a).addr[1])
#define _I2(a) ((a).addr[2])
#define _I3(a) ((a).addr[3])


#ifdef IPV6

/* Structure ip_addr may contain both IPv4 and IPv6 addresses */
typedef ip6_addr ip_addr;
#define IPA_NONE IP6_NONE

#define ipa_from_ip4(x) _MI6(0,0,0xffff,_I(x))
#define ipa_from_ip6(x) x
#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x))

#define ipa_to_ip4(x) _MI4(_I3(x))
#define ipa_to_ip6(x) x
#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))

#define ipa_is_ip4(a) ip6_is_v4mapped(a)

#else

/* Provisionary ip_addr definition same as ip4_addr */
typedef ip4_addr ip_addr;
#define IPA_NONE IP4_NONE

#define ipa_from_ip4(x) x
#define ipa_from_ip6(x) IPA_NONE
#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x))

#define ipa_to_ip4(x) x
#define ipa_to_ip6(x) IP6_NONE
#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))

#define ipa_is_ip4(a) 1

#endif


/*
 *	Public constructors
 */

#define ip4_from_u32(x) _MI4(x)
#define ip4_to_u32(x) _I(x)

#define ip4_build(a,b,c,d) _MI4(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
#define ip6_build(a,b,c,d) _MI6(a,b,c,d)

#define ipa_build4(a,b,c,d) ipa_from_ip4(ip4_build(a,b,c,d))
#define ipa_build6(a,b,c,d) ipa_from_ip6(ip6_build(a,b,c,d))


/*
 *	Basic algebraic functions
 */

static inline int ip4_equal(ip4_addr a, ip4_addr b)
{ return _I(a) == _I(b); }

static inline int ip4_zero(ip4_addr a)
{ return _I(a) == 0; }

static inline int ip4_nonzero(ip4_addr a)
{ return _I(a) != 0; }

static inline ip4_addr ip4_and(ip4_addr a, ip4_addr b)
{ return _MI4(_I(a) & _I(b)); }

static inline ip4_addr ip4_or(ip4_addr a, ip4_addr b)
{ return _MI4(_I(a) | _I(b)); }

static inline ip4_addr ip4_xor(ip4_addr a, ip4_addr b)
{ return _MI4(_I(a) ^ _I(b)); }

static inline ip4_addr ip4_not(ip4_addr a)
{ return _MI4(~_I(a)); }


static inline int ip6_equal(ip6_addr a, ip6_addr b)
{ return _I0(a) == _I0(b) && _I1(a) == _I1(b) && _I2(a) == _I2(b) && _I3(a) == _I3(b); }

static inline int ip6_zero(ip6_addr a)
{ return  !_I0(a) && !_I1(a) && !_I2(a) && !_I3(a); }

static inline int ip6_nonzero(ip6_addr a)
{ return _I0(a) || _I1(a) || _I2(a) || _I3(a); }

static inline ip6_addr ip6_and(ip6_addr a, ip6_addr b)
{ return _MI6(_I0(a) & _I0(b), _I1(a) & _I1(b), _I2(a) & _I2(b), _I3(a) & _I3(b)); }

static inline ip6_addr ip6_or(ip6_addr a, ip6_addr b)
{ return _MI6(_I0(a) | _I0(b), _I1(a) | _I1(b), _I2(a) | _I2(b), _I3(a) | _I3(b)); }

static inline ip6_addr ip6_xor(ip6_addr a, ip6_addr b)
{ return _MI6(_I0(a) ^ _I0(b), _I1(a) ^ _I1(b), _I2(a) ^ _I2(b), _I3(a) ^ _I3(b)); }

static inline ip6_addr ip6_not(ip6_addr a)
{ return _MI6(~_I0(a), ~_I1(a), ~_I2(a), ~_I3(a)); }


#ifdef IPV6
#define ipa_equal(x,y) ip6_equal(x,y)
#define ipa_zero(x) ip6_zero(x)
#define ipa_nonzero(x) ip6_nonzero(x)
#define ipa_and(x,y) ip6_and(x,y)
#define ipa_or(x,y) ip6_or(x,y)
#define ipa_xor(x,y) ip6_xor(x,y)
#define ipa_not(x) ip6_not(x)
#else
#define ipa_equal(x,y) ip4_equal(x,y)
#define ipa_zero(x) ip4_zero(x)
#define ipa_nonzero(x) ip4_nonzero(x)
#define ipa_and(x,y) ip4_and(x,y)
#define ipa_or(x,y) ip4_or(x,y)
#define ipa_xor(x,y) ip4_xor(x,y)
#define ipa_not(x) ip4_not(x)
#endif



#ifdef IPV6
/*
 * A zero address is either a token for invalid/unused, or the prefix of default
 * routes. These functions should be used in the second case, where both IPv4
 * and IPv6 zero addresses should be checked.
 */

static inline int ipa_zero2(ip_addr a)
{ return  !_I0(a) && !_I1(a) && ((_I2(a) == 0) || (_I2(a) == 0xffff)) && !_I3(a); }

static inline int ipa_nonzero2(ip_addr a)
{ return _I0(a) || _I1(a) || ((_I2(a) != 0) && (_I2(a) != 0xffff)) || _I3(a); }

#else
#define ipa_zero2(x) ip4_zero(x)
#define ipa_nonzero2(x) ip4_nonzero(x)
#endif


/*
 *	Hash and compare functions
 */

static inline uint ip4_hash(ip4_addr a)
{
  /* Returns a 16-bit value */
  u32 x = _I(a);
  x ^= x >> 16;
  x ^= x << 10;
  return x & 0xffff;
}

static inline u32 ip4_hash32(ip4_addr a)
{
  /* Returns a 32-bit value, although low-order bits are not mixed */
  u32 x = _I(a);
  x ^= x << 16;
  x ^= x << 12;
  return x;
}

static inline uint ip6_hash(ip6_addr a)
{
  /* Returns a 16-bit hash key */
  u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a);
  return (x ^ (x >> 16) ^ (x >> 8)) & 0xffff;
}

static inline u32 ip6_hash32(ip6_addr a)
{
  /* Returns a 32-bit hash key, although low-order bits are not mixed */
  u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a);
  return x ^ (x << 16) ^ (x << 24);
}

static inline int ip4_compare(ip4_addr a, ip4_addr b)
{ return (_I(a) > _I(b)) - (_I(a) < _I(b)); }

int ip6_compare(ip6_addr a, ip6_addr b);


#ifdef IPV6
#define ipa_hash(x) ip6_hash(x)
#define ipa_hash32(x) ip6_hash32(x)
#define ipa_compare(x,y) ip6_compare(x,y)
#else
#define ipa_hash(x) ip4_hash(x)
#define ipa_hash32(x) ip4_hash32(x)
#define ipa_compare(x,y) ip4_compare(x,y)
#endif

#define ipa_zero(x) (!ipa_nonzero(x))
#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l)))))
#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p))))
#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2)))))

/*
 *	ip_classify() returns either a negative number for invalid addresses
 *	or scope OR'ed together with address type.
 *	IP address classification
 */

/* Address class */
#define IADDR_INVALID		-1
#define IADDR_SCOPE_MASK       	0xfff
#define IADDR_HOST		0x1000
#define IADDR_BROADCAST		0x2000
#define IADDR_MULTICAST		0x4000

/*
 *	Address scope
 */

/* Address scope */
#define SCOPE_HOST		0
#define SCOPE_LINK		1
#define SCOPE_SITE		2
@@ -42,26 +284,199 @@
#define SCOPE_UNIVERSE		4
#define SCOPE_UNDEFINED		5

char *ip_scope_text(unsigned);
int ip4_classify(ip4_addr ad);
int ip6_classify(ip6_addr *a);

static inline int ip6_is_link_local(ip6_addr a)
{ return (_I0(a) & 0xffc00000) == 0xfe800000; }

static inline int ip6_is_v4mapped(ip6_addr a)
{ return _I0(a) == 0 && _I1(a) == 0 && _I2(a) == 0xffff; }

#ifdef IPV6
#define ipa_classify(x) ip6_classify(&(x))
#define ipa_is_link_local(x) ip6_is_link_local(x)
#else
#define ipa_classify(x) ip4_classify(x)
#define ipa_is_link_local(x) 0
#endif

static inline int ipa_classify_net(ip_addr a)
{ return ipa_zero2(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); }


/*
 *	Network prefixes
 *	Miscellaneous IP prefix manipulation
 */

struct prefix {
  ip_addr addr;
  unsigned int len;
};
static inline ip4_addr ip4_mkmask(uint n)
{ return _MI4(u32_mkmask(n)); }

static inline int ip4_masklen(ip4_addr a)
{ return u32_masklen(_I(a)); }

ip6_addr ip6_mkmask(uint n);
int ip6_masklen(ip6_addr *a);

/* ipX_pxlen() requires that x != y */
static inline uint ip4_pxlen(ip4_addr a, ip4_addr b)
{ return 31 - u32_log2(_I(a) ^ _I(b)); }

static inline uint ip6_pxlen(ip6_addr a, ip6_addr b)
{
  int i = 0;
  i += (a.addr[i] == b.addr[i]);
  i += (a.addr[i] == b.addr[i]);
  i += (a.addr[i] == b.addr[i]);
  i += (a.addr[i] == b.addr[i]);
  return 32 * i + 31 - u32_log2(a.addr[i] ^ b.addr[i]);
}

static inline u32 ip4_getbit(ip4_addr a, uint pos)
{ return _I(a) & (0x80000000 >> pos); }

static inline u32 ip6_getbit(ip6_addr a, uint pos)
{ return a.addr[pos / 32] & (0x80000000 >> (pos % 32)); }

static inline ip4_addr ip4_opposite_m1(ip4_addr a)
{ return _MI4(_I(a) ^ 1); }

static inline ip4_addr ip4_opposite_m2(ip4_addr a)
{ return _MI4(_I(a) ^ 3); }

static inline ip6_addr ip6_opposite_m1(ip6_addr a)
{ return _MI6(_I0(a), _I1(a), _I2(a), _I3(a) ^ 1); }

static inline ip6_addr ip6_opposite_m2(ip6_addr a)
{ return _MI6(_I0(a), _I1(a), _I2(a), _I3(a) ^ 3); }

ip4_addr ip4_class_mask(ip4_addr ad);

#ifdef IPV6
#define ipa_mkmask(x) ip6_mkmask(x)
#define ipa_masklen(x) ip6_masklen(&x)
#define ipa_pxlen(x,y) ip6_pxlen(x,y)
#define ipa_getbit(x,n) ip6_getbit(x,n)
#define ipa_opposite_m1(x) ip6_opposite_m1(x)
#define ipa_opposite_m2(x) ip6_opposite_m2(x)
#else
#define ipa_mkmask(x) ip4_mkmask(x)
#define ipa_masklen(x) ip4_masklen(x)
#define ipa_pxlen(x,y) ip4_pxlen(x,y)
#define ipa_getbit(x,n) ip4_getbit(x,n)
#define ipa_opposite_m1(x) ip4_opposite_m1(x)
#define ipa_opposite_m2(x) ip4_opposite_m2(x)
#endif


/*
 *	Host/network order conversions
 */

static inline ip4_addr ip4_hton(ip4_addr a)
{ return _MI4(htonl(_I(a))); }

static inline ip4_addr ip4_ntoh(ip4_addr a)
{ return _MI4(ntohl(_I(a))); }

static inline ip6_addr ip6_hton(ip6_addr a)
{ return _MI6(htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a))); }

static inline ip6_addr ip6_ntoh(ip6_addr a)
{ return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); }

#ifdef IPV6
#define ipa_hton(x) x = ip6_hton(x)
#define ipa_ntoh(x) x = ip6_ntoh(x)
#else
#define ipa_hton(x) x = ip4_hton(x)
#define ipa_ntoh(x) x = ip4_ntoh(x)
#endif


/*
 *	Unaligned data access (in network order)
 */

static inline ip4_addr get_ip4(void *buf)
{
  return _MI4(get_u32(buf));
}

static inline ip6_addr get_ip6(void *buf)
{
  ip6_addr a;
  memcpy(&a, buf, 16);
  return ip6_ntoh(a);
}

static inline void * put_ip4(void *buf, ip4_addr a)
{
  put_u32(buf, _I(a));
  return buf+4;
}

static inline void * put_ip6(void *buf, ip6_addr a)
{
  a = ip6_hton(a);
  memcpy(buf, &a, 16);
  return buf+16;
}

// XXXX these functions must be redesigned or removed
#ifdef IPV6
#define get_ipa(x) get_ip6(x)
#define put_ipa(x,y) put_ip6(x,y)
#else
#define get_ipa(x) get_ip4(x)
#define put_ipa(x,y) put_ip4(x,y)
#endif


/*
 *	Binary/text form conversions
 */

char *ip4_ntop(ip4_addr a, char *b);
char *ip6_ntop(ip6_addr a, char *b);

static inline char * ip4_ntox(ip4_addr a, char *b)
{ return b + bsprintf(b, "%08x", _I(a)); }

static inline char * ip6_ntox(ip6_addr a, char *b)
{ return b + bsprintf(b, "%08x.%08x.%08x.%08x", _I0(a), _I1(a), _I2(a), _I3(a)); }

int ip4_pton(char *a, ip4_addr *o);
int ip6_pton(char *a, ip6_addr *o);

// XXXX these functions must be redesigned or removed
#ifdef IPV6
#define ipa_ntop(x,y) ip6_ntop(x,y)
#define ipa_ntox(x,y) ip6_ntox(x,y)
#define ipa_pton(x,y) ip6_pton(x,y)
#else
#define ipa_ntop(x,y) ip4_ntop(x,y)
#define ipa_ntox(x,y) ip4_ntox(x,y)
#define ipa_pton(x,y) ip4_pton(x,y)
#endif

static inline int ipa_classify_net(ip_addr a)
{ return ipa_zero(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); }

/*
 *	Conversions between internal and string representation
 *	Miscellaneous
 */

char *ip_ntop(ip_addr a, char *);
char *ip_ntox(ip_addr a, char *);
int ip_pton(char *a, ip_addr *o);
// XXXX review this

#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l)))))
#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p))))
#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2)))))

char *ip_scope_text(unsigned);

struct prefix {
  ip_addr addr;
  unsigned int len;
};


#endif
Loading