PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
mac.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * mac.c
4  * PostgreSQL type definitions for 6 byte, EUI-48, MAC addresses.
5  *
6  * Portions Copyright (c) 1998-2017, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  * src/backend/utils/adt/mac.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 
14 #include "postgres.h"
15 
16 #include "access/hash.h"
17 #include "libpq/pqformat.h"
18 #include "utils/builtins.h"
19 #include "utils/inet.h"
20 
21 
22 /*
23  * Utility macros used for sorting and comparing:
24  */
25 
26 #define hibits(addr) \
27  ((unsigned long)(((addr)->a<<16)|((addr)->b<<8)|((addr)->c)))
28 
29 #define lobits(addr) \
30  ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
31 
32 /*
33  * MAC address reader. Accepts several common notations.
34  */
35 
36 Datum
38 {
39  char *str = PG_GETARG_CSTRING(0);
40  macaddr *result;
41  int a,
42  b,
43  c,
44  d,
45  e,
46  f;
47  char junk[2];
48  int count;
49 
50  /* %1s matches iff there is trailing non-whitespace garbage */
51 
52  count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
53  &a, &b, &c, &d, &e, &f, junk);
54  if (count != 6)
55  count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
56  &a, &b, &c, &d, &e, &f, junk);
57  if (count != 6)
58  count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
59  &a, &b, &c, &d, &e, &f, junk);
60  if (count != 6)
61  count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
62  &a, &b, &c, &d, &e, &f, junk);
63  if (count != 6)
64  count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
65  &a, &b, &c, &d, &e, &f, junk);
66  if (count != 6)
67  count = sscanf(str, "%2x%2x-%2x%2x-%2x%2x%1s",
68  &a, &b, &c, &d, &e, &f, junk);
69  if (count != 6)
70  count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
71  &a, &b, &c, &d, &e, &f, junk);
72  if (count != 6)
73  ereport(ERROR,
74  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
75  errmsg("invalid input syntax for type %s: \"%s\"", "macaddr",
76  str)));
77 
78  if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
79  (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
80  (e < 0) || (e > 255) || (f < 0) || (f > 255))
81  ereport(ERROR,
82  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
83  errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str)));
84 
85  result = (macaddr *) palloc(sizeof(macaddr));
86 
87  result->a = a;
88  result->b = b;
89  result->c = c;
90  result->d = d;
91  result->e = e;
92  result->f = f;
93 
94  PG_RETURN_MACADDR_P(result);
95 }
96 
97 /*
98  * MAC address output function. Fixed format.
99  */
100 
101 Datum
103 {
104  macaddr *addr = PG_GETARG_MACADDR_P(0);
105  char *result;
106 
107  result = (char *) palloc(32);
108 
109  snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x",
110  addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
111 
112  PG_RETURN_CSTRING(result);
113 }
114 
115 /*
116  * macaddr_recv - converts external binary format to macaddr
117  *
118  * The external representation is just the six bytes, MSB first.
119  */
120 Datum
122 {
124  macaddr *addr;
125 
126  addr = (macaddr *) palloc(sizeof(macaddr));
127 
128  addr->a = pq_getmsgbyte(buf);
129  addr->b = pq_getmsgbyte(buf);
130  addr->c = pq_getmsgbyte(buf);
131  addr->d = pq_getmsgbyte(buf);
132  addr->e = pq_getmsgbyte(buf);
133  addr->f = pq_getmsgbyte(buf);
134 
135  PG_RETURN_MACADDR_P(addr);
136 }
137 
138 /*
139  * macaddr_send - converts macaddr to binary format
140  */
141 Datum
143 {
144  macaddr *addr = PG_GETARG_MACADDR_P(0);
146 
147  pq_begintypsend(&buf);
148  pq_sendbyte(&buf, addr->a);
149  pq_sendbyte(&buf, addr->b);
150  pq_sendbyte(&buf, addr->c);
151  pq_sendbyte(&buf, addr->d);
152  pq_sendbyte(&buf, addr->e);
153  pq_sendbyte(&buf, addr->f);
155 }
156 
157 
158 /*
159  * Comparison function for sorting:
160  */
161 
162 static int32
164 {
165  if (hibits(a1) < hibits(a2))
166  return -1;
167  else if (hibits(a1) > hibits(a2))
168  return 1;
169  else if (lobits(a1) < lobits(a2))
170  return -1;
171  else if (lobits(a1) > lobits(a2))
172  return 1;
173  else
174  return 0;
175 }
176 
177 Datum
179 {
182 
184 }
185 
186 /*
187  * Boolean comparisons.
188  */
189 
190 Datum
192 {
195 
197 }
198 
199 Datum
201 {
204 
205  PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) <= 0);
206 }
207 
208 Datum
210 {
213 
214  PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) == 0);
215 }
216 
217 Datum
219 {
222 
223  PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) >= 0);
224 }
225 
226 Datum
228 {
231 
233 }
234 
235 Datum
237 {
240 
241  PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) != 0);
242 }
243 
244 /*
245  * Support function for hash indexes on macaddr.
246  */
247 Datum
249 {
250  macaddr *key = PG_GETARG_MACADDR_P(0);
251 
252  return hash_any((unsigned char *) key, sizeof(macaddr));
253 }
254 
255 /*
256  * Arithmetic functions: bitwise NOT, AND, OR.
257  */
258 Datum
260 {
261  macaddr *addr = PG_GETARG_MACADDR_P(0);
262  macaddr *result;
263 
264  result = (macaddr *) palloc(sizeof(macaddr));
265  result->a = ~addr->a;
266  result->b = ~addr->b;
267  result->c = ~addr->c;
268  result->d = ~addr->d;
269  result->e = ~addr->e;
270  result->f = ~addr->f;
271  PG_RETURN_MACADDR_P(result);
272 }
273 
274 Datum
276 {
277  macaddr *addr1 = PG_GETARG_MACADDR_P(0);
278  macaddr *addr2 = PG_GETARG_MACADDR_P(1);
279  macaddr *result;
280 
281  result = (macaddr *) palloc(sizeof(macaddr));
282  result->a = addr1->a & addr2->a;
283  result->b = addr1->b & addr2->b;
284  result->c = addr1->c & addr2->c;
285  result->d = addr1->d & addr2->d;
286  result->e = addr1->e & addr2->e;
287  result->f = addr1->f & addr2->f;
288  PG_RETURN_MACADDR_P(result);
289 }
290 
291 Datum
293 {
294  macaddr *addr1 = PG_GETARG_MACADDR_P(0);
295  macaddr *addr2 = PG_GETARG_MACADDR_P(1);
296  macaddr *result;
297 
298  result = (macaddr *) palloc(sizeof(macaddr));
299  result->a = addr1->a | addr2->a;
300  result->b = addr1->b | addr2->b;
301  result->c = addr1->c | addr2->c;
302  result->d = addr1->d | addr2->d;
303  result->e = addr1->e | addr2->e;
304  result->f = addr1->f | addr2->f;
305  PG_RETURN_MACADDR_P(result);
306 }
307 
308 /*
309  * Truncation function to allow comparing mac manufacturers.
310  * From suggestion by Alex Pilosov <alex@pilosoft.com>
311  */
312 Datum
314 {
315  macaddr *addr = PG_GETARG_MACADDR_P(0);
316  macaddr *result;
317 
318  result = (macaddr *) palloc(sizeof(macaddr));
319 
320  result->a = addr->a;
321  result->b = addr->b;
322  result->c = addr->c;
323  result->d = 0;
324  result->e = 0;
325  result->f = 0;
326 
327  PG_RETURN_MACADDR_P(result);
328 }
void pq_sendbyte(StringInfo buf, int byt)
Definition: pqformat.c:105
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:359
unsigned char f
Definition: inet.h:101
StringInfoData * StringInfo
Definition: stringinfo.h:46
Datum hashmacaddr(PG_FUNCTION_ARGS)
Definition: mac.c:248
#define PG_RETURN_INT32(x)
Definition: fmgr.h:306
Datum macaddr_le(PG_FUNCTION_ARGS)
Definition: mac.c:200
Datum macaddr_ge(PG_FUNCTION_ARGS)
Definition: mac.c:218
int errcode(int sqlerrcode)
Definition: elog.c:575
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:233
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:321
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:379
signed int int32
Definition: c.h:256
#define hibits(addr)
Definition: mac.c:26
#define PG_RETURN_MACADDR_P(x)
Definition: inet.h:134
unsigned char c
Definition: inet.h:98
#define ERROR
Definition: elog.h:43
unsigned char a
Definition: inet.h:96
#define PG_GETARG_MACADDR_P(n)
Definition: inet.h:133
#define lobits(addr)
Definition: mac.c:29
Datum macaddr_lt(PG_FUNCTION_ARGS)
Definition: mac.c:191
Datum macaddr_in(PG_FUNCTION_ARGS)
Definition: mac.c:37
unsigned char d
Definition: inet.h:99
static int32 macaddr_cmp_internal(macaddr *a1, macaddr *a2)
Definition: mac.c:163
Datum macaddr_trunc(PG_FUNCTION_ARGS)
Definition: mac.c:313
char * c
static char * buf
Definition: pg_test_fsync.c:65
Datum macaddr_not(PG_FUNCTION_ARGS)
Definition: mac.c:259
Datum macaddr_send(PG_FUNCTION_ARGS)
Definition: mac.c:142
#define ereport(elevel, rest)
Definition: elog.h:122
Datum macaddr_or(PG_FUNCTION_ARGS)
Definition: mac.c:292
unsigned char b
Definition: inet.h:97
Datum macaddr_eq(PG_FUNCTION_ARGS)
Definition: mac.c:209
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:311
uintptr_t Datum
Definition: postgres.h:372
unsigned char e
Definition: inet.h:100
Datum macaddr_ne(PG_FUNCTION_ARGS)
Definition: mac.c:236
static FormData_pg_attribute a1
Definition: heap.c:142
int pq_getmsgbyte(StringInfo msg)
Definition: pqformat.c:432
Datum macaddr_out(PG_FUNCTION_ARGS)
Definition: mac.c:102
Datum hash_any(register const unsigned char *k, register int keylen)
Definition: hashfunc.c:307
Datum macaddr_recv(PG_FUNCTION_ARGS)
Definition: mac.c:121
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:314
Definition: inet.h:94
Datum macaddr_and(PG_FUNCTION_ARGS)
Definition: mac.c:275
Datum macaddr_cmp(PG_FUNCTION_ARGS)
Definition: mac.c:178
e
Definition: preproc-init.c:82
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:234
#define PG_FUNCTION_ARGS
Definition: fmgr.h:150
Datum macaddr_gt(PG_FUNCTION_ARGS)
Definition: mac.c:227
static FormData_pg_attribute a2
Definition: heap.c:148