Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * mac8.c
4 : * PostgreSQL type definitions for 8 byte (EUI-64) MAC addresses.
5 : *
6 : * EUI-48 (6 byte) MAC addresses are accepted as input and are stored in
7 : * EUI-64 format, with the 4th and 5th bytes set to FF and FE, respectively.
8 : *
9 : * Output is always in 8 byte (EUI-64) format.
10 : *
11 : * The following code is written with the assumption that the OUI field
12 : * size is 24 bits.
13 : *
14 : * Portions Copyright (c) 1998-2023, PostgreSQL Global Development Group
15 : *
16 : * IDENTIFICATION
17 : * src/backend/utils/adt/mac8.c
18 : *
19 : *-------------------------------------------------------------------------
20 : */
21 :
22 : #include "postgres.h"
23 :
24 : #include "common/hashfn.h"
25 : #include "libpq/pqformat.h"
26 : #include "utils/builtins.h"
27 : #include "utils/inet.h"
28 :
29 : /*
30 : * Utility macros used for sorting and comparing:
31 : */
32 : #define hibits(addr) \
33 : ((unsigned long)(((addr)->a<<24) | ((addr)->b<<16) | ((addr)->c<<8) | ((addr)->d)))
34 :
35 : #define lobits(addr) \
36 : ((unsigned long)(((addr)->e<<24) | ((addr)->f<<16) | ((addr)->g<<8) | ((addr)->h)))
37 :
38 : static unsigned char hex2_to_uchar(const unsigned char *ptr, bool *badhex);
39 :
40 : static const signed char hexlookup[128] = {
41 : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
42 : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
43 : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
44 : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
45 : -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
46 : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
47 : -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48 : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
49 : };
50 :
51 : /*
52 : * hex2_to_uchar - convert 2 hex digits to a byte (unsigned char)
53 : *
54 : * Sets *badhex to true if the end of the string is reached ('\0' found), or if
55 : * either character is not a valid hex digit.
56 : */
57 : static inline unsigned char
116 tgl 58 GNC 8179 : hex2_to_uchar(const unsigned char *ptr, bool *badhex)
59 : {
60 : unsigned char ret;
2215 sfrost 61 ECB : signed char lookup;
2216 sfrost 62 EUB :
63 : /* Handle the first character */
2215 sfrost 64 CBC 8179 : if (*ptr > 127)
2216 sfrost 65 LBC 0 : goto invalid_input;
2216 sfrost 66 ECB :
2215 sfrost 67 GIC 8179 : lookup = hexlookup[*ptr];
2216 sfrost 68 CBC 8179 : if (lookup < 0)
2216 sfrost 69 GIC 12 : goto invalid_input;
70 :
2216 sfrost 71 CBC 8167 : ret = lookup << 4;
72 :
2216 sfrost 73 ECB : /* Move to the second character */
2216 sfrost 74 GBC 8167 : ptr++;
75 :
2215 sfrost 76 CBC 8167 : if (*ptr > 127)
2216 sfrost 77 LBC 0 : goto invalid_input;
2216 sfrost 78 ECB :
2215 sfrost 79 GIC 8167 : lookup = hexlookup[*ptr];
2216 sfrost 80 CBC 8167 : if (lookup < 0)
2216 sfrost 81 GIC 9 : goto invalid_input;
2216 sfrost 82 ECB :
2216 sfrost 83 GIC 8158 : ret += lookup;
2216 sfrost 84 ECB :
2216 sfrost 85 CBC 8158 : return ret;
2216 sfrost 86 ECB :
2216 sfrost 87 GIC 21 : invalid_input:
116 tgl 88 GNC 21 : *badhex = true;
2216 sfrost 89 GIC 21 : return 0;
2216 sfrost 90 ECB : }
91 :
92 : /*
93 : * MAC address (EUI-48 and EUI-64) reader. Accepts several common notations.
94 : */
95 : Datum
2216 sfrost 96 CBC 1211 : macaddr8_in(PG_FUNCTION_ARGS)
2216 sfrost 97 ECB : {
2153 bruce 98 CBC 1211 : const unsigned char *str = (unsigned char *) PG_GETARG_CSTRING(0);
116 tgl 99 GNC 1211 : Node *escontext = fcinfo->context;
2215 sfrost 100 CBC 1211 : const unsigned char *ptr = str;
116 tgl 101 GNC 1211 : bool badhex = false;
2216 sfrost 102 ECB : macaddr8 *result;
2216 sfrost 103 CBC 1211 : unsigned char a = 0,
104 1211 : b = 0,
105 1211 : c = 0,
106 1211 : d = 0,
2216 sfrost 107 GIC 1211 : e = 0,
108 1211 : f = 0,
2216 sfrost 109 CBC 1211 : g = 0,
110 1211 : h = 0;
2216 sfrost 111 GIC 1211 : int count = 0;
2215 112 1211 : unsigned char spacer = '\0';
2216 sfrost 113 ECB :
114 : /* skip leading spaces */
2215 sfrost 115 GIC 1259 : while (*ptr && isspace(*ptr))
2216 116 48 : ptr++;
117 :
118 : /* digits must always come in pairs */
119 9351 : while (*ptr && *(ptr + 1))
120 : {
121 : /*
2216 sfrost 122 ECB : * Attempt to decode each byte, which must be 2 hex digits in a row.
123 : * If either digit is not hex, hex2_to_uchar will throw ereport() for
124 : * us. Either 6 or 8 byte MAC addresses are supported.
125 : */
126 :
127 : /* Attempt to collect a byte */
2216 sfrost 128 CBC 8191 : count++;
2216 sfrost 129 ECB :
2216 sfrost 130 CBC 8191 : switch (count)
2216 sfrost 131 ECB : {
2216 sfrost 132 CBC 1211 : case 1:
116 tgl 133 GNC 1211 : a = hex2_to_uchar(ptr, &badhex);
2216 sfrost 134 CBC 1211 : break;
135 1205 : case 2:
116 tgl 136 GNC 1205 : b = hex2_to_uchar(ptr, &badhex);
2216 sfrost 137 CBC 1205 : break;
138 1193 : case 3:
116 tgl 139 GNC 1193 : c = hex2_to_uchar(ptr, &badhex);
2216 sfrost 140 CBC 1193 : break;
141 1193 : case 4:
116 tgl 142 GNC 1193 : d = hex2_to_uchar(ptr, &badhex);
2216 sfrost 143 CBC 1193 : break;
144 1187 : case 5:
116 tgl 145 GNC 1187 : e = hex2_to_uchar(ptr, &badhex);
2216 sfrost 146 CBC 1187 : break;
147 1187 : case 6:
116 tgl 148 GNC 1187 : f = hex2_to_uchar(ptr, &badhex);
2216 sfrost 149 CBC 1187 : break;
150 506 : case 7:
116 tgl 151 GNC 506 : g = hex2_to_uchar(ptr, &badhex);
2216 sfrost 152 CBC 506 : break;
2216 sfrost 153 GIC 497 : case 8:
116 tgl 154 GNC 497 : h = hex2_to_uchar(ptr, &badhex);
2216 sfrost 155 CBC 497 : break;
156 12 : default:
157 : /* must be trailing garbage... */
116 tgl 158 GNC 12 : goto fail;
2216 sfrost 159 ECB : }
160 :
116 tgl 161 GNC 8179 : if (badhex)
162 21 : goto fail;
163 :
164 : /* Move forward to where the next byte should be */
2216 sfrost 165 CBC 8158 : ptr += 2;
2216 sfrost 166 ECB :
167 : /* Check for a spacer, these are valid, anything else is not */
2216 sfrost 168 GIC 8158 : if (*ptr == ':' || *ptr == '-' || *ptr == '.')
2216 sfrost 169 ECB : {
170 : /* remember the spacer used, if it changes then it isn't valid */
2216 sfrost 171 GIC 4466 : if (spacer == '\0')
172 857 : spacer = *ptr;
2216 sfrost 173 ECB :
174 : /* Have to use the same spacer throughout */
2216 sfrost 175 GIC 3609 : else if (spacer != *ptr)
116 tgl 176 GNC 12 : goto fail;
177 :
2216 sfrost 178 ECB : /* move past the spacer */
2216 sfrost 179 GIC 4454 : ptr++;
180 : }
2216 sfrost 181 ECB :
182 : /* allow trailing whitespace after if we have 6 or 8 bytes */
2216 sfrost 183 GIC 8146 : if (count == 6 || count == 8)
184 : {
2215 185 1678 : if (isspace(*ptr))
186 : {
187 72 : while (*++ptr && isspace(*ptr));
2216 sfrost 188 ECB :
189 : /* If we found a space and then non-space, it's invalid */
2216 sfrost 190 CBC 18 : if (*ptr)
116 tgl 191 GNC 6 : goto fail;
2216 sfrost 192 ECB : }
193 : }
194 : }
195 :
196 : /* Convert a 6 byte MAC address to macaddr8 */
2216 sfrost 197 CBC 1160 : if (count == 6)
198 : {
199 678 : h = f;
200 678 : g = e;
201 678 : f = d;
2216 sfrost 202 ECB :
2216 sfrost 203 CBC 678 : d = 0xFF;
204 678 : e = 0xFE;
2216 sfrost 205 ECB : }
2216 sfrost 206 CBC 482 : else if (count != 8)
116 tgl 207 GNC 6 : goto fail;
2216 sfrost 208 ECB :
2216 sfrost 209 GIC 1154 : result = (macaddr8 *) palloc0(sizeof(macaddr8));
210 :
211 1154 : result->a = a;
212 1154 : result->b = b;
213 1154 : result->c = c;
214 1154 : result->d = d;
215 1154 : result->e = e;
216 1154 : result->f = f;
217 1154 : result->g = g;
2216 sfrost 218 CBC 1154 : result->h = h;
219 :
220 1154 : PG_RETURN_MACADDR8_P(result);
221 :
116 tgl 222 GNC 57 : fail:
223 57 : ereturn(escontext, (Datum) 0,
224 : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
225 : errmsg("invalid input syntax for type %s: \"%s\"", "macaddr8",
226 : str)));
227 : }
228 :
2216 sfrost 229 ECB : /*
230 : * MAC8 address (EUI-64) output function. Fixed format.
231 : */
232 : Datum
2216 sfrost 233 CBC 872 : macaddr8_out(PG_FUNCTION_ARGS)
234 : {
235 872 : macaddr8 *addr = PG_GETARG_MACADDR8_P(0);
236 : char *result;
237 :
2216 sfrost 238 GIC 872 : result = (char *) palloc(32);
239 :
240 872 : snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
241 872 : addr->a, addr->b, addr->c, addr->d,
242 872 : addr->e, addr->f, addr->g, addr->h);
243 :
2216 sfrost 244 GBC 872 : PG_RETURN_CSTRING(result);
245 : }
2216 sfrost 246 EUB :
247 : /*
248 : * macaddr8_recv - converts external binary format(EUI-48 and EUI-64) to macaddr8
249 : *
250 : * The external representation is just the eight bytes, MSB first.
251 : */
252 : Datum
2216 sfrost 253 UBC 0 : macaddr8_recv(PG_FUNCTION_ARGS)
254 : {
255 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
256 : macaddr8 *addr;
2216 sfrost 257 EUB :
2216 sfrost 258 UBC 0 : addr = (macaddr8 *) palloc0(sizeof(macaddr8));
259 :
2216 sfrost 260 UIC 0 : addr->a = pq_getmsgbyte(buf);
261 0 : addr->b = pq_getmsgbyte(buf);
2216 sfrost 262 UBC 0 : addr->c = pq_getmsgbyte(buf);
2216 sfrost 263 EUB :
2216 sfrost 264 UIC 0 : if (buf->len == 6)
265 : {
2216 sfrost 266 UBC 0 : addr->d = 0xFF;
267 0 : addr->e = 0xFE;
2216 sfrost 268 EUB : }
269 : else
270 : {
2216 sfrost 271 UIC 0 : addr->d = pq_getmsgbyte(buf);
272 0 : addr->e = pq_getmsgbyte(buf);
273 : }
274 :
275 0 : addr->f = pq_getmsgbyte(buf);
276 0 : addr->g = pq_getmsgbyte(buf);
2216 sfrost 277 UBC 0 : addr->h = pq_getmsgbyte(buf);
278 :
279 0 : PG_RETURN_MACADDR8_P(addr);
280 : }
281 :
2216 sfrost 282 EUB : /*
283 : * macaddr8_send - converts macaddr8(EUI-64) to binary format
284 : */
285 : Datum
2216 sfrost 286 UBC 0 : macaddr8_send(PG_FUNCTION_ARGS)
2216 sfrost 287 EUB : {
2216 sfrost 288 UBC 0 : macaddr8 *addr = PG_GETARG_MACADDR8_P(0);
2216 sfrost 289 EUB : StringInfoData buf;
290 :
2216 sfrost 291 UIC 0 : pq_begintypsend(&buf);
2216 sfrost 292 UBC 0 : pq_sendbyte(&buf, addr->a);
2216 sfrost 293 UIC 0 : pq_sendbyte(&buf, addr->b);
294 0 : pq_sendbyte(&buf, addr->c);
295 0 : pq_sendbyte(&buf, addr->d);
296 0 : pq_sendbyte(&buf, addr->e);
297 0 : pq_sendbyte(&buf, addr->f);
298 0 : pq_sendbyte(&buf, addr->g);
299 0 : pq_sendbyte(&buf, addr->h);
2216 sfrost 300 ECB :
2216 sfrost 301 UIC 0 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
2216 sfrost 302 ECB : }
303 :
304 :
305 : /*
306 : * macaddr8_cmp_internal - comparison function for sorting:
307 : */
308 : static int32
2216 sfrost 309 CBC 89347 : macaddr8_cmp_internal(macaddr8 *a1, macaddr8 *a2)
310 : {
311 89347 : if (hibits(a1) < hibits(a2))
2216 sfrost 312 GIC 49408 : return -1;
313 39939 : else if (hibits(a1) > hibits(a2))
314 35846 : return 1;
2216 sfrost 315 CBC 4093 : else if (lobits(a1) < lobits(a2))
2216 sfrost 316 GIC 111 : return -1;
2216 sfrost 317 CBC 3982 : else if (lobits(a1) > lobits(a2))
318 12 : return 1;
319 : else
320 3970 : return 0;
321 : }
322 :
323 : Datum
2216 sfrost 324 GIC 7253 : macaddr8_cmp(PG_FUNCTION_ARGS)
325 : {
326 7253 : macaddr8 *a1 = PG_GETARG_MACADDR8_P(0);
327 7253 : macaddr8 *a2 = PG_GETARG_MACADDR8_P(1);
2216 sfrost 328 ECB :
2216 sfrost 329 GIC 7253 : PG_RETURN_INT32(macaddr8_cmp_internal(a1, a2));
2216 sfrost 330 ECB : }
331 :
332 : /*
333 : * Boolean comparison functions.
334 : */
335 :
336 : Datum
2216 sfrost 337 CBC 56675 : macaddr8_lt(PG_FUNCTION_ARGS)
338 : {
339 56675 : macaddr8 *a1 = PG_GETARG_MACADDR8_P(0);
340 56675 : macaddr8 *a2 = PG_GETARG_MACADDR8_P(1);
341 :
342 56675 : PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) < 0);
343 : }
344 :
345 : Datum
346 1846 : macaddr8_le(PG_FUNCTION_ARGS)
347 : {
348 1846 : macaddr8 *a1 = PG_GETARG_MACADDR8_P(0);
349 1846 : macaddr8 *a2 = PG_GETARG_MACADDR8_P(1);
350 :
351 1846 : PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) <= 0);
352 : }
353 :
354 : Datum
355 19005 : macaddr8_eq(PG_FUNCTION_ARGS)
356 : {
357 19005 : macaddr8 *a1 = PG_GETARG_MACADDR8_P(0);
358 19005 : macaddr8 *a2 = PG_GETARG_MACADDR8_P(1);
359 :
360 19005 : PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) == 0);
361 : }
362 :
363 : Datum
364 1497 : macaddr8_ge(PG_FUNCTION_ARGS)
365 : {
366 1497 : macaddr8 *a1 = PG_GETARG_MACADDR8_P(0);
367 1497 : macaddr8 *a2 = PG_GETARG_MACADDR8_P(1);
368 :
369 1497 : PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) >= 0);
370 : }
371 :
372 : Datum
373 3065 : macaddr8_gt(PG_FUNCTION_ARGS)
374 : {
375 3065 : macaddr8 *a1 = PG_GETARG_MACADDR8_P(0);
376 3065 : macaddr8 *a2 = PG_GETARG_MACADDR8_P(1);
377 :
378 3065 : PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) > 0);
379 : }
380 :
381 : Datum
2216 sfrost 382 GIC 6 : macaddr8_ne(PG_FUNCTION_ARGS)
383 : {
384 6 : macaddr8 *a1 = PG_GETARG_MACADDR8_P(0);
2216 sfrost 385 CBC 6 : macaddr8 *a2 = PG_GETARG_MACADDR8_P(1);
386 :
387 6 : PG_RETURN_BOOL(macaddr8_cmp_internal(a1, a2) != 0);
388 : }
2216 sfrost 389 ECB :
390 : /*
391 : * Support function for hash indexes on macaddr8.
392 : */
393 : Datum
2216 sfrost 394 GIC 90 : hashmacaddr8(PG_FUNCTION_ARGS)
2216 sfrost 395 ECB : {
2216 sfrost 396 GIC 90 : macaddr8 *key = PG_GETARG_MACADDR8_P(0);
2216 sfrost 397 ECB :
2216 sfrost 398 CBC 90 : return hash_any((unsigned char *) key, sizeof(macaddr8));
399 : }
400 :
401 : Datum
2047 rhaas 402 GIC 30 : hashmacaddr8extended(PG_FUNCTION_ARGS)
403 : {
404 30 : macaddr8 *key = PG_GETARG_MACADDR8_P(0);
2047 rhaas 405 ECB :
2047 rhaas 406 GIC 30 : return hash_any_extended((unsigned char *) key, sizeof(macaddr8),
2047 rhaas 407 CBC 30 : PG_GETARG_INT64(1));
408 : }
409 :
2216 sfrost 410 ECB : /*
411 : * Arithmetic functions: bitwise NOT, AND, OR.
412 : */
413 : Datum
2216 sfrost 414 CBC 60 : macaddr8_not(PG_FUNCTION_ARGS)
2216 sfrost 415 ECB : {
2216 sfrost 416 CBC 60 : macaddr8 *addr = PG_GETARG_MACADDR8_P(0);
2216 sfrost 417 ECB : macaddr8 *result;
418 :
2216 sfrost 419 GIC 60 : result = (macaddr8 *) palloc0(sizeof(macaddr8));
2216 sfrost 420 CBC 60 : result->a = ~addr->a;
2216 sfrost 421 GIC 60 : result->b = ~addr->b;
422 60 : result->c = ~addr->c;
423 60 : result->d = ~addr->d;
2216 sfrost 424 CBC 60 : result->e = ~addr->e;
2216 sfrost 425 GIC 60 : result->f = ~addr->f;
2216 sfrost 426 CBC 60 : result->g = ~addr->g;
427 60 : result->h = ~addr->h;
428 :
2216 sfrost 429 GIC 60 : PG_RETURN_MACADDR8_P(result);
2216 sfrost 430 ECB : }
431 :
432 : Datum
2216 sfrost 433 CBC 60 : macaddr8_and(PG_FUNCTION_ARGS)
2216 sfrost 434 ECB : {
2216 sfrost 435 CBC 60 : macaddr8 *addr1 = PG_GETARG_MACADDR8_P(0);
436 60 : macaddr8 *addr2 = PG_GETARG_MACADDR8_P(1);
2216 sfrost 437 ECB : macaddr8 *result;
438 :
2216 sfrost 439 GIC 60 : result = (macaddr8 *) palloc0(sizeof(macaddr8));
2216 sfrost 440 CBC 60 : result->a = addr1->a & addr2->a;
2216 sfrost 441 GIC 60 : result->b = addr1->b & addr2->b;
442 60 : result->c = addr1->c & addr2->c;
443 60 : result->d = addr1->d & addr2->d;
2216 sfrost 444 CBC 60 : result->e = addr1->e & addr2->e;
2216 sfrost 445 GIC 60 : result->f = addr1->f & addr2->f;
2216 sfrost 446 CBC 60 : result->g = addr1->g & addr2->g;
447 60 : result->h = addr1->h & addr2->h;
448 :
2216 sfrost 449 GIC 60 : PG_RETURN_MACADDR8_P(result);
2216 sfrost 450 ECB : }
451 :
452 : Datum
2216 sfrost 453 CBC 60 : macaddr8_or(PG_FUNCTION_ARGS)
2216 sfrost 454 ECB : {
2216 sfrost 455 CBC 60 : macaddr8 *addr1 = PG_GETARG_MACADDR8_P(0);
456 60 : macaddr8 *addr2 = PG_GETARG_MACADDR8_P(1);
2216 sfrost 457 ECB : macaddr8 *result;
458 :
2216 sfrost 459 GIC 60 : result = (macaddr8 *) palloc0(sizeof(macaddr8));
2216 sfrost 460 CBC 60 : result->a = addr1->a | addr2->a;
2216 sfrost 461 GIC 60 : result->b = addr1->b | addr2->b;
462 60 : result->c = addr1->c | addr2->c;
463 60 : result->d = addr1->d | addr2->d;
464 60 : result->e = addr1->e | addr2->e;
465 60 : result->f = addr1->f | addr2->f;
466 60 : result->g = addr1->g | addr2->g;
2216 sfrost 467 CBC 60 : result->h = addr1->h | addr2->h;
468 :
469 60 : PG_RETURN_MACADDR8_P(result);
470 : }
471 :
2216 sfrost 472 ECB : /*
473 : * Truncation function to allow comparing macaddr8 manufacturers.
474 : */
475 : Datum
2216 sfrost 476 CBC 60 : macaddr8_trunc(PG_FUNCTION_ARGS)
2216 sfrost 477 ECB : {
2216 sfrost 478 CBC 60 : macaddr8 *addr = PG_GETARG_MACADDR8_P(0);
2216 sfrost 479 ECB : macaddr8 *result;
480 :
2216 sfrost 481 CBC 60 : result = (macaddr8 *) palloc0(sizeof(macaddr8));
482 :
483 60 : result->a = addr->a;
2216 sfrost 484 GIC 60 : result->b = addr->b;
485 60 : result->c = addr->c;
486 60 : result->d = 0;
487 60 : result->e = 0;
488 60 : result->f = 0;
489 60 : result->g = 0;
2216 sfrost 490 CBC 60 : result->h = 0;
491 :
492 60 : PG_RETURN_MACADDR8_P(result);
493 : }
494 :
2216 sfrost 495 ECB : /*
496 : * Set 7th bit for modified EUI-64 as used in IPv6.
497 : */
498 : Datum
2216 sfrost 499 CBC 3 : macaddr8_set7bit(PG_FUNCTION_ARGS)
2216 sfrost 500 ECB : {
2216 sfrost 501 CBC 3 : macaddr8 *addr = PG_GETARG_MACADDR8_P(0);
2216 sfrost 502 ECB : macaddr8 *result;
503 :
2216 sfrost 504 CBC 3 : result = (macaddr8 *) palloc0(sizeof(macaddr8));
505 :
506 3 : result->a = addr->a | 0x02;
2216 sfrost 507 GIC 3 : result->b = addr->b;
508 3 : result->c = addr->c;
509 3 : result->d = addr->d;
510 3 : result->e = addr->e;
511 3 : result->f = addr->f;
512 3 : result->g = addr->g;
513 3 : result->h = addr->h;
2216 sfrost 514 EUB :
2216 sfrost 515 GIC 3 : PG_RETURN_MACADDR8_P(result);
2216 sfrost 516 EUB : }
517 :
518 : /*----------------------------------------------------------
519 : * Conversion operators.
520 : *---------------------------------------------------------*/
521 :
522 : Datum
2216 sfrost 523 UBC 0 : macaddrtomacaddr8(PG_FUNCTION_ARGS)
2216 sfrost 524 EUB : {
2216 sfrost 525 UBC 0 : macaddr *addr6 = PG_GETARG_MACADDR_P(0);
2216 sfrost 526 EUB : macaddr8 *result;
527 :
2216 sfrost 528 UBC 0 : result = (macaddr8 *) palloc0(sizeof(macaddr8));
529 :
2216 sfrost 530 UIC 0 : result->a = addr6->a;
2216 sfrost 531 UBC 0 : result->b = addr6->b;
2216 sfrost 532 UIC 0 : result->c = addr6->c;
533 0 : result->d = 0xFF;
534 0 : result->e = 0xFE;
2216 sfrost 535 LBC 0 : result->f = addr6->d;
2216 sfrost 536 UIC 0 : result->g = addr6->e;
2216 sfrost 537 LBC 0 : result->h = addr6->f;
538 :
539 :
540 0 : PG_RETURN_MACADDR8_P(result);
541 : }
2216 sfrost 542 ECB :
2216 sfrost 543 EUB : Datum
2216 sfrost 544 GIC 12 : macaddr8tomacaddr(PG_FUNCTION_ARGS)
545 : {
546 12 : macaddr8 *addr = PG_GETARG_MACADDR8_P(0);
547 : macaddr *result;
548 :
549 12 : result = (macaddr *) palloc0(sizeof(macaddr));
550 :
2216 sfrost 551 CBC 12 : if ((addr->d != 0xFF) || (addr->e != 0xFE))
2216 sfrost 552 LBC 0 : ereport(ERROR,
2216 sfrost 553 ECB : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
554 : errmsg("macaddr8 data out of range to convert to macaddr"),
2118 tgl 555 : errhint("Only addresses that have FF and FE as values in the "
2036 peter_e 556 : "4th and 5th bytes from the left, for example "
557 : "xx:xx:xx:ff:fe:xx:xx:xx, are eligible to be converted "
2118 tgl 558 : "from macaddr8 to macaddr.")));
559 :
2216 sfrost 560 GIC 12 : result->a = addr->a;
561 12 : result->b = addr->b;
562 12 : result->c = addr->c;
563 12 : result->d = addr->f;
564 12 : result->e = addr->g;
565 12 : result->f = addr->h;
566 :
567 12 : PG_RETURN_MACADDR_P(result);
568 : }
|