aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils')
-rw-r--r--src/backend/utils/adt/Makefile5
-rw-r--r--src/backend/utils/adt/inet_net_ntop.c137
-rw-r--r--src/backend/utils/adt/inet_net_pton.c217
-rw-r--r--src/backend/utils/adt/ip.c283
-rw-r--r--src/backend/utils/adt/mac.c323
5 files changed, 963 insertions, 2 deletions
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index d9812a52367..686a2d0e8ca 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -4,7 +4,7 @@
# Makefile for utils/adt
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/backend/utils/adt/Makefile,v 1.17 1998/08/24 01:38:04 momjian Exp $
+# $Header: /cvsroot/pgsql/src/backend/utils/adt/Makefile,v 1.18 1998/10/03 05:40:47 momjian Exp $
#
#-------------------------------------------------------------------------
@@ -23,7 +23,8 @@ OBJS = acl.o arrayfuncs.o arrayutils.o bool.o cash.o char.o chunk.o \
misc.o nabstime.o name.o not_in.o numutils.o \
oid.o oracle_compat.o \
regexp.o regproc.o ruleutils.o selfuncs.o sets.o \
- tid.o timestamp.o varchar.o varlena.o version.o
+ tid.o timestamp.o varchar.o varlena.o version.o \
+ ip.o mac.o inet_net_ntop.o inet_net_pton.o
all: SUBSYS.o
diff --git a/src/backend/utils/adt/inet_net_ntop.c b/src/backend/utils/adt/inet_net_ntop.c
new file mode 100644
index 00000000000..655f8ba62e6
--- /dev/null
+++ b/src/backend/utils/adt/inet_net_ntop.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.1 1998/10/03 05:40:48 momjian Exp $";
+
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef SPRINTF_CHAR
+#define SPRINTF(x) strlen(sprintf/**/x)
+#else
+#define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static char *inet_net_ntop_ipv4(const u_char *src, int bits,
+ char *dst, size_t size);
+
+/*
+ * char *
+ * inet_net_ntop(af, src, bits, dst, size)
+ * convert network number from network to presentation format.
+ * generates CIDR style result always.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+char *
+inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
+{
+ switch (af)
+ {
+ case AF_INET:
+ return (inet_net_ntop_ipv4(src, bits, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+}
+
+/*
+ * static char *
+ * inet_net_ntop_ipv4(src, bits, dst, size)
+ * convert IPv4 network number from network to presentation format.
+ * generates CIDR style result always.
+ * return:
+ * pointer to dst, or NULL if an error occurred (check errno).
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0x11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), July 1996
+ */
+static char *
+inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
+{
+ char *odst = dst;
+ char *t;
+ u_int m;
+ int b;
+
+ if (bits < 0 || bits > 32)
+ {
+ errno = EINVAL;
+ return (NULL);
+ }
+ if (bits == 0)
+ {
+ if (size < sizeof "0")
+ goto emsgsize;
+ *dst++ = '0';
+ *dst = '\0';
+ }
+
+ /* Format whole octets. */
+ for (b = bits / 8; b > 0; b--)
+ {
+ if (size < sizeof "255.")
+ goto emsgsize;
+ t = dst;
+ dst += SPRINTF((dst, "%u", *src++));
+ if (b > 1)
+ {
+ *dst++ = '.';
+ *dst = '\0';
+ }
+ size -= (size_t) (dst - t);
+ }
+
+ /* Format partial octet. */
+ b = bits % 8;
+ if (b > 0)
+ {
+ if (size < sizeof ".255")
+ goto emsgsize;
+ t = dst;
+ if (dst != odst)
+ *dst++ = '.';
+ m = ((1 << b) - 1) << (8 - b);
+ dst += SPRINTF((dst, "%u", *src & m));
+ size -= (size_t) (dst - t);
+ }
+
+ /* Format CIDR /width. */
+ if (size < sizeof "/32")
+ goto emsgsize;
+ dst += SPRINTF((dst, "/%u", bits));
+ return (odst);
+
+emsgsize:
+ errno = EMSGSIZE;
+ return (NULL);
+}
diff --git a/src/backend/utils/adt/inet_net_pton.c b/src/backend/utils/adt/inet_net_pton.c
new file mode 100644
index 00000000000..8b3ae41127f
--- /dev/null
+++ b/src/backend/utils/adt/inet_net_pton.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: inet_net_pton.c,v 1.1 1998/10/03 05:40:49 momjian Exp $";
+
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef SPRINTF_CHAR
+#define SPRINTF(x) strlen(sprintf/**/x)
+#else
+#define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+static int inet_net_pton_ipv4(const char *src, u_char *dst, size_t size);
+
+/*
+ * static int
+ * inet_net_pton(af, src, dst, size)
+ * convert network number from presentation to network format.
+ * accepts hex octets, hex strings, decimal octets, and /CIDR.
+ * "size" is in bytes and describes "dst".
+ * return:
+ * number of bits, either imputed classfully or specified with /CIDR,
+ * or -1 if some failure occurred (check errno). ENOENT means it was
+ * not a valid network specification.
+ * author:
+ * Paul Vixie (ISC), June 1996
+ */
+int
+inet_net_pton(int af, const char *src, void *dst, size_t size)
+{
+ switch (af)
+ {
+ case AF_INET:
+ return (inet_net_pton_ipv4(src, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+/*
+ * static int
+ * inet_net_pton_ipv4(src, dst, size)
+ * convert IPv4 network number from presentation to network format.
+ * accepts hex octets, hex strings, decimal octets, and /CIDR.
+ * "size" is in bytes and describes "dst".
+ * return:
+ * number of bits, either imputed classfully or specified with /CIDR,
+ * or -1 if some failure occurred (check errno). ENOENT means it was
+ * not an IPv4 network specification.
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0x11110000 in its fourth octet.
+ * author:
+ * Paul Vixie (ISC), June 1996
+ */
+static int
+inet_net_pton_ipv4(const char *src, u_char *dst, size_t size)
+{
+ static const char
+ xdigits[] = "0123456789abcdef",
+ digits[] = "0123456789";
+ int n,
+ ch,
+ tmp,
+ dirty,
+ bits;
+ const u_char *odst = dst;
+
+ ch = *src++;
+ if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
+ && isascii(src[1]) && isxdigit(src[1]))
+ {
+ /* Hexadecimal: Eat nybble string. */
+ if (size <= 0)
+ goto emsgsize;
+ *dst = 0, dirty = 0;
+ src++; /* skip x or X. */
+ while ((ch = *src++) != '\0' &&
+ isascii(ch) && isxdigit(ch))
+ {
+ if (isupper(ch))
+ ch = tolower(ch);
+ n = strchr(xdigits, ch) - xdigits;
+ assert(n >= 0 && n <= 15);
+ *dst |= n;
+ if (!dirty++)
+ *dst <<= 4;
+ else if (size-- > 0)
+ *++dst = 0, dirty = 0;
+ else
+ goto emsgsize;
+ }
+ if (dirty)
+ size--;
+ }
+ else if (isascii(ch) && isdigit(ch))
+ {
+ /* Decimal: eat dotted digit string. */
+ for (;;)
+ {
+ tmp = 0;
+ do
+ {
+ n = strchr(digits, ch) - digits;
+ assert(n >= 0 && n <= 9);
+ tmp *= 10;
+ tmp += n;
+ if (tmp > 255)
+ goto enoent;
+ } while ((ch = *src++) != '\0' &&
+ isascii(ch) && isdigit(ch));
+ if (size-- <= 0)
+ goto emsgsize;
+ *dst++ = (u_char) tmp;
+ if (ch == '\0' || ch == '/')
+ break;
+ if (ch != '.')
+ goto enoent;
+ ch = *src++;
+ if (!isascii(ch) || !isdigit(ch))
+ goto enoent;
+ }
+ }
+ else
+ goto enoent;
+
+ bits = -1;
+ if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst)
+ {
+ /* CIDR width specifier. Nothing can follow it. */
+ ch = *src++; /* Skip over the /. */
+ bits = 0;
+ do
+ {
+ n = strchr(digits, ch) - digits;
+ assert(n >= 0 && n <= 9);
+ bits *= 10;
+ bits += n;
+ } while ((ch = *src++) != '\0' &&
+ isascii(ch) && isdigit(ch));
+ if (ch != '\0')
+ goto enoent;
+ if (bits > 32)
+ goto emsgsize;
+ }
+
+ /* Firey death and destruction unless we prefetched EOS. */
+ if (ch != '\0')
+ goto enoent;
+
+ /* If nothing was written to the destination, we found no address. */
+ if (dst == odst)
+ goto enoent;
+ /* If no CIDR spec was given, infer width from net class. */
+ if (bits == -1)
+ {
+ if (*odst >= 240) /* Class E */
+ bits = 32;
+ else if (*odst >= 224) /* Class D */
+ bits = 4;
+ else if (*odst >= 192) /* Class C */
+ bits = 24;
+ else if (*odst >= 128) /* Class B */
+ bits = 16;
+ else
+/* Class A */
+ bits = 8;
+ /* If imputed mask is narrower than specified octets, widen. */
+ if (bits >= 8 && bits < ((dst - odst) * 8))
+ bits = (dst - odst) * 8;
+ }
+ /* Extend network to cover the actual mask. */
+ while (bits > ((dst - odst) * 8))
+ {
+ if (size-- <= 0)
+ goto emsgsize;
+ *dst++ = '\0';
+ }
+ return (bits);
+
+enoent:
+ errno = ENOENT;
+ return (-1);
+
+emsgsize:
+ errno = EMSGSIZE;
+ return (-1);
+}
diff --git a/src/backend/utils/adt/ip.c b/src/backend/utils/adt/ip.c
new file mode 100644
index 00000000000..b29339694b9
--- /dev/null
+++ b/src/backend/utils/adt/ip.c
@@ -0,0 +1,283 @@
+/*
+ * PostgreSQL type definitions for IP addresses. This
+ * is for IP V4 CIDR notation, but prepared for V6: just
+ * add the necessary bits where the comments indicate.
+ *
+ * $Id: ip.c,v 1.1 1998/10/03 05:40:49 momjian Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <postgres.h>
+#include <utils/palloc.h>
+#include <utils/mac.h>
+
+/*
+ * Access macros. Add IPV6 support.
+ */
+
+#define ip_addrsize(ipaddrptr) \
+ (((ipaddr_struct *)VARDATA(ipaddrptr))->family == AF_INET ? 4 : -1)
+
+#define ip_family(ipaddrptr) \
+ (((ipaddr_struct *)VARDATA(ipaddrptr))->family)
+
+#define ip_bits(ipaddrptr) \
+ (((ipaddr_struct *)VARDATA(ipaddrptr))->bits)
+
+#define ip_v4addr(ipaddrptr) \
+ (((ipaddr_struct *)VARDATA(ipaddrptr))->addr.ipv4_addr)
+
+/*
+ * IP address reader.
+ */
+
+ipaddr *
+ipaddr_in(char *src)
+{
+ int bits;
+ ipaddr *dst;
+
+ dst = palloc(VARHDRSZ + sizeof(ipaddr_struct));
+ if (dst == NULL)
+ {
+ elog(ERROR, "unable to allocate memory in ipaddr_in()");
+ return (NULL);
+ }
+ /* First, try for an IP V4 address: */
+ ip_family(dst) = AF_INET;
+ bits = inet_net_pton(ip_family(dst), src, &ip_v4addr(dst), ip_addrsize(dst));
+ if ((bits < 0) || (bits > 32))
+ {
+ /* Go for an IPV6 address here, before faulting out: */
+ elog(ERROR, "could not parse \"%s\"", src);
+ pfree(dst);
+ return (NULL);
+ }
+ VARSIZE(dst) = VARHDRSZ
+ + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst))
+ + ip_addrsize(dst);
+ ip_bits(dst) = bits;
+ return (dst);
+}
+
+/*
+ * IP address output function.
+ */
+
+char *
+ipaddr_out(ipaddr *src)
+{
+ char *dst,
+ tmp[sizeof("255.255.255.255/32")];
+
+ if (ip_family(src) == AF_INET)
+ {
+ /* It's an IP V4 address: */
+ if (inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
+ tmp, sizeof(tmp)) < 0)
+ {
+ elog(ERROR, "unable to print address (%s)", strerror(errno));
+ return (NULL);
+ }
+ }
+ else
+ {
+ /* Go for an IPV6 address here, before faulting out: */
+ elog(ERROR, "unknown address family (%d)", ip_family(src));
+ return (NULL);
+ }
+ dst = palloc(strlen(tmp) + 1);
+ if (dst == NULL)
+ {
+ elog(ERROR, "unable to allocate memory in ipaddr_out()");
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/*
+ * Boolean tests for magnitude. Add V4/V6 testing!
+ */
+
+bool
+ipaddr_lt(ipaddr *a1, ipaddr *a2)
+{
+ if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
+ {
+ int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
+
+ return ((order < 0) || ((order == 0) && (ip_bits(a1) < ip_bits(a2))));
+ }
+ else
+ {
+ /* Go for an IPV6 address here, before faulting out: */
+ elog(ERROR, "cannot compare address families %d and %d",
+ ip_family(a1), ip_family(a2));
+ return (FALSE);
+ }
+}
+
+bool
+ipaddr_le(ipaddr *a1, ipaddr *a2)
+{
+ return (ipaddr_lt(a1, a2) || ipaddr_eq(a1, a2));
+}
+
+bool
+ipaddr_eq(ipaddr *a1, ipaddr *a2)
+{
+ if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
+ {
+ return ((ip_bits(a1) == ip_bits(a2))
+ && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
+ }
+ else
+ {
+ /* Go for an IPV6 address here, before faulting out: */
+ elog(ERROR, "cannot compare address families %d and %d",
+ ip_family(a1), ip_family(a2));
+ return (FALSE);
+ }
+}
+
+bool
+ipaddr_ge(ipaddr *a1, ipaddr *a2)
+{
+ return (ipaddr_gt(a1, a2) || ipaddr_eq(a1, a2));
+}
+
+bool
+ipaddr_gt(ipaddr *a1, ipaddr *a2)
+{
+ if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
+ {
+ int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
+
+ return ((order > 0) || ((order == 0) && (ip_bits(a1) > ip_bits(a2))));
+ }
+ else
+ {
+ /* Go for an IPV6 address here, before faulting out: */
+ elog(ERROR, "cannot compare address families %d and %d",
+ ip_family(a1), ip_family(a2));
+ return (FALSE);
+ }
+}
+
+bool
+ipaddr_ne(ipaddr *a1, ipaddr *a2)
+{
+ return (!ipaddr_eq(a1, a2));
+}
+
+bool
+ipaddr_sub(ipaddr *a1, ipaddr *a2)
+{
+ if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
+ {
+ return ((ip_bits(a1) > ip_bits(a2))
+ && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
+ }
+ else
+ {
+ /* Go for an IPV6 address here, before faulting out: */
+ elog(ERROR, "cannot compare address families %d and %d",
+ ip_family(a1), ip_family(a2));
+ return (FALSE);
+ }
+}
+
+bool
+ipaddr_subeq(ipaddr *a1, ipaddr *a2)
+{
+ if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
+ {
+ return ((ip_bits(a1) >= ip_bits(a2))
+ && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
+ }
+ else
+ {
+ /* Go for an IPV6 address here, before faulting out: */
+ elog(ERROR, "cannot compare address families %d and %d",
+ ip_family(a1), ip_family(a2));
+ return (FALSE);
+ }
+}
+
+bool
+ipaddr_sup(ipaddr *a1, ipaddr *a2)
+{
+ if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
+ {
+ return ((ip_bits(a1) < ip_bits(a2))
+ && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
+ }
+ else
+ {
+ /* Go for an IPV6 address here, before faulting out: */
+ elog(ERROR, "cannot compare address families %d and %d",
+ ip_family(a1), ip_family(a2));
+ return (FALSE);
+ }
+}
+
+bool
+ipaddr_supeq(ipaddr *a1, ipaddr *a2)
+{
+ if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
+ {
+ return ((ip_bits(a1) <= ip_bits(a2))
+ && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
+ }
+ else
+ {
+ /* Go for an IPV6 address here, before faulting out: */
+ elog(ERROR, "cannot compare address families %d and %d",
+ ip_family(a1), ip_family(a2));
+ return (FALSE);
+ }
+}
+
+/*
+ * Comparison function for sorting. Add V4/V6 testing!
+ */
+
+int4
+ipaddr_cmp(ipaddr *a1, ipaddr *a2)
+{
+ if (ntohl(ip_v4addr(a1)) < ntohl(ip_v4addr(a2)))
+ return (-1);
+ else if (ntohl(ip_v4addr(a1)) > ntohl(ip_v4addr(a2)))
+ return (1);
+ return 0;
+}
+
+/*
+ * Bitwise comparison for V4 addresses. Add V6 implementation!
+ */
+
+int
+v4bitncmp(u_int32_t a1, u_int32_t a2, int bits)
+{
+ unsigned long mask = 0;
+ int i;
+
+ for (i = 0; i < bits; i++)
+ mask = (mask >> 1) | 0x80000000;
+ a1 = ntohl(a1);
+ a2 = ntohl(a2);
+ if ((a1 & mask) < (a2 & mask))
+ return (-1);
+ else if ((a1 & mask) > (a2 & mask))
+ return (1);
+ return (0);
+}
diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c
new file mode 100644
index 00000000000..8d09ea16c6e
--- /dev/null
+++ b/src/backend/utils/adt/mac.c
@@ -0,0 +1,323 @@
+/*
+ * PostgreSQL type definitions for MAC addresses.
+ *
+ * $Id: mac.c,v 1.1 1998/10/03 05:40:50 momjian Exp $
+ */
+
+#include <stdio.h>
+
+#include <postgres.h>
+#include <utils/palloc.h>
+
+#include <utils/mac.h>
+
+manufacturer manufacturers[] = {
+ {0x00, 0x00, 0x0C, "Cisco"},
+ {0x00, 0x00, 0x0E, "Fujitsu"},
+ {0x00, 0x00, 0x0F, "NeXT"},
+ {0x00, 0x00, 0x10, "Sytek"},
+ {0x00, 0x00, 0x1D, "Cabletron"},
+ {0x00, 0x00, 0x20, "DIAB"},
+ {0x00, 0x00, 0x22, "Visual Technology"},
+ {0x00, 0x00, 0x2A, "TRW"},
+ {0x00, 0x00, 0x32, "GPT Limited"},
+ {0x00, 0x00, 0x5A, "S & Koch"},
+ {0x00, 0x00, 0x5E, "IANA"},
+ {0x00, 0x00, 0x65, "Network General"},
+ {0x00, 0x00, 0x6B, "MIPS"},
+ {0x00, 0x00, 0x77, "MIPS"},
+ {0x00, 0x00, 0x7A, "Ardent"},
+ {0x00, 0x00, 0x89, "Cayman Systems"},
+ {0x00, 0x00, 0x93, "Proteon"},
+ {0x00, 0x00, 0x9F, "Ameristar Technology"},
+ {0x00, 0x00, 0xA2, "Wellfleet"},
+ {0x00, 0x00, 0xA3, "Network Application Technology"},
+ {0x00, 0x00, 0xA6, "Network General"},
+ {0x00, 0x00, 0xA7, "NCD"},
+ {0x00, 0x00, 0xA9, "Network Systems"},
+ {0x00, 0x00, 0xAA, "Xerox"},
+ {0x00, 0x00, 0xB3, "CIMLinc"},
+ {0x00, 0x00, 0xB7, "Dove Fastnet"},
+ {0x00, 0x00, 0xBC, "Allen-Bradley"},
+ {0x00, 0x00, 0xC0, "Western Digital"},
+ {0x00, 0x00, 0xC5, "Farallon"},
+ {0x00, 0x00, 0xC6, "Hewlett-Packard"},
+ {0x00, 0x00, 0xC8, "Altos"},
+ {0x00, 0x00, 0xC9, "Emulex"},
+ {0x00, 0x00, 0xD7, "Dartmouth College"},
+ {0x00, 0x00, 0xD8, "3Com (?)"},
+ {0x00, 0x00, 0xDD, "Gould"},
+ {0x00, 0x00, 0xDE, "Unigraph"},
+ {0x00, 0x00, 0xE2, "Acer Counterpoint"},
+ {0x00, 0x00, 0xEF, "Alantec"},
+ {0x00, 0x00, 0xFD, "High Level Hardware"},
+ {0x00, 0x01, 0x02, "BBN internal usage"},
+ {0x00, 0x20, 0xAF, "3Com"},
+ {0x00, 0x17, 0x00, "Kabel"},
+ {0x00, 0x80, 0x64, "Wyse Technology"},
+ {0x00, 0x80, 0x2B, "IMAC (?)"},
+ {0x00, 0x80, 0x2D, "Xylogics, Inc."},
+ {0x00, 0x80, 0x8C, "Frontier Software Development"},
+ {0x00, 0x80, 0xC2, "IEEE 802.1 Committee"},
+ {0x00, 0x80, 0xD3, "Shiva"},
+ {0x00, 0xAA, 0x00, "Intel"},
+ {0x00, 0xDD, 0x00, "Ungermann-Bass"},
+ {0x00, 0xDD, 0x01, "Ungermann-Bass"},
+ {0x02, 0x07, 0x01, "Racal InterLan"},
+ {0x02, 0x04, 0x06, "BBN internal usage"},
+ {0x02, 0x60, 0x86, "Satelcom MegaPac"},
+ {0x02, 0x60, 0x8C, "3Com"},
+ {0x02, 0xCF, 0x1F, "CMC"},
+ {0x08, 0x00, 0x02, "3Com"},
+ {0x08, 0x00, 0x03, "ACC"},
+ {0x08, 0x00, 0x05, "Symbolics"},
+ {0x08, 0x00, 0x08, "BBN"},
+ {0x08, 0x00, 0x09, "Hewlett-Packard"},
+ {0x08, 0x00, 0x0A, "Nestar Systems"},
+ {0x08, 0x00, 0x0B, "Unisys"},
+ {0x08, 0x00, 0x11, "Tektronix"},
+ {0x08, 0x00, 0x14, "Excelan"},
+ {0x08, 0x00, 0x17, "NSC"},
+ {0x08, 0x00, 0x1A, "Data General"},
+ {0x08, 0x00, 0x1B, "Data General"},
+ {0x08, 0x00, 0x1E, "Apollo"},
+ {0x08, 0x00, 0x20, "Sun"},
+ {0x08, 0x00, 0x22, "NBI"},
+ {0x08, 0x00, 0x25, "CDC"},
+ {0x08, 0x00, 0x26, "Norsk Data"},
+ {0x08, 0x00, 0x27, "PCS Computer Systems GmbH"},
+ {0x08, 0x00, 0x28, "Texas Instruments"},
+ {0x08, 0x00, 0x2B, "DEC"},
+ {0x08, 0x00, 0x2E, "Metaphor"},
+ {0x08, 0x00, 0x2F, "Prime Computer"},
+ {0x08, 0x00, 0x36, "Intergraph"},
+ {0x08, 0x00, 0x37, "Fujitsu-Xerox"},
+ {0x08, 0x00, 0x38, "Bull"},
+ {0x08, 0x00, 0x39, "Spider Systems"},
+ {0x08, 0x00, 0x41, "DCA Digital Comm. Assoc."},
+ {0x08, 0x00, 0x45, "Xylogics (?)"},
+ {0x08, 0x00, 0x46, "Sony"},
+ {0x08, 0x00, 0x47, "Sequent"},
+ {0x08, 0x00, 0x49, "Univation"},
+ {0x08, 0x00, 0x4C, "Encore"},
+ {0x08, 0x00, 0x4E, "BICC"},
+ {0x08, 0x00, 0x56, "Stanford University"},
+ {0x08, 0x00, 0x58, "DECsystem 20 (?)"},
+ {0x08, 0x00, 0x5A, "IBM"},
+ {0x08, 0x00, 0x67, "Comdesign"},
+ {0x08, 0x00, 0x68, "Ridge"},
+ {0x08, 0x00, 0x69, "Silicon Graphics"},
+ {0x08, 0x00, 0x6E, "Concurrent"},
+ {0x08, 0x00, 0x75, "DDE"},
+ {0x08, 0x00, 0x7C, "Vitalink"},
+ {0x08, 0x00, 0x80, "XIOS"},
+ {0x08, 0x00, 0x86, "Imagen/QMS"},
+ {0x08, 0x00, 0x87, "Xyplex"},
+ {0x08, 0x00, 0x89, "Kinetics"},
+ {0x08, 0x00, 0x8B, "Pyramid"},
+ {0x08, 0x00, 0x8D, "XyVision"},
+ {0x08, 0x00, 0x90, "Retix Inc"},
+ {0x48, 0x44, 0x53, "HDS (?)"},
+ {0x80, 0x00, 0x10, "AT&T"},
+ {0xAA, 0x00, 0x00, "DEC"},
+ {0xAA, 0x00, 0x01, "DEC"},
+ {0xAA, 0x00, 0x02, "DEC"},
+ {0xAA, 0x00, 0x03, "DEC"},
+ {0xAA, 0x00, 0x04, "DEC"},
+ {0x00, 0x00, 0x00, NULL}
+};
+
+/*
+ * Utility macros used for sorting and comparing:
+ */
+
+#define hibits(addr) \
+ ((unsigned long)((addr->a<<16)|(addr->b<<8)|(addr->c)))
+
+#define lobits(addr) \
+ ((unsigned long)((addr->c<<16)|(addr->e<<8)|(addr->f)))
+
+/*
+ * MAC address reader. Accepts several common notations.
+ */
+
+macaddr *
+macaddr_in(char *str)
+{
+ int a,
+ b,
+ c,
+ d,
+ e,
+ f;
+ macaddr *result;
+ int count;
+
+ if (strlen(str) > 0)
+ {
+
+ count = sscanf(str, "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f);
+ if (count != 6)
+ count = sscanf(str, "%x-%x-%x-%x-%x-%x", &a, &b, &c, &d, &e, &f);
+ if (count != 6)
+ count = sscanf(str, "%2x%2x%2x:%2x%2x%2x", &a, &b, &c, &d, &e, &f);
+ if (count != 6)
+ count = sscanf(str, "%2x%2x%2x-%2x%2x%2x", &a, &b, &c, &d, &e, &f);
+ if (count != 6)
+ count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x", &a, &b, &c, &d, &e, &f);
+
+ if (count != 6)
+ {
+ elog(ERROR, "macaddr_in: error in parsing \"%s\"", str);
+ return (NULL);
+ }
+
+ if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
+ (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
+ (e < 0) || (e > 255) || (f < 0) || (f > 255))
+ {
+ elog(ERROR, "macaddr_in: illegal address \"%s\"", str);
+ return (NULL);
+ }
+ }
+ else
+ {
+ a = b = c = d = e = f = 0; /* special case for missing
+ * address */
+ }
+
+ result = (macaddr *) palloc(sizeof(macaddr));
+
+ result->a = a;
+ result->b = b;
+ result->c = c;
+ result->d = d;
+ result->e = e;
+ result->f = f;
+
+ return (result);
+}
+
+/*
+ * MAC address output function. Fixed format.
+ */
+
+char *
+macaddr_out(macaddr *addr)
+{
+ char *result;
+
+ if (addr == NULL)
+ return (NULL);
+
+ result = (char *) palloc(32);
+
+ if ((hibits(addr) > 0) || (lobits(addr) > 0))
+ {
+ sprintf(result, "%02x:%02x:%02x:%02x:%02x:%02x",
+ addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
+ }
+ else
+ {
+ result[0] = 0; /* special case for missing address */
+ }
+ return (result);
+}
+
+/*
+ * Boolean tests.
+ */
+
+bool
+macaddr_lt(macaddr *a1, macaddr *a2)
+{
+ return ((hibits(a1) < hibits(a2)) ||
+ ((hibits(a1) == hibits(a2)) && lobits(a1) < lobits(a2)));
+};
+
+bool
+macaddr_le(macaddr *a1, macaddr *a2)
+{
+ return ((hibits(a1) < hibits(a2)) ||
+ ((hibits(a1) == hibits(a2)) && lobits(a1) <= lobits(a2)));
+};
+
+bool
+macaddr_eq(macaddr *a1, macaddr *a2)
+{
+ return ((hibits(a1) == hibits(a2)) && (lobits(a1) == lobits(a2)));
+};
+
+bool
+macaddr_ge(macaddr *a1, macaddr *a2)
+{
+ return ((hibits(a1) > hibits(a2)) ||
+ ((hibits(a1) == hibits(a2)) && lobits(a1) >= lobits(a2)));
+};
+
+bool
+macaddr_gt(macaddr *a1, macaddr *a2)
+{
+ return ((hibits(a1) > hibits(a2)) ||
+ ((hibits(a1) == hibits(a2)) && lobits(a1) > lobits(a2)));
+};
+
+bool
+macaddr_ne(macaddr *a1, macaddr *a2)
+{
+ return ((hibits(a1) != hibits(a2)) || (lobits(a1) != lobits(a2)));
+};
+
+/*
+ * Comparison function for sorting:
+ */
+
+int4
+macaddr_cmp(macaddr *a1, macaddr *a2)
+{
+ if (hibits(a1) < hibits(a2))
+ return -1;
+ else if (hibits(a1) > hibits(a2))
+ return 1;
+ else if (lobits(a1) < lobits(a2))
+ return -1;
+ else if (lobits(a1) > lobits(a2))
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * The special manufacturer fetching function. See "mac.h".
+ */
+
+text *
+macaddr_manuf(macaddr *addr)
+{
+ manufacturer *manuf;
+ int length;
+ text *result;
+
+ for (manuf = manufacturers; manuf->name != NULL; manuf++)
+ {
+ if ((manuf->a == addr->a) &&
+ (manuf->b == addr->b) &&
+ (manuf->c == addr->c))
+ break;
+ }
+ if (manuf->name == NULL)
+ {
+ result = palloc(VARHDRSZ + 1);
+ memset(result, 0, VARHDRSZ + 1);
+ VARSIZE(result) = VARHDRSZ + 1;
+ }
+ else
+ {
+ length = strlen(manuf->name) + 1;
+ result = palloc(length + VARHDRSZ);
+ memset(result, 0, length + VARHDRSZ);
+ VARSIZE(result) = length + VARHDRSZ;
+ memcpy(VARDATA(result), manuf->name, length);
+ }
+ return result;
+}