mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			578 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			578 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*-------------------------------------------------------------------------
 | 
						|
 *
 | 
						|
 * mac8.c
 | 
						|
 *	  PostgreSQL type definitions for 8 byte (EUI-64) MAC addresses.
 | 
						|
 *
 | 
						|
 * EUI-48 (6 byte) MAC addresses are accepted as input and are stored in
 | 
						|
 * EUI-64 format, with the 4th and 5th bytes set to FF and FE, respectively.
 | 
						|
 *
 | 
						|
 * Output is always in 8 byte (EUI-64) format.
 | 
						|
 *
 | 
						|
 * The following code is written with the assumption that the OUI field
 | 
						|
 * size is 24 bits.
 | 
						|
 *
 | 
						|
 * Portions Copyright (c) 1998-2018, PostgreSQL Global Development Group
 | 
						|
 *
 | 
						|
 * IDENTIFICATION
 | 
						|
 *		  src/backend/utils/adt/mac8.c
 | 
						|
 *
 | 
						|
 *-------------------------------------------------------------------------
 | 
						|
 */
 | 
						|
 | 
						|
#include "postgres.h"
 | 
						|
 | 
						|
#include "access/hash.h"
 | 
						|
#include "libpq/pqformat.h"
 | 
						|
#include "utils/builtins.h"
 | 
						|
#include "utils/inet.h"
 | 
						|
 | 
						|
/*
 | 
						|
 *	Utility macros used for sorting and comparing:
 | 
						|
 */
 | 
						|
#define hibits(addr) \
 | 
						|
  ((unsigned long)(((addr)->a<<24) | ((addr)->b<<16) | ((addr)->c<<8) | ((addr)->d)))
 | 
						|
 | 
						|
#define lobits(addr) \
 | 
						|
  ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h)))
 | 
						|
 | 
						|
static unsigned char hex2_to_uchar(const unsigned char *str, const unsigned char *ptr);
 | 
						|
 | 
						|
static const signed char hexlookup[128] = {
 | 
						|
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
						|
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
						|
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
						|
	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
 | 
						|
	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
						|
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
						|
	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
						|
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * hex2_to_uchar - convert 2 hex digits to a byte (unsigned char)
 | 
						|
 *
 | 
						|
 * This will ereport() if the end of the string is reached ('\0' found), or if
 | 
						|
 * either character is not a valid hex digit.
 | 
						|
 *
 | 
						|
 * ptr is the pointer to where the digits to convert are in the string, str is
 | 
						|
 * the entire string, which is used only for error reporting.
 | 
						|
 */
 | 
						|
static inline unsigned char
 | 
						|
hex2_to_uchar(const unsigned char *ptr, const unsigned char *str)
 | 
						|
{
 | 
						|
	unsigned char ret = 0;
 | 
						|
	signed char lookup;
 | 
						|
 | 
						|
	/* Handle the first character */
 | 
						|
	if (*ptr > 127)
 | 
						|
		goto invalid_input;
 | 
						|
 | 
						|
	lookup = hexlookup[*ptr];
 | 
						|
	if (lookup < 0)
 | 
						|
		goto invalid_input;
 | 
						|
 | 
						|
	ret = lookup << 4;
 | 
						|
 | 
						|
	/* Move to the second character */
 | 
						|
	ptr++;
 | 
						|
 | 
						|
	if (*ptr > 127)
 | 
						|
		goto invalid_input;
 | 
						|
 | 
						|
	lookup = hexlookup[*ptr];
 | 
						|
	if (lookup < 0)
 | 
						|
		goto invalid_input;
 | 
						|
 | 
						|
	ret += lookup;
 | 
						|
 | 
						|
	return ret;
 | 
						|
 | 
						|
invalid_input:
 | 
						|
	ereport(ERROR,
 | 
						|
			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 | 
						|
			 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 | 
						|
					str)));
 | 
						|
 | 
						|
	/* We do not actually reach here */
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * MAC address (EUI-48 and EUI-64) reader. Accepts several common notations.
 | 
						|
 */
 | 
						|
Datum
 | 
						|
macaddr8_in(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	const unsigned char *str = (unsigned char *) PG_GETARG_CSTRING(0);
 | 
						|
	const unsigned char *ptr = str;
 | 
						|
	macaddr8   *result;
 | 
						|
	unsigned char a = 0,
 | 
						|
				b = 0,
 | 
						|
				c = 0,
 | 
						|
				d = 0,
 | 
						|
				e = 0,
 | 
						|
				f = 0,
 | 
						|
				g = 0,
 | 
						|
				h = 0;
 | 
						|
	int			count = 0;
 | 
						|
	unsigned char spacer = '\0';
 | 
						|
 | 
						|
	/* skip leading spaces */
 | 
						|
	while (*ptr && isspace(*ptr))
 | 
						|
		ptr++;
 | 
						|
 | 
						|
	/* digits must always come in pairs */
 | 
						|
	while (*ptr && *(ptr + 1))
 | 
						|
	{
 | 
						|
		/*
 | 
						|
		 * Attempt to decode each byte, which must be 2 hex digits in a row.
 | 
						|
		 * If either digit is not hex, hex2_to_uchar will throw ereport() for
 | 
						|
		 * us.  Either 6 or 8 byte MAC addresses are supported.
 | 
						|
		 */
 | 
						|
 | 
						|
		/* Attempt to collect a byte */
 | 
						|
		count++;
 | 
						|
 | 
						|
		switch (count)
 | 
						|
		{
 | 
						|
			case 1:
 | 
						|
				a = hex2_to_uchar(ptr, str);
 | 
						|
				break;
 | 
						|
			case 2:
 | 
						|
				b = hex2_to_uchar(ptr, str);
 | 
						|
				break;
 | 
						|
			case 3:
 | 
						|
				c = hex2_to_uchar(ptr, str);
 | 
						|
				break;
 | 
						|
			case 4:
 | 
						|
				d = hex2_to_uchar(ptr, str);
 | 
						|
				break;
 | 
						|
			case 5:
 | 
						|
				e = hex2_to_uchar(ptr, str);
 | 
						|
				break;
 | 
						|
			case 6:
 | 
						|
				f = hex2_to_uchar(ptr, str);
 | 
						|
				break;
 | 
						|
			case 7:
 | 
						|
				g = hex2_to_uchar(ptr, str);
 | 
						|
				break;
 | 
						|
			case 8:
 | 
						|
				h = hex2_to_uchar(ptr, str);
 | 
						|
				break;
 | 
						|
			default:
 | 
						|
				/* must be trailing garbage... */
 | 
						|
				ereport(ERROR,
 | 
						|
						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 | 
						|
						 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 | 
						|
								str)));
 | 
						|
		}
 | 
						|
 | 
						|
		/* Move forward to where the next byte should be */
 | 
						|
		ptr += 2;
 | 
						|
 | 
						|
		/* Check for a spacer, these are valid, anything else is not */
 | 
						|
		if (*ptr == ':' || *ptr == '-' || *ptr == '.')
 | 
						|
		{
 | 
						|
			/* remember the spacer used, if it changes then it isn't valid */
 | 
						|
			if (spacer == '\0')
 | 
						|
				spacer = *ptr;
 | 
						|
 | 
						|
			/* Have to use the same spacer throughout */
 | 
						|
			else if (spacer != *ptr)
 | 
						|
				ereport(ERROR,
 | 
						|
						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 | 
						|
						 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 | 
						|
								str)));
 | 
						|
 | 
						|
			/* move past the spacer */
 | 
						|
			ptr++;
 | 
						|
		}
 | 
						|
 | 
						|
		/* allow trailing whitespace after if we have 6 or 8 bytes */
 | 
						|
		if (count == 6 || count == 8)
 | 
						|
		{
 | 
						|
			if (isspace(*ptr))
 | 
						|
			{
 | 
						|
				while (*++ptr && isspace(*ptr));
 | 
						|
 | 
						|
				/* If we found a space and then non-space, it's invalid */
 | 
						|
				if (*ptr)
 | 
						|
					ereport(ERROR,
 | 
						|
							(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 | 
						|
							 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 | 
						|
									str)));
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* Convert a 6 byte MAC address to macaddr8 */
 | 
						|
	if (count == 6)
 | 
						|
	{
 | 
						|
		h = f;
 | 
						|
		g = e;
 | 
						|
		f = d;
 | 
						|
 | 
						|
		d = 0xFF;
 | 
						|
		e = 0xFE;
 | 
						|
	}
 | 
						|
	else if (count != 8)
 | 
						|
		ereport(ERROR,
 | 
						|
				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 | 
						|
				 errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
 | 
						|
						str)));
 | 
						|
 | 
						|
	result = (macaddr8 *) palloc0(sizeof(macaddr8));
 | 
						|
 | 
						|
	result->a = a;
 | 
						|
	result->b = b;
 | 
						|
	result->c = c;
 | 
						|
	result->d = d;
 | 
						|
	result->e = e;
 | 
						|
	result->f = f;
 | 
						|
	result->g = g;
 | 
						|
	result->h = h;
 | 
						|
 | 
						|
	PG_RETURN_MACADDR8_P(result);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * MAC8 address (EUI-64) output function. Fixed format.
 | 
						|
 */
 | 
						|
Datum
 | 
						|
macaddr8_out(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
 | 
						|
	char	   *result;
 | 
						|
 | 
						|
	result = (char *) palloc(32);
 | 
						|
 | 
						|
	snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
 | 
						|
			 addr->a, addr->b, addr->c, addr->d,
 | 
						|
			 addr->e, addr->f, addr->g, addr->h);
 | 
						|
 | 
						|
	PG_RETURN_CSTRING(result);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
 | 
						|
 *
 | 
						|
 * The external representation is just the eight bytes, MSB first.
 | 
						|
 */
 | 
						|
Datum
 | 
						|
macaddr8_recv(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
 | 
						|
	macaddr8   *addr;
 | 
						|
 | 
						|
	addr = (macaddr8 *) palloc0(sizeof(macaddr8));
 | 
						|
 | 
						|
	addr->a = pq_getmsgbyte(buf);
 | 
						|
	addr->b = pq_getmsgbyte(buf);
 | 
						|
	addr->c = pq_getmsgbyte(buf);
 | 
						|
 | 
						|
	if (buf->len == 6)
 | 
						|
	{
 | 
						|
		addr->d = 0xFF;
 | 
						|
		addr->e = 0xFE;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		addr->d = pq_getmsgbyte(buf);
 | 
						|
		addr->e = pq_getmsgbyte(buf);
 | 
						|
	}
 | 
						|
 | 
						|
	addr->f = pq_getmsgbyte(buf);
 | 
						|
	addr->g = pq_getmsgbyte(buf);
 | 
						|
	addr->h = pq_getmsgbyte(buf);
 | 
						|
 | 
						|
	PG_RETURN_MACADDR8_P(addr);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * macaddr8_send - converts macaddr8(EUI-64) to binary format
 | 
						|
 */
 | 
						|
Datum
 | 
						|
macaddr8_send(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
 | 
						|
	StringInfoData buf;
 | 
						|
 | 
						|
	pq_begintypsend(&buf);
 | 
						|
	pq_sendbyte(&buf, addr->a);
 | 
						|
	pq_sendbyte(&buf, addr->b);
 | 
						|
	pq_sendbyte(&buf, addr->c);
 | 
						|
	pq_sendbyte(&buf, addr->d);
 | 
						|
	pq_sendbyte(&buf, addr->e);
 | 
						|
	pq_sendbyte(&buf, addr->f);
 | 
						|
	pq_sendbyte(&buf, addr->g);
 | 
						|
	pq_sendbyte(&buf, addr->h);
 | 
						|
 | 
						|
	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * macaddr8_cmp_internal - comparison function for sorting:
 | 
						|
 */
 | 
						|
static int32
 | 
						|
macaddr8_cmp_internal(macaddr8 *a1, macaddr8 *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;
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
macaddr8_cmp(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
 | 
						|
 | 
						|
	PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Boolean comparison functions.
 | 
						|
 */
 | 
						|
 | 
						|
Datum
 | 
						|
macaddr8_lt(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
 | 
						|
 | 
						|
	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
macaddr8_le(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
 | 
						|
 | 
						|
	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
macaddr8_eq(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
 | 
						|
 | 
						|
	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
macaddr8_ge(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
 | 
						|
 | 
						|
	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
macaddr8_gt(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
 | 
						|
 | 
						|
	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
macaddr8_ne(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *a1 = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *a2 = PG_GETARG_MACADDR8_P(1);
 | 
						|
 | 
						|
	PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Support function for hash indexes on macaddr8.
 | 
						|
 */
 | 
						|
Datum
 | 
						|
hashmacaddr8(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *key = PG_GETARG_MACADDR8_P(0);
 | 
						|
 | 
						|
	return hash_any((unsigned char *) key, sizeof(macaddr8));
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
hashmacaddr8extended(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *key = PG_GETARG_MACADDR8_P(0);
 | 
						|
 | 
						|
	return hash_any_extended((unsigned char *) key, sizeof(macaddr8),
 | 
						|
							 PG_GETARG_INT64(1));
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Arithmetic functions: bitwise NOT, AND, OR.
 | 
						|
 */
 | 
						|
Datum
 | 
						|
macaddr8_not(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *result;
 | 
						|
 | 
						|
	result = (macaddr8 *) palloc0(sizeof(macaddr8));
 | 
						|
	result->a = ~addr->a;
 | 
						|
	result->b = ~addr->b;
 | 
						|
	result->c = ~addr->c;
 | 
						|
	result->d = ~addr->d;
 | 
						|
	result->e = ~addr->e;
 | 
						|
	result->f = ~addr->f;
 | 
						|
	result->g = ~addr->g;
 | 
						|
	result->h = ~addr->h;
 | 
						|
 | 
						|
	PG_RETURN_MACADDR8_P(result);
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
macaddr8_and(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
 | 
						|
	macaddr8   *result;
 | 
						|
 | 
						|
	result = (macaddr8 *) palloc0(sizeof(macaddr8));
 | 
						|
	result->a = addr1->a & addr2->a;
 | 
						|
	result->b = addr1->b & addr2->b;
 | 
						|
	result->c = addr1->c & addr2->c;
 | 
						|
	result->d = addr1->d & addr2->d;
 | 
						|
	result->e = addr1->e & addr2->e;
 | 
						|
	result->f = addr1->f & addr2->f;
 | 
						|
	result->g = addr1->g & addr2->g;
 | 
						|
	result->h = addr1->h & addr2->h;
 | 
						|
 | 
						|
	PG_RETURN_MACADDR8_P(result);
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
macaddr8_or(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *addr1 = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *addr2 = PG_GETARG_MACADDR8_P(1);
 | 
						|
	macaddr8   *result;
 | 
						|
 | 
						|
	result = (macaddr8 *) palloc0(sizeof(macaddr8));
 | 
						|
	result->a = addr1->a | addr2->a;
 | 
						|
	result->b = addr1->b | addr2->b;
 | 
						|
	result->c = addr1->c | addr2->c;
 | 
						|
	result->d = addr1->d | addr2->d;
 | 
						|
	result->e = addr1->e | addr2->e;
 | 
						|
	result->f = addr1->f | addr2->f;
 | 
						|
	result->g = addr1->g | addr2->g;
 | 
						|
	result->h = addr1->h | addr2->h;
 | 
						|
 | 
						|
	PG_RETURN_MACADDR8_P(result);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Truncation function to allow comparing macaddr8 manufacturers.
 | 
						|
 */
 | 
						|
Datum
 | 
						|
macaddr8_trunc(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *result;
 | 
						|
 | 
						|
	result = (macaddr8 *) palloc0(sizeof(macaddr8));
 | 
						|
 | 
						|
	result->a = addr->a;
 | 
						|
	result->b = addr->b;
 | 
						|
	result->c = addr->c;
 | 
						|
	result->d = 0;
 | 
						|
	result->e = 0;
 | 
						|
	result->f = 0;
 | 
						|
	result->g = 0;
 | 
						|
	result->h = 0;
 | 
						|
 | 
						|
	PG_RETURN_MACADDR8_P(result);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Set 7th bit for modified EUI-64 as used in IPv6.
 | 
						|
 */
 | 
						|
Datum
 | 
						|
macaddr8_set7bit(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr8   *result;
 | 
						|
 | 
						|
	result = (macaddr8 *) palloc0(sizeof(macaddr8));
 | 
						|
 | 
						|
	result->a = addr->a | 0x02;
 | 
						|
	result->b = addr->b;
 | 
						|
	result->c = addr->c;
 | 
						|
	result->d = addr->d;
 | 
						|
	result->e = addr->e;
 | 
						|
	result->f = addr->f;
 | 
						|
	result->g = addr->g;
 | 
						|
	result->h = addr->h;
 | 
						|
 | 
						|
	PG_RETURN_MACADDR8_P(result);
 | 
						|
}
 | 
						|
 | 
						|
/*----------------------------------------------------------
 | 
						|
 *	Conversion operators.
 | 
						|
 *---------------------------------------------------------*/
 | 
						|
 | 
						|
Datum
 | 
						|
macaddrtomacaddr8(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr    *addr6 = PG_GETARG_MACADDR_P(0);
 | 
						|
	macaddr8   *result;
 | 
						|
 | 
						|
	result = (macaddr8 *) palloc0(sizeof(macaddr8));
 | 
						|
 | 
						|
	result->a = addr6->a;
 | 
						|
	result->b = addr6->b;
 | 
						|
	result->c = addr6->c;
 | 
						|
	result->d = 0xFF;
 | 
						|
	result->e = 0xFE;
 | 
						|
	result->f = addr6->d;
 | 
						|
	result->g = addr6->e;
 | 
						|
	result->h = addr6->f;
 | 
						|
 | 
						|
 | 
						|
	PG_RETURN_MACADDR8_P(result);
 | 
						|
}
 | 
						|
 | 
						|
Datum
 | 
						|
macaddr8tomacaddr(PG_FUNCTION_ARGS)
 | 
						|
{
 | 
						|
	macaddr8   *addr = PG_GETARG_MACADDR8_P(0);
 | 
						|
	macaddr    *result;
 | 
						|
 | 
						|
	result = (macaddr *) palloc0(sizeof(macaddr));
 | 
						|
 | 
						|
	if ((addr->d != 0xFF) || (addr->e != 0xFE))
 | 
						|
		ereport(ERROR,
 | 
						|
				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 | 
						|
				 errmsg("macaddr8 data out of range to convert to macaddr"),
 | 
						|
				 errhint("Only addresses that have FF and FE as values in the "
 | 
						|
						 "4th and 5th bytes from the left, for example "
 | 
						|
						 "xx:xx:xx:ff:fe:xx:xx:xx, are eligible to be converted "
 | 
						|
						 "from macaddr8 to macaddr.")));
 | 
						|
 | 
						|
	result->a = addr->a;
 | 
						|
	result->b = addr->b;
 | 
						|
	result->c = addr->c;
 | 
						|
	result->d = addr->f;
 | 
						|
	result->e = addr->g;
 | 
						|
	result->f = addr->h;
 | 
						|
 | 
						|
	PG_RETURN_MACADDR_P(result);
 | 
						|
}
 |