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