libnl
3.2.3
|
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 /** @} */