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