libnl  3.2.3
/build/buildd/libnl3-3.2.3/lib/utils.c
00001 /*
00002  * lib/utils.c          Utility Functions
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup core
00014  * @defgroup utils Utilities
00015  * @{
00016  */
00017 
00018 #include <netlink-local.h>
00019 #include <netlink/netlink.h>
00020 #include <netlink/utils.h>
00021 #include <linux/socket.h>
00022 
00023 /**
00024  * Debug level
00025  */
00026 int nl_debug = 0;
00027 
00028 struct nl_dump_params nl_debug_dp = {
00029         .dp_type = NL_DUMP_DETAILS,
00030 };
00031 
00032 static void __init nl_debug_init(void)
00033 {
00034         char *nldbg, *end;
00035         
00036         if ((nldbg = getenv("NLDBG"))) {
00037                 long level = strtol(nldbg, &end, 0);
00038                 if (nldbg != end)
00039                         nl_debug = level;
00040         }
00041 
00042         nl_debug_dp.dp_fd = stderr;
00043 }
00044 
00045 int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
00046 {
00047         FILE *fd;
00048         char buf[128];
00049 
00050         fd = fopen(path, "r");
00051         if (fd == NULL)
00052                 return -nl_syserr2nlerr(errno);
00053 
00054         while (fgets(buf, sizeof(buf), fd)) {
00055                 int goodlen, err;
00056                 long num;
00057                 char *end;
00058 
00059                 if (*buf == '#' || *buf == '\n' || *buf == '\r')
00060                         continue;
00061 
00062                 num = strtol(buf, &end, 0);
00063                 if (end == buf)
00064                         return -NLE_INVAL;
00065 
00066                 if (num == LONG_MIN || num == LONG_MAX)
00067                         return -NLE_RANGE;
00068 
00069                 while (*end == ' ' || *end == '\t')
00070                         end++;
00071 
00072                 goodlen = strcspn(end, "#\r\n\t ");
00073                 if (goodlen == 0)
00074                         return -NLE_INVAL;
00075 
00076                 end[goodlen] = '\0';
00077 
00078                 err = cb(num, end);
00079                 if (err < 0)
00080                         return err;
00081         }
00082 
00083         fclose(fd);
00084 
00085         return 0;
00086 }
00087 
00088 /**
00089  * @name Unit Pretty-Printing
00090  * @{
00091  */
00092 
00093 /**
00094  * Cancel down a byte counter
00095  * @arg l               byte counter
00096  * @arg unit            destination unit pointer
00097  *
00098  * Cancels down a byte counter until it reaches a reasonable
00099  * unit. The chosen unit is assigned to \a unit.
00100  * 
00101  * @return The cancelled down byte counter in the new unit.
00102  */
00103 double nl_cancel_down_bytes(unsigned long long l, char **unit)
00104 {
00105         if (l >= 1099511627776LL) {
00106                 *unit = "TiB";
00107                 return ((double) l) / 1099511627776LL;
00108         } else if (l >= 1073741824) {
00109                 *unit = "GiB";
00110                 return ((double) l) / 1073741824;
00111         } else if (l >= 1048576) {
00112                 *unit = "MiB";
00113                 return ((double) l) / 1048576;
00114         } else if (l >= 1024) {
00115                 *unit = "KiB";
00116                 return ((double) l) / 1024;
00117         } else {
00118                 *unit = "B";
00119                 return (double) l;
00120         }
00121 }
00122 
00123 /**
00124  * Cancel down a bit counter
00125  * @arg l               bit counter
00126  * @arg unit            destination unit pointer
00127  *
00128  * Cancels downa bit counter until it reaches a reasonable
00129  * unit. The chosen unit is assigned to \a unit.
00130  *
00131  * @return The cancelled down bit counter in the new unit.
00132  */
00133 double nl_cancel_down_bits(unsigned long long l, char **unit)
00134 {
00135         if (l >= 1099511627776ULL) {
00136                 *unit = "Tbit";
00137                 return ((double) l) / 1099511627776ULL;
00138         } else if (l >= 1073741824) {
00139                 *unit = "Gbit";
00140                 return ((double) l) / 1073741824;
00141         } else if (l >= 1048576) {
00142                 *unit = "Mbit";
00143                 return ((double) l) / 1048576;
00144         } else if (l >= 1024) {
00145                 *unit = "Kbit";
00146                 return ((double) l) / 1024;
00147         } else {
00148                 *unit = "bit";
00149                 return (double) l;
00150         }
00151                 
00152 }
00153 
00154 int nl_rate2str(unsigned long long rate, int type, char *buf, size_t len)
00155 {
00156         char *unit;
00157         double frac;
00158 
00159         switch (type) {
00160         case NL_BYTE_RATE:
00161                 frac = nl_cancel_down_bytes(rate, &unit);
00162                 break;
00163         
00164         case NL_BIT_RATE:
00165                 frac = nl_cancel_down_bits(rate, &unit);
00166                 break;
00167         
00168         default:
00169                 BUG();
00170         }
00171 
00172         return snprintf(buf, len, "%.2f%s/s", frac, unit);
00173 }
00174 
00175 /**
00176  * Cancel down a micro second value
00177  * @arg l               micro seconds
00178  * @arg unit            destination unit pointer
00179  *
00180  * Cancels down a microsecond counter until it reaches a
00181  * reasonable unit. The chosen unit is assigned to \a unit.
00182  *
00183  * @return The cancelled down microsecond in the new unit
00184  */
00185 double nl_cancel_down_us(uint32_t l, char **unit)
00186 {
00187         if (l >= 1000000) {
00188                 *unit = "s";
00189                 return ((double) l) / 1000000;
00190         } else if (l >= 1000) {
00191                 *unit = "ms";
00192                 return ((double) l) / 1000;
00193         } else {
00194                 *unit = "us";
00195                 return (double) l;
00196         }
00197 }
00198 
00199 /** @} */
00200 
00201 /**
00202  * @name Generic Unit Translations
00203  * @{
00204  */
00205 
00206 /**
00207  * Convert a character string to a size
00208  * @arg str             size encoded as character string
00209  *
00210  * Converts the specified size as character to the corresponding
00211  * number of bytes.
00212  *
00213  * Supported formats are:
00214  *  - b,kb/k,m/mb,gb/g for bytes
00215  *  - bit,kbit/mbit/gbit
00216  *
00217  * @return The number of bytes or -1 if the string is unparseable
00218  */
00219 long nl_size2int(const char *str)
00220 {
00221         char *p;
00222         long l = strtol(str, &p, 0);
00223         if (p == str)
00224                 return -NLE_INVAL;
00225 
00226         if (*p) {
00227                 if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
00228                         l *= 1024;
00229                 else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g"))
00230                         l *= 1024*1024*1024;
00231                 else if (!strcasecmp(p, "gbit"))
00232                         l *= 1024*1024*1024/8;
00233                 else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m"))
00234                         l *= 1024*1024;
00235                 else if (!strcasecmp(p, "mbit"))
00236                         l *= 1024*1024/8;
00237                 else if (!strcasecmp(p, "kbit"))
00238                         l *= 1024/8;
00239                 else if (!strcasecmp(p, "bit"))
00240                         l /= 8;
00241                 else if (strcasecmp(p, "b") != 0)
00242                         return -NLE_INVAL;
00243         }
00244 
00245         return l;
00246 }
00247 
00248 static const struct {
00249         double limit;
00250         const char *unit;
00251 } size_units[] = {
00252         { 1024. * 1024. * 1024. * 1024. * 1024., "EiB" },
00253         { 1024. * 1024. * 1024. * 1024., "TiB" },
00254         { 1024. * 1024. * 1024., "GiB" },
00255         { 1024. * 1024., "MiB" },
00256         { 1024., "KiB" },
00257         { 0., "B" },
00258 };
00259 
00260 /**
00261  * Convert a size toa character string
00262  * @arg size            Size in number of bytes
00263  * @arg buf             Buffer to write character string to
00264  * @arg len             Size of buf
00265  *
00266  * This function converts a value in bytes to a human readable representation
00267  * of it. The function uses IEC prefixes:
00268  *
00269  * @code
00270  * 1024 bytes => 1 KiB
00271  * 1048576 bytes => 1 MiB
00272  * @endcode
00273  *
00274  * The highest prefix is used which ensures a result of >= 1.0, the result
00275  * is provided as floating point number with a maximum precision of 2 digits:
00276  * @code
00277  * 965176 bytes => 942.55 KiB
00278  * @endcode
00279  *
00280  * @return pointer to buf
00281  */
00282 char *nl_size2str(const size_t size, char *buf, const size_t len)
00283 {
00284         int i;
00285 
00286         for (i = 0; i < ARRAY_SIZE(size_units); i++) {
00287                 if (size >= size_units[i].limit) {
00288                         snprintf(buf, len, "%.2g%s",
00289                                 (double) size / size_units[i].limit,
00290                                 size_units[i].unit);
00291                         return buf;
00292                 }
00293         }
00294 
00295         BUG();
00296 }
00297 
00298 /**
00299  * Convert a character string to a probability
00300  * @arg str             probability encoded as character string
00301  *
00302  * Converts the specified probability as character to the
00303  * corresponding probability number.
00304  *
00305  * Supported formats are:
00306  *  - 0.0-1.0
00307  *  - 0%-100%
00308  *
00309  * @return The probability relative to NL_PROB_MIN and NL_PROB_MAX
00310  */
00311 long nl_prob2int(const char *str)
00312 {
00313         char *p;
00314         double d = strtod(str, &p);
00315 
00316         if (p == str)
00317                 return -NLE_INVAL;
00318 
00319         if (d > 1.0)
00320                 d /= 100.0f;
00321 
00322         if (d > 1.0f || d < 0.0f)
00323                 return -NLE_RANGE;
00324 
00325         if (*p && strcmp(p, "%") != 0)
00326                 return -NLE_INVAL;
00327 
00328         return rint(d * NL_PROB_MAX);
00329 }
00330 
00331 /** @} */
00332 
00333 /**
00334  * @name Time Translations
00335  * @{
00336  */
00337 
00338 #ifdef USER_HZ
00339 static uint32_t user_hz = USER_HZ;
00340 #else
00341 static uint32_t user_hz = 100;
00342 #endif
00343 
00344 static double ticks_per_usec = 1.0f;
00345 
00346 /* Retrieves the configured HZ and ticks/us value in the kernel.
00347  * The value is cached. Supported ways of getting it:
00348  *
00349  * 1) environment variable
00350  * 2) /proc/net/psched and sysconf
00351  *
00352  * Supports the environment variables:
00353  *   PROC_NET_PSCHED  - may point to psched file in /proc
00354  *   PROC_ROOT        - may point to /proc fs */ 
00355 static void __init get_psched_settings(void)
00356 {
00357         char name[FILENAME_MAX];
00358         FILE *fd;
00359         int got_hz = 0;
00360 
00361         if (getenv("HZ")) {
00362                 long hz = strtol(getenv("HZ"), NULL, 0);
00363 
00364                 if (LONG_MIN != hz && LONG_MAX != hz) {
00365                         user_hz = hz;
00366                         got_hz = 1;
00367                 }
00368         }
00369 
00370         if (!got_hz)
00371                 user_hz = sysconf(_SC_CLK_TCK);
00372 
00373         if (getenv("TICKS_PER_USEC")) {
00374                 double t = strtod(getenv("TICKS_PER_USEC"), NULL);
00375                 ticks_per_usec = t;
00376         }
00377         else {
00378                 if (getenv("PROC_NET_PSCHED"))
00379                         snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED"));
00380                 else if (getenv("PROC_ROOT"))
00381                         snprintf(name, sizeof(name), "%s/net/psched",
00382                                  getenv("PROC_ROOT"));
00383                 else
00384                         strncpy(name, "/proc/net/psched", sizeof(name) - 1);
00385                 
00386                 if ((fd = fopen(name, "r"))) {
00387                         uint32_t ns_per_usec, ns_per_tick;
00388                         /* the file contains 4 hexadecimals, but we just use
00389                            the first two of them */
00390                         fscanf(fd, "%08x %08x", &ns_per_usec, &ns_per_tick);
00391 
00392                         ticks_per_usec = (double) ns_per_usec / 
00393                                          (double) ns_per_tick;
00394 
00395 
00396                         fclose(fd);
00397                 }
00398         }
00399 }
00400 
00401 
00402 /**
00403  * Return the value of HZ
00404  */
00405 int nl_get_user_hz(void)
00406 {
00407         return user_hz;
00408 }
00409 
00410 
00411 /**
00412  * Convert micro seconds to ticks
00413  * @arg us              micro seconds
00414  * @return number of ticks
00415  */
00416 uint32_t nl_us2ticks(uint32_t us)
00417 {
00418         return us * ticks_per_usec;
00419 }
00420 
00421 
00422 /**
00423  * Convert ticks to micro seconds
00424  * @arg ticks           number of ticks
00425  * @return microseconds
00426  */
00427 uint32_t nl_ticks2us(uint32_t ticks)
00428 {
00429         return ticks / ticks_per_usec;
00430 }
00431 
00432 int nl_str2msec(const char *str, uint64_t *result)
00433 {
00434         uint64_t total = 0, l;
00435         int plen;
00436         char *p;
00437 
00438         do {
00439                 l = strtoul(str, &p, 0);
00440                 if (p == str)
00441                         return -NLE_INVAL;
00442                 else if (*p) {
00443                         plen = strcspn(p, " \t");
00444 
00445                         if (!plen)
00446                                 total += l;
00447                         else if (!strncasecmp(p, "sec", plen))
00448                                 total += (l * 1000);
00449                         else if (!strncasecmp(p, "min", plen))
00450                                 total += (l * 1000*60);
00451                         else if (!strncasecmp(p, "hour", plen))
00452                                 total += (l * 1000*60*60);
00453                         else if (!strncasecmp(p, "day", plen))
00454                                 total += (l * 1000*60*60*24);
00455                         else
00456                                 return -NLE_INVAL;
00457 
00458                         str = p + plen;
00459                 } else
00460                         total += l;
00461         } while (*str && *p);
00462 
00463         *result = total;
00464 
00465         return 0;
00466 }
00467 
00468 /**
00469  * Convert milliseconds to a character string
00470  * @arg msec            number of milliseconds
00471  * @arg buf             destination buffer
00472  * @arg len             buffer length
00473  *
00474  * Converts milliseconds to a character string split up in days, hours,
00475  * minutes, seconds, and milliseconds and stores it in the specified
00476  * destination buffer.
00477  *
00478  * @return The destination buffer.
00479  */
00480 char * nl_msec2str(uint64_t msec, char *buf, size_t len)
00481 {
00482         int i, split[5];
00483         char *units[] = {"d", "h", "m", "s", "msec"};
00484 
00485 #define _SPLIT(idx, unit) if ((split[idx] = msec / unit) > 0) msec %= unit
00486         _SPLIT(0, 86400000);    /* days */
00487         _SPLIT(1, 3600000);     /* hours */
00488         _SPLIT(2, 60000);       /* minutes */
00489         _SPLIT(3, 1000);        /* seconds */
00490 #undef  _SPLIT
00491         split[4] = msec;
00492 
00493         memset(buf, 0, len);
00494 
00495         for (i = 0; i < ARRAY_SIZE(split); i++) {
00496                 if (split[i] > 0) {
00497                         char t[64];
00498                         snprintf(t, sizeof(t), "%s%d%s",
00499                                  strlen(buf) ? " " : "", split[i], units[i]);
00500                         strncat(buf, t, len - strlen(buf) - 1);
00501                 }
00502         }
00503 
00504         return buf;
00505 }
00506 
00507 /** @} */
00508 
00509 /**
00510  * @name Netlink Family Translations
00511  * @{
00512  */
00513 
00514 static const struct trans_tbl nlfamilies[] = {
00515         __ADD(NETLINK_ROUTE,route)
00516         __ADD(NETLINK_USERSOCK,usersock)
00517         __ADD(NETLINK_FIREWALL,firewall)
00518         __ADD(NETLINK_INET_DIAG,inetdiag)
00519         __ADD(NETLINK_NFLOG,nflog)
00520         __ADD(NETLINK_XFRM,xfrm)
00521         __ADD(NETLINK_SELINUX,selinux)
00522         __ADD(NETLINK_ISCSI,iscsi)
00523         __ADD(NETLINK_AUDIT,audit)
00524         __ADD(NETLINK_FIB_LOOKUP,fib_lookup)
00525         __ADD(NETLINK_CONNECTOR,connector)
00526         __ADD(NETLINK_NETFILTER,netfilter)
00527         __ADD(NETLINK_IP6_FW,ip6_fw)
00528         __ADD(NETLINK_DNRTMSG,dnrtmsg)
00529         __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent)
00530         __ADD(NETLINK_GENERIC,generic)
00531         __ADD(NETLINK_SCSITRANSPORT,scsitransport)
00532         __ADD(NETLINK_ECRYPTFS,ecryptfs)
00533 };
00534 
00535 char * nl_nlfamily2str(int family, char *buf, size_t size)
00536 {
00537         return __type2str(family, buf, size, nlfamilies,
00538                           ARRAY_SIZE(nlfamilies));
00539 }
00540 
00541 int nl_str2nlfamily(const char *name)
00542 {
00543         return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies));
00544 }
00545 
00546 /**
00547  * @}
00548  */
00549 
00550 /**
00551  * @name Link Layer Protocol Translations
00552  * @{
00553  */
00554 
00555 static const struct trans_tbl llprotos[] = {
00556         {0, "generic"},
00557         __ADD(ARPHRD_ETHER,ether)
00558         __ADD(ARPHRD_EETHER,eether)
00559         __ADD(ARPHRD_AX25,ax25)
00560         __ADD(ARPHRD_PRONET,pronet)
00561         __ADD(ARPHRD_CHAOS,chaos)
00562         __ADD(ARPHRD_IEEE802,ieee802)
00563         __ADD(ARPHRD_ARCNET,arcnet)
00564         __ADD(ARPHRD_APPLETLK,atalk)
00565         __ADD(ARPHRD_DLCI,dlci)
00566         __ADD(ARPHRD_ATM,atm)
00567         __ADD(ARPHRD_METRICOM,metricom)
00568         __ADD(ARPHRD_IEEE1394,ieee1394)
00569 #ifdef ARPHRD_EUI64
00570         __ADD(ARPHRD_EUI64,eui64)
00571 #endif
00572         __ADD(ARPHRD_INFINIBAND,infiniband)
00573         __ADD(ARPHRD_SLIP,slip)
00574         __ADD(ARPHRD_CSLIP,cslip)
00575         __ADD(ARPHRD_SLIP6,slip6)
00576         __ADD(ARPHRD_CSLIP6,cslip6)
00577         __ADD(ARPHRD_RSRVD,rsrvd)
00578         __ADD(ARPHRD_ADAPT,adapt)
00579         __ADD(ARPHRD_ROSE,rose)
00580         __ADD(ARPHRD_X25,x25)
00581 #ifdef ARPHRD_HWX25
00582         __ADD(ARPHRD_HWX25,hwx25)
00583 #endif
00584         __ADD(ARPHRD_CAN,can)
00585         __ADD(ARPHRD_PPP,ppp)
00586         __ADD(ARPHRD_HDLC,hdlc)
00587         __ADD(ARPHRD_LAPB,lapb)
00588         __ADD(ARPHRD_DDCMP,ddcmp)
00589         __ADD(ARPHRD_RAWHDLC,rawhdlc)
00590         __ADD(ARPHRD_TUNNEL,ipip)
00591         __ADD(ARPHRD_TUNNEL6,tunnel6)
00592         __ADD(ARPHRD_FRAD,frad)
00593         __ADD(ARPHRD_SKIP,skip)
00594         __ADD(ARPHRD_LOOPBACK,loopback)
00595         __ADD(ARPHRD_LOCALTLK,localtlk)
00596         __ADD(ARPHRD_FDDI,fddi)
00597         __ADD(ARPHRD_BIF,bif)
00598         __ADD(ARPHRD_SIT,sit)
00599         __ADD(ARPHRD_IPDDP,ip/ddp)
00600         __ADD(ARPHRD_IPGRE,gre)
00601         __ADD(ARPHRD_PIMREG,pimreg)
00602         __ADD(ARPHRD_HIPPI,hippi)
00603         __ADD(ARPHRD_ASH,ash)
00604         __ADD(ARPHRD_ECONET,econet)
00605         __ADD(ARPHRD_IRDA,irda)
00606         __ADD(ARPHRD_FCPP,fcpp)
00607         __ADD(ARPHRD_FCAL,fcal)
00608         __ADD(ARPHRD_FCPL,fcpl)
00609         __ADD(ARPHRD_FCFABRIC,fcfb_0)
00610         __ADD(ARPHRD_FCFABRIC+1,fcfb_1)
00611         __ADD(ARPHRD_FCFABRIC+2,fcfb_2)
00612         __ADD(ARPHRD_FCFABRIC+3,fcfb_3)
00613         __ADD(ARPHRD_FCFABRIC+4,fcfb_4)
00614         __ADD(ARPHRD_FCFABRIC+5,fcfb_5)
00615         __ADD(ARPHRD_FCFABRIC+6,fcfb_6)
00616         __ADD(ARPHRD_FCFABRIC+7,fcfb_7)
00617         __ADD(ARPHRD_FCFABRIC+8,fcfb_8)
00618         __ADD(ARPHRD_FCFABRIC+9,fcfb_9)
00619         __ADD(ARPHRD_FCFABRIC+10,fcfb_10)
00620         __ADD(ARPHRD_FCFABRIC+11,fcfb_11)
00621         __ADD(ARPHRD_FCFABRIC+12,fcfb_12)
00622         __ADD(ARPHRD_IEEE802_TR,tr)
00623         __ADD(ARPHRD_IEEE80211,ieee802.11)
00624         __ADD(ARPHRD_PHONET,phonet)
00625         __ADD(ARPHRD_CAIF, caif)
00626 #ifdef ARPHRD_IEEE80211_PRISM
00627         __ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism)
00628 #endif
00629 #ifdef ARPHRD_VOID
00630         __ADD(ARPHRD_VOID,void)
00631 #endif
00632 #ifdef ARPHRD_NONE
00633         __ADD(ARPHRD_NONE,nohdr)
00634 #endif
00635 };
00636 
00637 char * nl_llproto2str(int llproto, char *buf, size_t len)
00638 {
00639         return __type2str(llproto, buf, len, llprotos, ARRAY_SIZE(llprotos));
00640 }
00641 
00642 int nl_str2llproto(const char *name)
00643 {
00644         return __str2type(name, llprotos, ARRAY_SIZE(llprotos));
00645 }
00646 
00647 /** @} */
00648 
00649 
00650 /**
00651  * @name Ethernet Protocol Translations
00652  * @{
00653  */
00654 
00655 static const struct trans_tbl ether_protos[] = {
00656         __ADD(ETH_P_LOOP,loop)
00657         __ADD(ETH_P_PUP,pup)
00658         __ADD(ETH_P_PUPAT,pupat)
00659         __ADD(ETH_P_IP,ip)
00660         __ADD(ETH_P_X25,x25)
00661         __ADD(ETH_P_ARP,arp)
00662         __ADD(ETH_P_BPQ,bpq)
00663         __ADD(ETH_P_IEEEPUP,ieeepup)
00664         __ADD(ETH_P_IEEEPUPAT,ieeepupat)
00665         __ADD(ETH_P_DEC,dec)
00666         __ADD(ETH_P_DNA_DL,dna_dl)
00667         __ADD(ETH_P_DNA_RC,dna_rc)
00668         __ADD(ETH_P_DNA_RT,dna_rt)
00669         __ADD(ETH_P_LAT,lat)
00670         __ADD(ETH_P_DIAG,diag)
00671         __ADD(ETH_P_CUST,cust)
00672         __ADD(ETH_P_SCA,sca)
00673         __ADD(ETH_P_TEB,teb)
00674         __ADD(ETH_P_RARP,rarp)
00675         __ADD(ETH_P_ATALK,atalk)
00676         __ADD(ETH_P_AARP,aarp)
00677 #ifdef ETH_P_8021Q
00678         __ADD(ETH_P_8021Q,802.1q)
00679 #endif
00680         __ADD(ETH_P_IPX,ipx)
00681         __ADD(ETH_P_IPV6,ipv6)
00682         __ADD(ETH_P_PAUSE,pause)
00683         __ADD(ETH_P_SLOW,slow)
00684 #ifdef ETH_P_WCCP
00685         __ADD(ETH_P_WCCP,wccp)
00686 #endif
00687         __ADD(ETH_P_PPP_DISC,ppp_disc)
00688         __ADD(ETH_P_PPP_SES,ppp_ses)
00689         __ADD(ETH_P_MPLS_UC,mpls_uc)
00690         __ADD(ETH_P_MPLS_MC,mpls_mc)
00691         __ADD(ETH_P_ATMMPOA,atmmpoa)
00692         __ADD(ETH_P_LINK_CTL,link_ctl)
00693         __ADD(ETH_P_ATMFATE,atmfate)
00694         __ADD(ETH_P_PAE,pae)
00695         __ADD(ETH_P_AOE,aoe)
00696         __ADD(ETH_P_TIPC,tipc)
00697         __ADD(ETH_P_1588,ieee1588)
00698         __ADD(ETH_P_FCOE,fcoe)
00699         __ADD(ETH_P_FIP,fip)
00700         __ADD(ETH_P_EDSA,edsa)
00701         __ADD(ETH_P_EDP2,edp2)
00702         __ADD(ETH_P_802_3,802.3)
00703         __ADD(ETH_P_AX25,ax25)
00704         __ADD(ETH_P_ALL,all)
00705         __ADD(ETH_P_802_2,802.2)
00706         __ADD(ETH_P_SNAP,snap)
00707         __ADD(ETH_P_DDCMP,ddcmp)
00708         __ADD(ETH_P_WAN_PPP,wan_ppp)
00709         __ADD(ETH_P_PPP_MP,ppp_mp)
00710         __ADD(ETH_P_LOCALTALK,localtalk)
00711         __ADD(ETH_P_CAN,can)
00712         __ADD(ETH_P_PPPTALK,ppptalk)
00713         __ADD(ETH_P_TR_802_2,tr_802.2)
00714         __ADD(ETH_P_MOBITEX,mobitex)
00715         __ADD(ETH_P_CONTROL,control)
00716         __ADD(ETH_P_IRDA,irda)
00717         __ADD(ETH_P_ECONET,econet)
00718         __ADD(ETH_P_HDLC,hdlc)
00719         __ADD(ETH_P_ARCNET,arcnet)
00720         __ADD(ETH_P_DSA,dsa)
00721         __ADD(ETH_P_TRAILER,trailer)
00722         __ADD(ETH_P_PHONET,phonet)
00723         __ADD(ETH_P_IEEE802154,ieee802154)
00724         __ADD(ETH_P_CAIF,caif)
00725 };
00726 
00727 char *nl_ether_proto2str(int eproto, char *buf, size_t len)
00728 {
00729         return __type2str(eproto, buf, len, ether_protos,
00730                             ARRAY_SIZE(ether_protos));
00731 }
00732 
00733 int nl_str2ether_proto(const char *name)
00734 {
00735         return __str2type(name, ether_protos, ARRAY_SIZE(ether_protos));
00736 }
00737 
00738 /** @} */
00739 
00740 /**
00741  * @name IP Protocol Translations
00742  * @{
00743  */
00744 
00745 char *nl_ip_proto2str(int proto, char *buf, size_t len)
00746 {
00747         struct protoent *p = getprotobynumber(proto);
00748 
00749         if (p) {
00750                 snprintf(buf, len, "%s", p->p_name);
00751                 return buf;
00752         }
00753 
00754         snprintf(buf, len, "0x%x", proto);
00755         return buf;
00756 }
00757 
00758 int nl_str2ip_proto(const char *name)
00759 {
00760         struct protoent *p = getprotobyname(name);
00761         unsigned long l;
00762         char *end;
00763 
00764         if (p)
00765                 return p->p_proto;
00766 
00767         l = strtoul(name, &end, 0);
00768         if (l == ULONG_MAX || *end != '\0')
00769                 return -NLE_OBJ_NOTFOUND;
00770 
00771         return (int) l;
00772 }
00773 
00774 /** @} */
00775 
00776 /**
00777  * @name Dumping Helpers
00778  * @{
00779  */
00780 
00781 /**
00782  * Handle a new line while dumping
00783  * @arg params          Dumping parameters
00784  *
00785  * This function must be called before dumping any onto a
00786  * new line. It will ensure proper prefixing as specified
00787  * by the dumping parameters.
00788  *
00789  * @note This function will NOT dump any newlines itself
00790  */
00791 void nl_new_line(struct nl_dump_params *params)
00792 {
00793         params->dp_line++;
00794 
00795         if (params->dp_prefix) {
00796                 int i;
00797                 for (i = 0; i < params->dp_prefix; i++) {
00798                         if (params->dp_fd)
00799                                 fprintf(params->dp_fd, " ");
00800                         else if (params->dp_buf)
00801                                 strncat(params->dp_buf, " ",
00802                                         params->dp_buflen -
00803                                         sizeof(params->dp_buf) - 1);
00804                 }
00805         }
00806 
00807         if (params->dp_nl_cb)
00808                 params->dp_nl_cb(params, params->dp_line);
00809 }
00810 
00811 static void dump_one(struct nl_dump_params *parms, const char *fmt,
00812                      va_list args)
00813 {
00814         if (parms->dp_fd)
00815                 vfprintf(parms->dp_fd, fmt, args);
00816         else if (parms->dp_buf || parms->dp_cb) {
00817                 char *buf = NULL;
00818                 if (vasprintf(&buf, fmt, args) >= 0) {
00819                         if (parms->dp_cb)
00820                                 parms->dp_cb(parms, buf);
00821                         else
00822                                 strncat(parms->dp_buf, buf,
00823                                         parms->dp_buflen - strlen(parms->dp_buf) - 1);
00824                         free(buf);
00825                 }
00826         }
00827 }
00828 
00829 
00830 /**
00831  * Dump a formatted character string
00832  * @arg params          Dumping parameters
00833  * @arg fmt             printf style formatting string
00834  * @arg ...             Arguments to formatting string
00835  *
00836  * Dumps a printf style formatting string to the output device
00837  * as specified by the dumping parameters.
00838  */
00839 void nl_dump(struct nl_dump_params *params, const char *fmt, ...)
00840 {
00841         va_list args;
00842 
00843         va_start(args, fmt);
00844         dump_one(params, fmt, args);
00845         va_end(args);
00846 }
00847 
00848 void nl_dump_line(struct nl_dump_params *parms, const char *fmt, ...)
00849 {
00850         va_list args;
00851 
00852         nl_new_line(parms);
00853 
00854         va_start(args, fmt);
00855         dump_one(parms, fmt, args);
00856         va_end(args);
00857 }
00858 
00859 
00860 /** @} */
00861 
00862 /** @cond SKIP */
00863 
00864 int __trans_list_add(int i, const char *a, struct nl_list_head *head)
00865 {
00866         struct trans_list *tl;
00867 
00868         tl = calloc(1, sizeof(*tl));
00869         if (!tl)
00870                 return -NLE_NOMEM;
00871 
00872         tl->i = i;
00873         tl->a = strdup(a);
00874 
00875         nl_list_add_tail(&tl->list, head);
00876 
00877         return 0;
00878 }
00879 
00880 void __trans_list_clear(struct nl_list_head *head)
00881 {
00882         struct trans_list *tl, *next;
00883 
00884         nl_list_for_each_entry_safe(tl, next, head, list) {
00885                 free(tl->a);
00886                 free(tl);
00887         }
00888 
00889         nl_init_list_head(head);
00890 }
00891 
00892 char *__type2str(int type, char *buf, size_t len,
00893                  const struct trans_tbl *tbl, size_t tbl_len)
00894 {
00895         int i;
00896         for (i = 0; i < tbl_len; i++) {
00897                 if (tbl[i].i == type) {
00898                         snprintf(buf, len, "%s", tbl[i].a);
00899                         return buf;
00900                 }
00901         }
00902 
00903         snprintf(buf, len, "0x%x", type);
00904         return buf;
00905 }
00906 
00907 char *__list_type2str(int type, char *buf, size_t len,
00908                       struct nl_list_head *head)
00909 {
00910         struct trans_list *tl;
00911 
00912         nl_list_for_each_entry(tl, head, list) {
00913                 if (tl->i == type) {
00914                         snprintf(buf, len, "%s", tl->a);
00915                         return buf;
00916                 }
00917         }
00918 
00919         snprintf(buf, len, "0x%x", type);
00920         return buf;
00921 }
00922 
00923 char *__flags2str(int flags, char *buf, size_t len,
00924                   const struct trans_tbl *tbl, size_t tbl_len)
00925 {
00926         int i;
00927         int tmp = flags;
00928 
00929         memset(buf, 0, len);
00930         
00931         for (i = 0; i < tbl_len; i++) {
00932                 if (tbl[i].i & tmp) {
00933                         tmp &= ~tbl[i].i;
00934                         strncat(buf, tbl[i].a, len - strlen(buf) - 1);
00935                         if ((tmp & flags))
00936                                 strncat(buf, ",", len - strlen(buf) - 1);
00937                 }
00938         }
00939 
00940         return buf;
00941 }
00942 
00943 int __str2type(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
00944 {
00945         unsigned long l;
00946         char *end;
00947         int i;
00948 
00949         if (*buf == '\0')
00950                 return -NLE_INVAL;
00951 
00952         for (i = 0; i < tbl_len; i++)
00953                 if (!strcasecmp(tbl[i].a, buf))
00954                         return tbl[i].i;
00955 
00956         l = strtoul(buf, &end, 0);
00957         if (l == ULONG_MAX || *end != '\0')
00958                 return -NLE_OBJ_NOTFOUND;
00959 
00960         return (int) l;
00961 }
00962 
00963 int __list_str2type(const char *buf, struct nl_list_head *head)
00964 {
00965         struct trans_list *tl;
00966         unsigned long l;
00967         char *end;
00968 
00969         if (*buf == '\0')
00970                 return -NLE_INVAL;
00971 
00972         nl_list_for_each_entry(tl, head, list) {
00973                 if (!strcasecmp(tl->a, buf))
00974                         return tl->i;
00975         }
00976 
00977         l = strtoul(buf, &end, 0);
00978         if (l == ULONG_MAX || *end != '\0')
00979                 return -NLE_OBJ_NOTFOUND;
00980 
00981         return (int) l;
00982 }
00983 
00984 int __str2flags(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
00985 {
00986         int i, flags = 0, len;
00987         char *p = (char *) buf, *t;
00988 
00989         for (;;) {
00990                 if (*p == ' ')
00991                         p++;
00992         
00993                 t = strchr(p, ',');
00994                 len = t ? t - p : strlen(p);
00995                 for (i = 0; i < tbl_len; i++)
00996                         if (!strncasecmp(tbl[i].a, p, len))
00997                                 flags |= tbl[i].i;
00998 
00999                 if (!t)
01000                         return flags;
01001 
01002                 p = ++t;
01003         }
01004 
01005         return 0;
01006 }
01007 
01008 void dump_from_ops(struct nl_object *obj, struct nl_dump_params *params)
01009 {
01010         int type = params->dp_type;
01011 
01012         if (type < 0 || type > NL_DUMP_MAX)
01013                 BUG();
01014 
01015         params->dp_line = 0;
01016 
01017         if (params->dp_dump_msgtype) {
01018 #if 0
01019                 /* XXX */
01020                 char buf[64];
01021 
01022                 dp_dump_line(params, 0, "%s ",
01023                              nl_cache_mngt_type2name(obj->ce_ops,
01024                                                      obj->ce_ops->co_protocol,
01025                                                      obj->ce_msgtype,
01026                                                      buf, sizeof(buf)));
01027 #endif
01028                 params->dp_pre_dump = 1;
01029         }
01030 
01031         if (params->dp_buf)
01032                 memset(params->dp_buf, 0, params->dp_buflen);
01033 
01034         if (obj->ce_ops->oo_dump[type])
01035                 obj->ce_ops->oo_dump[type](obj, params);
01036 }
01037 
01038 /** @endcond */
01039 
01040 /** @} */