mirror of https://github.com/postgres/postgres
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.pull/50/head
parent
9f8d3b668b
commit
674b22a2a4
@ -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
|
@ -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). |
@ -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 |
||||
*/ |
@ -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 |
||||
-- |
@ -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 |
||||
*/ |
@ -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 |
||||
*/ |
@ -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 |
||||
-- |
Loading…
Reference in new issue