From 674b22a2a43318f14cc6d6af2b4893bcce530a6a Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" <scrappy@hub.org> Date: Sun, 25 Jan 1998 07:11:07 +0000 Subject: [PATCH] From: Tom I Helbekkmo <tih@Hamartun.Priv.NO> PostgreSQL type extensions for IP and MAC addresses. I needed to record IP and MAC level ethernet addresses in a data base, and I really didn't want to store them as plain strings, with no enforced error checking, so I put together the accompanying code as my first experiment with adding a data type to PostgreSQL. I then thought that this might be useful to others, both directly and as a very simple example of how to do this sort of thing, so here it is, in the hope that it will be useful. --- contrib/ip_and_mac/Makefile | 20 ++++ contrib/ip_and_mac/README | 51 +++++++++ contrib/ip_and_mac/ip.c | 212 ++++++++++++++++++++++++++++++++++++ contrib/ip_and_mac/ip.sql | 131 ++++++++++++++++++++++ contrib/ip_and_mac/mac.c | 202 ++++++++++++++++++++++++++++++++++ contrib/ip_and_mac/mac.h | 130 ++++++++++++++++++++++ contrib/ip_and_mac/mac.sql | 88 +++++++++++++++ 7 files changed, 834 insertions(+) create mode 100644 contrib/ip_and_mac/Makefile create mode 100644 contrib/ip_and_mac/README create mode 100644 contrib/ip_and_mac/ip.c create mode 100644 contrib/ip_and_mac/ip.sql create mode 100644 contrib/ip_and_mac/mac.c create mode 100644 contrib/ip_and_mac/mac.h create mode 100644 contrib/ip_and_mac/mac.sql diff --git a/contrib/ip_and_mac/Makefile b/contrib/ip_and_mac/Makefile new file mode 100644 index 00000000000..924a20029e4 --- /dev/null +++ b/contrib/ip_and_mac/Makefile @@ -0,0 +1,20 @@ +# PostgreSQL type definitions for IP and MAC addresses. + +all: ip.so mac.so + +ip.so: ip.o + ld -Bshareable -o ip.so ip.o + +ip.o: ip.c + cc -g -O -fPIC -I/usr/local/pgsql/include -c ip.c + +mac.so: mac.o + ld -Bshareable -o mac.so mac.o + +mac.o: mac.c mac.h + cc -g -O -fPIC -I/usr/local/pgsql/include -c mac.c + +install: ip.so mac.so + install -c ip.so mac.so /usr/local/pgsql/modules + +# eof diff --git a/contrib/ip_and_mac/README b/contrib/ip_and_mac/README new file mode 100644 index 00000000000..a2da4fc46d5 --- /dev/null +++ b/contrib/ip_and_mac/README @@ -0,0 +1,51 @@ +PostgreSQL type extensions for IP and MAC addresses. +--------------------------------------------------- + +I needed to record IP and MAC level ethernet addresses in a data +base, and I really didn't want to store them as plain strings, with +no enforced error checking, so I put together the accompanying code +as my first experiment with adding a data type to PostgreSQL. I +then thought that this might be useful to others, both directly and +as a very simple example of how to do this sort of thing, so here +it is, in the hope that it will be useful. + +IP addresses are implemented as an 8 byte struct (this may well be +more than is useful, but I figured that since it has to be at least 5, +it might as well round well) that contains the four bytes of address +and a mask width. Thus, a node address looks like '158.37.96.15/32' +(or just '158.37.96.15', which is understood to mean the same thing). +This address happens to be part of a subnet where I work; +'158.37.96.0/24', which itself is a part of the larger subnet +allocated to our institution, which is '158.37.96.0/21', which again, +if you go by the book, is part of the class "B" net '158.37.0.0/16'. + +Input and output functions are supplied, along with the "normal" <, +<=, =, >=, > and <> operators, which all do what you expect, and the +similarity operator ~~, which checks whether two given addresses are +either the same, or, failing that, whether one is a subnet +specification and the other an address (or a smaller subnet) within +that. Good for picking out records with addresses in a given subnet: +note that '158.37.96.0/21' spans '158.37.96.0' to '158.37.103.255', +which is not all that easily handled in its external representation. + +MAC level ethernet addresses are also implemented as an 8 byte struct +(I wish I knew what alignment needs are actually present -- I'm just +not taking any chances here) that contains the address as unsigned +chars. Several input forms are accepted: the following are all the +same address: '08002b:010203', '08002b-010203', '0800.2b01.0203', +'08-00-2b-01-02-03' and '08:00:2b:01:02:03'. Upper and lower case is +accepted for the digits 'a' through 'f'. Output is always in the +latter of the given forms. + +Input and output functions are supplied, along with the = and <> +operators, which do what you expect, and the similarity operator ~~, +which checks whether two given addresses belong to hardware from the +same manufacturer (first three bytes the same, that is). As an extra +feature, a function macaddr_manuf() is defined, which returns the name +of the manufacturer as a string. + +To install: fix the path names in the SQL files and the Makefile if +you need to, then make, make install, slurp the SQL files into psql or +whatever, and you're off. Enjoy! + +Bergen, Norway, 1998-01-11, Tom Ivar Helbekkmo (tih@Hamartun.Priv.NO). diff --git a/contrib/ip_and_mac/ip.c b/contrib/ip_and_mac/ip.c new file mode 100644 index 00000000000..de967aa8eda --- /dev/null +++ b/contrib/ip_and_mac/ip.c @@ -0,0 +1,212 @@ +/* + * PostgreSQL type definitions for IP addresses. + */ + +#include <stdio.h> + +#include <postgres.h> +#include <utils/palloc.h> + +/* + * This is the internal storage format for IP addresses: + */ + +typedef struct ipaddr { + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + unsigned char w; + unsigned char pad1; + short pad2; +} ipaddr; + +/* + * Various forward declarations: + */ + +ipaddr *ipaddr_in(char *str); +char *ipaddr_out(ipaddr *addr); + +bool ipaddr_lt(ipaddr *a1, ipaddr *a2); +bool ipaddr_le(ipaddr *a1, ipaddr *a2); +bool ipaddr_eq(ipaddr *a1, ipaddr *a2); +bool ipaddr_ge(ipaddr *a1, ipaddr *a2); +bool ipaddr_gt(ipaddr *a1, ipaddr *a2); + +bool ipaddr_ne(ipaddr *a1, ipaddr *a2); +int4 ipaddr_cmp(ipaddr *a1, ipaddr *a2); +bool ipaddr_like(ipaddr *a1, ipaddr *a2); + +/* + * A utility macro used for sorting addresses numerically: + */ + +#define Mag(addr) \ + ((unsigned long)((addr->a<<24)|(addr->b<<16)|(addr->c<<8)|(addr->d))) + +/* + * IP address reader. Note how the count returned by sscanf() + * is used to determine whether the mask size was specified. + */ + +ipaddr *ipaddr_in(char *str) { + int a, b, c, d, w; + ipaddr *result; + int count; + + if (strlen(str) > 0) { + + count = sscanf(str, "%d.%d.%d.%d/%d", &a, &b, &c, &d, &w); + + if (count < 4) { + elog(ERROR, "ipaddr_in: error in parsing \"%s\"", str); + return(NULL); + } + + if (count == 4) + w = 32; + + if ((a < 0) || (a > 255) || (b < 0) || (b > 255) || + (c < 0) || (c > 255) || (d < 0) || (d > 255) || + (w < 0) || (w > 32)) { + elog(ERROR, "ipaddr_in: illegal address \"%s\"", str); + return(NULL); + } + } else { + a = b = c = d = w = 0; /* special case for missing address */ + } + + result = (ipaddr *)palloc(sizeof(ipaddr)); + + result->a = a; + result->b = b; + result->c = c; + result->d = d; + result->w = w; + + return(result); +} + +/* + * IP address output function. Note mask size specification + * generated only for subnets, not for plain host addresses. + */ + +char *ipaddr_out(ipaddr *addr) { + char *result; + + if (addr == NULL) + return(NULL); + + result = (char *)palloc(32); + + if (Mag(addr) > 0) { + if (addr->w == 32) + sprintf(result, "%d.%d.%d.%d", + addr->a, addr->b, addr->c, addr->d); + else + sprintf(result, "%d.%d.%d.%d/%d", + addr->a, addr->b, addr->c, addr->d, addr->w); + } else { + result[0] = 0; /* special case for missing address */ + } + return(result); +} + +/* + * Boolean tests. The Mag() macro was defined above. + */ + +bool ipaddr_lt(ipaddr *a1, ipaddr *a2) { + unsigned long a1mag, a2mag; + a1mag = Mag(a1); + a2mag = Mag(a2); + return (a1mag < a2mag); +}; + +bool ipaddr_le(ipaddr *a1, ipaddr *a2) { + unsigned long a1mag, a2mag; + a1mag = Mag(a1); + a2mag = Mag(a2); + return (a1mag <= a2mag); +}; + +bool ipaddr_eq(ipaddr *a1, ipaddr *a2) { + unsigned long a1mag, a2mag; + a1mag = Mag(a1); + a2mag = Mag(a2); + return ((a1mag == a2mag) && (a1->w == a2->w)); +}; + +bool ipaddr_ge(ipaddr *a1, ipaddr *a2) { + unsigned long a1mag, a2mag; + a1mag = Mag(a1); + a2mag = Mag(a2); + return (a1mag >= a2mag); +}; + +bool ipaddr_gt(ipaddr *a1, ipaddr *a2) { + unsigned long a1mag, a2mag; + a1mag = Mag(a1); + a2mag = Mag(a2); + return (a1mag > a2mag); +}; + +bool ipaddr_ne(ipaddr *a1, ipaddr *a2) { + unsigned long a1mag, a2mag; + a1mag = Mag(a1); + a2mag = Mag(a2); + return ((a1mag != a2mag) || (a1->w != a2->w)); +}; + +/* + * Comparison function for sorting: + */ + +int4 ipaddr_cmp(ipaddr *a1, ipaddr *a2) { + unsigned long a1mag = Mag(a1), a2mag = Mag(a2); + if (a1mag < a2mag) + return -1; + else if (a1mag > a2mag) + return 1; + else + return 0; +} + +/* + * Our "similarity" operator checks whether two addresses are + * either the same node address, or, failing that, whether one + * of them contains the other. This will be true if they have + * the same high bits down as far as the shortest mask reaches. + */ + +unsigned long build_mask(unsigned char bits) { + unsigned long mask = 0; + int i; + for (i = 0; i < bits; i++) + mask = (mask >> 1) | 0x80000000; + return mask; +} + +bool ipaddr_like(ipaddr *a1, ipaddr *a2) { + unsigned long a1bits, a2bits, maskbits; + if ((a1->w == 0) || (a2->w == 0)) + return FALSE; + if ((a1->w == 32) && (a2->w == 32)) + return ipaddr_eq(a1, a2); + a1bits = Mag(a1); + a2bits = Mag(a2); + if (a1->w > a2->w) { + maskbits = build_mask(a2->w); + return ((a1bits & maskbits) == (a2bits & maskbits)); + } else { + maskbits = build_mask(a1->w); + return ((a2bits & maskbits) == (a1bits & maskbits)); + } + return FALSE; +} + +/* + * eof + */ diff --git a/contrib/ip_and_mac/ip.sql b/contrib/ip_and_mac/ip.sql new file mode 100644 index 00000000000..bcfe1a24d90 --- /dev/null +++ b/contrib/ip_and_mac/ip.sql @@ -0,0 +1,131 @@ +-- +-- PostgreSQL code for IP addresses. +-- + +load '/usr/local/pgsql/modules/ip.so'; + +-- +-- Input and output functions and the type itself: +-- + +create function ipaddr_in(opaque) + returns opaque + as '/usr/local/pgsql/modules/ip.so' + language 'c'; + +create function ipaddr_out(opaque) + returns opaque + as '/usr/local/pgsql/modules/ip.so' + language 'c'; + +create type ipaddr ( + internallength = 8, + externallength = variable, + input = ipaddr_in, + output = ipaddr_out +); + +-- +-- The various boolean tests: +-- + +create function ipaddr_lt(ipaddr, ipaddr) + returns bool + as '/usr/local/pgsql/modules/ip.so' + language 'c'; + +create function ipaddr_le(ipaddr, ipaddr) + returns bool + as '/usr/local/pgsql/modules/ip.so' + language 'c'; + +create function ipaddr_eq(ipaddr, ipaddr) + returns bool + as '/usr/local/pgsql/modules/ip.so' + language 'c'; + +create function ipaddr_ge(ipaddr, ipaddr) + returns bool + as '/usr/local/pgsql/modules/ip.so' + language 'c'; + +create function ipaddr_gt(ipaddr, ipaddr) + returns bool + as '/usr/local/pgsql/modules/ip.so' + language 'c'; + +create function ipaddr_ne(ipaddr, ipaddr) + returns bool + as '/usr/local/pgsql/modules/ip.so' + language 'c'; + +create function ipaddr_like(ipaddr, ipaddr) + returns bool + as '/usr/local/pgsql/modules/ip.so' + language 'c'; + +-- +-- Now the operators. Note how some of the parameters to some +-- of the 'create operator' commands are commented out. This +-- is because they reference as yet undefined operators, and +-- will be implicitly defined when those are, further down. +-- + +create operator <= ( + leftarg = ipaddr, + rightarg = ipaddr, +-- commutator = >, +-- negator = >, + procedure = ipaddr_le +); + +create operator < ( + leftarg = ipaddr, + rightarg = ipaddr, +-- commutator = >=, +-- negator = >=, + procedure = ipaddr_lt +); + +create operator = ( + leftarg = ipaddr, + rightarg = ipaddr, + commutator = =, +-- negator = <>, + procedure = ipaddr_eq +); + +create operator >= ( + leftarg = ipaddr, + rightarg = ipaddr, + commutator = <, + negator = <, + procedure = ipaddr_ge +); + +create operator > ( + leftarg = ipaddr, + rightarg = ipaddr, + commutator = <=, + negator = <=, + procedure = ipaddr_gt +); + +create operator <> ( + leftarg = ipaddr, + rightarg = ipaddr, + commutator = <>, + negator = =, + procedure = ipaddr_ne +); + +create operator ~~ ( + leftarg = ipaddr, + rightarg = ipaddr, + commutator = ~~, + procedure = ipaddr_like +); + +-- +-- eof +-- diff --git a/contrib/ip_and_mac/mac.c b/contrib/ip_and_mac/mac.c new file mode 100644 index 00000000000..3317eab24eb --- /dev/null +++ b/contrib/ip_and_mac/mac.c @@ -0,0 +1,202 @@ +/* + * PostgreSQL type definitions for MAC addresses. + */ + +#include <stdio.h> + +#include <postgres.h> +#include <utils/palloc.h> + +#include "mac.h" + +/* + * This is the internal storage format for MAC addresses: + */ + +typedef struct macaddr { + unsigned char a; + unsigned char b; + unsigned char c; + unsigned char d; + unsigned char e; + unsigned char f; + short pad; +} macaddr; + +/* + * Various forward declarations: + */ + +macaddr *macaddr_in(char *str); +char *macaddr_out(macaddr *addr); + +bool macaddr_eq(macaddr *a1, macaddr *a2); +bool macaddr_ne(macaddr *a1, macaddr *a2); + +int4 macaddr_cmp(macaddr *a1, macaddr *a2); +bool macaddr_like(macaddr *a1, macaddr *a2); +text *macaddr_manuf(macaddr *addr); + +/* + * Utility macros used for sorting and comparing: + */ + +#define MagM(addr) \ + ((unsigned long)((addr->a<<16)|(addr->b<<8)|(addr->c))) + +#define MagH(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 ((MagM(addr) > 0) || (MagH(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_eq(macaddr *a1, macaddr *a2) { + return((a1->a == a2->a) && (a1->b == a2->b) && + (a1->c == a2->c) && (a1->d == a2->d) && + (a1->e == a2->e) && (a1->f == a2->f)); +}; + +bool macaddr_ne(macaddr *a1, macaddr *a2) { + return((a1->a != a2->a) || (a1->b != a2->b) || + (a1->c != a2->c) || (a1->d != a2->d) || + (a1->e != a2->e) || (a1->f != a2->f)); +}; + +/* + * Comparison function for sorting: + */ + +int4 macaddr_cmp(macaddr *a1, macaddr *a2) { + unsigned long a1magm, a1magh, a2magm, a2magh; + a1magm = MagM(a1); + a1magh = MagH(a1); + a2magm = MagM(a2); + a2magh = MagH(a2); + if (a1magm < a2magm) + return -1; + else if (a1magm > a2magm) + return 1; + else if (a1magh < a2magh) + return -1; + else if (a1magh > a2magh) + return 1; + else + return 0; +} + +/* + * Similarity means having the same manufacurer, which means + * having the same first three bytes of address: + */ + +bool macaddr_like(macaddr *a1, macaddr *a2) { + unsigned long a1magm, a2magm; + a1magm = MagM(a1); + a2magm = MagM(a2); + if ((a1magm == 0) || (a2magm == 0)) + return FALSE; + return (a1magm == a2magm); +} + +/* + * 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; +} + +/* + * eof + */ diff --git a/contrib/ip_and_mac/mac.h b/contrib/ip_and_mac/mac.h new file mode 100644 index 00000000000..39f12d83bb3 --- /dev/null +++ b/contrib/ip_and_mac/mac.h @@ -0,0 +1,130 @@ +/* + * PostgreSQL type definitions for MAC addresses. + */ + +typedef struct manufacturer { + unsigned char a; + unsigned char b; + unsigned char c; + char *name; +} manufacturer; + +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} +}; + +/* + * eof + */ diff --git a/contrib/ip_and_mac/mac.sql b/contrib/ip_and_mac/mac.sql new file mode 100644 index 00000000000..9e5ec61277b --- /dev/null +++ b/contrib/ip_and_mac/mac.sql @@ -0,0 +1,88 @@ +-- +-- PostgreSQL code for MAC addresses. +-- + +load '/usr/local/pgsql/modules/mac.so'; + +-- +-- Input and output functions and the type itself: +-- + +create function macaddr_in(opaque) + returns opaque + as '/usr/local/pgsql/modules/mac.so' + language 'c'; + +create function macaddr_out(opaque) + returns opaque + as '/usr/local/pgsql/modules/mac.so' + language 'c'; + +create type macaddr ( + internallength = 8, + externallength = variable, + input = macaddr_in, + output = macaddr_out +); + +-- +-- The various boolean tests: +-- + +create function macaddr_eq(macaddr, macaddr) + returns bool + as '/usr/local/pgsql/modules/mac.so' + language 'c'; + +create function macaddr_ne(macaddr, macaddr) + returns bool + as '/usr/local/pgsql/modules/mac.so' + language 'c'; + +create function macaddr_like(macaddr, macaddr) + returns bool + as '/usr/local/pgsql/modules/mac.so' + language 'c'; + +-- +-- Now the operators. Note how the "negator = <>" in the +-- definition of the equivalence operator is commented out. +-- It gets defined implicitly when "<>" is defined, with +-- "=" as its negator. +-- + +create operator = ( + leftarg = macaddr, + rightarg = macaddr, + commutator = =, +-- negator = <>, + procedure = macaddr_eq +); + +create operator <> ( + leftarg = macaddr, + rightarg = macaddr, + commutator = <>, + negator = =, + procedure = macaddr_ne +); + +create operator ~~ ( + leftarg = macaddr, + rightarg = macaddr, + commutator = ~~, + procedure = macaddr_like +); + +-- +-- Finally, the special manufacurer matching function: +-- + +create function macaddr_manuf(macaddr) + returns text + as '/usr/local/pgsql/modules/mac.so' + language 'c'; + +-- +-- eof +-- -- GitLab