Header And Logo

PostgreSQL
| The world's most advanced open source database.

mac.c

Go to the documentation of this file.
00001 /*
00002  *  PostgreSQL type definitions for MAC addresses.
00003  *
00004  *  src/backend/utils/adt/mac.c
00005  */
00006 
00007 #include "postgres.h"
00008 
00009 #include "access/hash.h"
00010 #include "libpq/pqformat.h"
00011 #include "utils/builtins.h"
00012 #include "utils/inet.h"
00013 
00014 
00015 /*
00016  *  Utility macros used for sorting and comparing:
00017  */
00018 
00019 #define hibits(addr) \
00020   ((unsigned long)(((addr)->a<<16)|((addr)->b<<8)|((addr)->c)))
00021 
00022 #define lobits(addr) \
00023   ((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
00024 
00025 /*
00026  *  MAC address reader.  Accepts several common notations.
00027  */
00028 
00029 Datum
00030 macaddr_in(PG_FUNCTION_ARGS)
00031 {
00032     char       *str = PG_GETARG_CSTRING(0);
00033     macaddr    *result;
00034     int         a,
00035                 b,
00036                 c,
00037                 d,
00038                 e,
00039                 f;
00040     char        junk[2];
00041     int         count;
00042 
00043     /* %1s matches iff there is trailing non-whitespace garbage */
00044 
00045     count = sscanf(str, "%x:%x:%x:%x:%x:%x%1s",
00046                    &a, &b, &c, &d, &e, &f, junk);
00047     if (count != 6)
00048         count = sscanf(str, "%x-%x-%x-%x-%x-%x%1s",
00049                        &a, &b, &c, &d, &e, &f, junk);
00050     if (count != 6)
00051         count = sscanf(str, "%2x%2x%2x:%2x%2x%2x%1s",
00052                        &a, &b, &c, &d, &e, &f, junk);
00053     if (count != 6)
00054         count = sscanf(str, "%2x%2x%2x-%2x%2x%2x%1s",
00055                        &a, &b, &c, &d, &e, &f, junk);
00056     if (count != 6)
00057         count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x%1s",
00058                        &a, &b, &c, &d, &e, &f, junk);
00059     if (count != 6)
00060         count = sscanf(str, "%2x%2x%2x%2x%2x%2x%1s",
00061                        &a, &b, &c, &d, &e, &f, junk);
00062     if (count != 6)
00063         ereport(ERROR,
00064                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00065               errmsg("invalid input syntax for type macaddr: \"%s\"", str)));
00066 
00067     if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
00068         (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
00069         (e < 0) || (e > 255) || (f < 0) || (f > 255))
00070         ereport(ERROR,
00071                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
00072            errmsg("invalid octet value in \"macaddr\" value: \"%s\"", str)));
00073 
00074     result = (macaddr *) palloc(sizeof(macaddr));
00075 
00076     result->a = a;
00077     result->b = b;
00078     result->c = c;
00079     result->d = d;
00080     result->e = e;
00081     result->f = f;
00082 
00083     PG_RETURN_MACADDR_P(result);
00084 }
00085 
00086 /*
00087  *  MAC address output function.  Fixed format.
00088  */
00089 
00090 Datum
00091 macaddr_out(PG_FUNCTION_ARGS)
00092 {
00093     macaddr    *addr = PG_GETARG_MACADDR_P(0);
00094     char       *result;
00095 
00096     result = (char *) palloc(32);
00097 
00098     snprintf(result, 32, "%02x:%02x:%02x:%02x:%02x:%02x",
00099              addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
00100 
00101     PG_RETURN_CSTRING(result);
00102 }
00103 
00104 /*
00105  *      macaddr_recv            - converts external binary format to macaddr
00106  *
00107  * The external representation is just the six bytes, MSB first.
00108  */
00109 Datum
00110 macaddr_recv(PG_FUNCTION_ARGS)
00111 {
00112     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00113     macaddr    *addr;
00114 
00115     addr = (macaddr *) palloc(sizeof(macaddr));
00116 
00117     addr->a = pq_getmsgbyte(buf);
00118     addr->b = pq_getmsgbyte(buf);
00119     addr->c = pq_getmsgbyte(buf);
00120     addr->d = pq_getmsgbyte(buf);
00121     addr->e = pq_getmsgbyte(buf);
00122     addr->f = pq_getmsgbyte(buf);
00123 
00124     PG_RETURN_MACADDR_P(addr);
00125 }
00126 
00127 /*
00128  *      macaddr_send            - converts macaddr to binary format
00129  */
00130 Datum
00131 macaddr_send(PG_FUNCTION_ARGS)
00132 {
00133     macaddr    *addr = PG_GETARG_MACADDR_P(0);
00134     StringInfoData buf;
00135 
00136     pq_begintypsend(&buf);
00137     pq_sendbyte(&buf, addr->a);
00138     pq_sendbyte(&buf, addr->b);
00139     pq_sendbyte(&buf, addr->c);
00140     pq_sendbyte(&buf, addr->d);
00141     pq_sendbyte(&buf, addr->e);
00142     pq_sendbyte(&buf, addr->f);
00143     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00144 }
00145 
00146 
00147 /*
00148  *  Comparison function for sorting:
00149  */
00150 
00151 static int32
00152 macaddr_cmp_internal(macaddr *a1, macaddr *a2)
00153 {
00154     if (hibits(a1) < hibits(a2))
00155         return -1;
00156     else if (hibits(a1) > hibits(a2))
00157         return 1;
00158     else if (lobits(a1) < lobits(a2))
00159         return -1;
00160     else if (lobits(a1) > lobits(a2))
00161         return 1;
00162     else
00163         return 0;
00164 }
00165 
00166 Datum
00167 macaddr_cmp(PG_FUNCTION_ARGS)
00168 {
00169     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
00170     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
00171 
00172     PG_RETURN_INT32(macaddr_cmp_internal(a1, a2));
00173 }
00174 
00175 /*
00176  *  Boolean comparisons.
00177  */
00178 
00179 Datum
00180 macaddr_lt(PG_FUNCTION_ARGS)
00181 {
00182     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
00183     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
00184 
00185     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) < 0);
00186 }
00187 
00188 Datum
00189 macaddr_le(PG_FUNCTION_ARGS)
00190 {
00191     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
00192     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
00193 
00194     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) <= 0);
00195 }
00196 
00197 Datum
00198 macaddr_eq(PG_FUNCTION_ARGS)
00199 {
00200     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
00201     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
00202 
00203     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) == 0);
00204 }
00205 
00206 Datum
00207 macaddr_ge(PG_FUNCTION_ARGS)
00208 {
00209     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
00210     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
00211 
00212     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) >= 0);
00213 }
00214 
00215 Datum
00216 macaddr_gt(PG_FUNCTION_ARGS)
00217 {
00218     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
00219     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
00220 
00221     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) > 0);
00222 }
00223 
00224 Datum
00225 macaddr_ne(PG_FUNCTION_ARGS)
00226 {
00227     macaddr    *a1 = PG_GETARG_MACADDR_P(0);
00228     macaddr    *a2 = PG_GETARG_MACADDR_P(1);
00229 
00230     PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) != 0);
00231 }
00232 
00233 /*
00234  * Support function for hash indexes on macaddr.
00235  */
00236 Datum
00237 hashmacaddr(PG_FUNCTION_ARGS)
00238 {
00239     macaddr    *key = PG_GETARG_MACADDR_P(0);
00240 
00241     return hash_any((unsigned char *) key, sizeof(macaddr));
00242 }
00243 
00244 /*
00245  * Arithmetic functions: bitwise NOT, AND, OR.
00246  */
00247 Datum
00248 macaddr_not(PG_FUNCTION_ARGS)
00249 {
00250     macaddr    *addr = PG_GETARG_MACADDR_P(0);
00251     macaddr    *result;
00252 
00253     result = (macaddr *) palloc(sizeof(macaddr));
00254     result->a = ~addr->a;
00255     result->b = ~addr->b;
00256     result->c = ~addr->c;
00257     result->d = ~addr->d;
00258     result->e = ~addr->e;
00259     result->f = ~addr->f;
00260     PG_RETURN_MACADDR_P(result);
00261 }
00262 
00263 Datum
00264 macaddr_and(PG_FUNCTION_ARGS)
00265 {
00266     macaddr    *addr1 = PG_GETARG_MACADDR_P(0);
00267     macaddr    *addr2 = PG_GETARG_MACADDR_P(1);
00268     macaddr    *result;
00269 
00270     result = (macaddr *) palloc(sizeof(macaddr));
00271     result->a = addr1->a & addr2->a;
00272     result->b = addr1->b & addr2->b;
00273     result->c = addr1->c & addr2->c;
00274     result->d = addr1->d & addr2->d;
00275     result->e = addr1->e & addr2->e;
00276     result->f = addr1->f & addr2->f;
00277     PG_RETURN_MACADDR_P(result);
00278 }
00279 
00280 Datum
00281 macaddr_or(PG_FUNCTION_ARGS)
00282 {
00283     macaddr    *addr1 = PG_GETARG_MACADDR_P(0);
00284     macaddr    *addr2 = PG_GETARG_MACADDR_P(1);
00285     macaddr    *result;
00286 
00287     result = (macaddr *) palloc(sizeof(macaddr));
00288     result->a = addr1->a | addr2->a;
00289     result->b = addr1->b | addr2->b;
00290     result->c = addr1->c | addr2->c;
00291     result->d = addr1->d | addr2->d;
00292     result->e = addr1->e | addr2->e;
00293     result->f = addr1->f | addr2->f;
00294     PG_RETURN_MACADDR_P(result);
00295 }
00296 
00297 /*
00298  *  Truncation function to allow comparing mac manufacturers.
00299  *  From suggestion by Alex Pilosov <[email protected]>
00300  */
00301 Datum
00302 macaddr_trunc(PG_FUNCTION_ARGS)
00303 {
00304     macaddr    *addr = PG_GETARG_MACADDR_P(0);
00305     macaddr    *result;
00306 
00307     result = (macaddr *) palloc(sizeof(macaddr));
00308 
00309     result->a = addr->a;
00310     result->b = addr->b;
00311     result->c = addr->c;
00312     result->d = 0;
00313     result->e = 0;
00314     result->f = 0;
00315 
00316     PG_RETURN_MACADDR_P(result);
00317 }