libnl  3.2.7
utils.c
1 /*
2  * lib/utils.c Utility Functions
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup core
14  * @defgroup utils Utilities
15  * @{
16  */
17 
18 #include <netlink-local.h>
19 #include <netlink/netlink.h>
20 #include <netlink/utils.h>
21 #include <linux/socket.h>
22 
23 /**
24  * Debug level
25  */
26 int nl_debug = 0;
27 
28 struct nl_dump_params nl_debug_dp = {
30 };
31 
32 static void __init nl_debug_init(void)
33 {
34  char *nldbg, *end;
35 
36  if ((nldbg = getenv("NLDBG"))) {
37  long level = strtol(nldbg, &end, 0);
38  if (nldbg != end)
39  nl_debug = level;
40  }
41 
42  nl_debug_dp.dp_fd = stderr;
43 }
44 
45 int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
46 {
47  FILE *fd;
48  char buf[128];
49 
50  fd = fopen(path, "r");
51  if (fd == NULL)
52  return -nl_syserr2nlerr(errno);
53 
54  while (fgets(buf, sizeof(buf), fd)) {
55  int goodlen, err;
56  long num;
57  char *end;
58 
59  if (*buf == '#' || *buf == '\n' || *buf == '\r')
60  continue;
61 
62  num = strtol(buf, &end, 0);
63  if (end == buf)
64  return -NLE_INVAL;
65 
66  if (num == LONG_MIN || num == LONG_MAX)
67  return -NLE_RANGE;
68 
69  while (*end == ' ' || *end == '\t')
70  end++;
71 
72  goodlen = strcspn(end, "#\r\n\t ");
73  if (goodlen == 0)
74  return -NLE_INVAL;
75 
76  end[goodlen] = '\0';
77 
78  err = cb(num, end);
79  if (err < 0)
80  return err;
81  }
82 
83  fclose(fd);
84 
85  return 0;
86 }
87 
88 /**
89  * @name Unit Pretty-Printing
90  * @{
91  */
92 
93 /**
94  * Cancel down a byte counter
95  * @arg l byte counter
96  * @arg unit destination unit pointer
97  *
98  * Cancels down a byte counter until it reaches a reasonable
99  * unit. The chosen unit is assigned to \a unit.
100  *
101  * @return The cancelled down byte counter in the new unit.
102  */
103 double nl_cancel_down_bytes(unsigned long long l, char **unit)
104 {
105  if (l >= 1099511627776LL) {
106  *unit = "TiB";
107  return ((double) l) / 1099511627776LL;
108  } else if (l >= 1073741824) {
109  *unit = "GiB";
110  return ((double) l) / 1073741824;
111  } else if (l >= 1048576) {
112  *unit = "MiB";
113  return ((double) l) / 1048576;
114  } else if (l >= 1024) {
115  *unit = "KiB";
116  return ((double) l) / 1024;
117  } else {
118  *unit = "B";
119  return (double) l;
120  }
121 }
122 
123 /**
124  * Cancel down a bit counter
125  * @arg l bit counter
126  * @arg unit destination unit pointer
127  *
128  * Cancels downa bit counter until it reaches a reasonable
129  * unit. The chosen unit is assigned to \a unit.
130  *
131  * @return The cancelled down bit counter in the new unit.
132  */
133 double nl_cancel_down_bits(unsigned long long l, char **unit)
134 {
135  if (l >= 1099511627776ULL) {
136  *unit = "Tbit";
137  return ((double) l) / 1099511627776ULL;
138  } else if (l >= 1073741824) {
139  *unit = "Gbit";
140  return ((double) l) / 1073741824;
141  } else if (l >= 1048576) {
142  *unit = "Mbit";
143  return ((double) l) / 1048576;
144  } else if (l >= 1024) {
145  *unit = "Kbit";
146  return ((double) l) / 1024;
147  } else {
148  *unit = "bit";
149  return (double) l;
150  }
151 
152 }
153 
154 int nl_rate2str(unsigned long long rate, int type, char *buf, size_t len)
155 {
156  char *unit;
157  double frac;
158 
159  switch (type) {
160  case NL_BYTE_RATE:
161  frac = nl_cancel_down_bytes(rate, &unit);
162  break;
163 
164  case NL_BIT_RATE:
165  frac = nl_cancel_down_bits(rate, &unit);
166  break;
167 
168  default:
169  BUG();
170  }
171 
172  return snprintf(buf, len, "%.2f%s/s", frac, unit);
173 }
174 
175 /**
176  * Cancel down a micro second value
177  * @arg l micro seconds
178  * @arg unit destination unit pointer
179  *
180  * Cancels down a microsecond counter until it reaches a
181  * reasonable unit. The chosen unit is assigned to \a unit.
182  *
183  * @return The cancelled down microsecond in the new unit
184  */
185 double nl_cancel_down_us(uint32_t l, char **unit)
186 {
187  if (l >= 1000000) {
188  *unit = "s";
189  return ((double) l) / 1000000;
190  } else if (l >= 1000) {
191  *unit = "ms";
192  return ((double) l) / 1000;
193  } else {
194  *unit = "us";
195  return (double) l;
196  }
197 }
198 
199 /** @} */
200 
201 /**
202  * @name Generic Unit Translations
203  * @{
204  */
205 
206 /**
207  * Convert a character string to a size
208  * @arg str size encoded as character string
209  *
210  * Converts the specified size as character to the corresponding
211  * number of bytes.
212  *
213  * Supported formats are:
214  * - b,kb/k,m/mb,gb/g for bytes
215  * - bit,kbit/mbit/gbit
216  *
217  * @return The number of bytes or -1 if the string is unparseable
218  */
219 long nl_size2int(const char *str)
220 {
221  char *p;
222  long l = strtol(str, &p, 0);
223  if (p == str)
224  return -NLE_INVAL;
225 
226  if (*p) {
227  if (!strcasecmp(p, "kb") || !strcasecmp(p, "k"))
228  l *= 1024;
229  else if (!strcasecmp(p, "gb") || !strcasecmp(p, "g"))
230  l *= 1024*1024*1024;
231  else if (!strcasecmp(p, "gbit"))
232  l *= 1024*1024*1024/8;
233  else if (!strcasecmp(p, "mb") || !strcasecmp(p, "m"))
234  l *= 1024*1024;
235  else if (!strcasecmp(p, "mbit"))
236  l *= 1024*1024/8;
237  else if (!strcasecmp(p, "kbit"))
238  l *= 1024/8;
239  else if (!strcasecmp(p, "bit"))
240  l /= 8;
241  else if (strcasecmp(p, "b") != 0)
242  return -NLE_INVAL;
243  }
244 
245  return l;
246 }
247 
248 static const struct {
249  double limit;
250  const char *unit;
251 } size_units[] = {
252  { 1024. * 1024. * 1024. * 1024. * 1024., "EiB" },
253  { 1024. * 1024. * 1024. * 1024., "TiB" },
254  { 1024. * 1024. * 1024., "GiB" },
255  { 1024. * 1024., "MiB" },
256  { 1024., "KiB" },
257  { 0., "B" },
258 };
259 
260 /**
261  * Convert a size toa character string
262  * @arg size Size in number of bytes
263  * @arg buf Buffer to write character string to
264  * @arg len Size of buf
265  *
266  * This function converts a value in bytes to a human readable representation
267  * of it. The function uses IEC prefixes:
268  *
269  * @code
270  * 1024 bytes => 1 KiB
271  * 1048576 bytes => 1 MiB
272  * @endcode
273  *
274  * The highest prefix is used which ensures a result of >= 1.0, the result
275  * is provided as floating point number with a maximum precision of 2 digits:
276  * @code
277  * 965176 bytes => 942.55 KiB
278  * @endcode
279  *
280  * @return pointer to buf
281  */
282 char *nl_size2str(const size_t size, char *buf, const size_t len)
283 {
284  int i;
285 
286  for (i = 0; i < ARRAY_SIZE(size_units); i++) {
287  if (size >= size_units[i].limit) {
288  snprintf(buf, len, "%.2g%s",
289  (double) size / size_units[i].limit,
290  size_units[i].unit);
291  return buf;
292  }
293  }
294 
295  BUG();
296 }
297 
298 /**
299  * Convert a character string to a probability
300  * @arg str probability encoded as character string
301  *
302  * Converts the specified probability as character to the
303  * corresponding probability number.
304  *
305  * Supported formats are:
306  * - 0.0-1.0
307  * - 0%-100%
308  *
309  * @return The probability relative to NL_PROB_MIN and NL_PROB_MAX
310  */
311 long nl_prob2int(const char *str)
312 {
313  char *p;
314  double d = strtod(str, &p);
315 
316  if (p == str)
317  return -NLE_INVAL;
318 
319  if (d > 1.0)
320  d /= 100.0f;
321 
322  if (d > 1.0f || d < 0.0f)
323  return -NLE_RANGE;
324 
325  if (*p && strcmp(p, "%") != 0)
326  return -NLE_INVAL;
327 
328  return rint(d * NL_PROB_MAX);
329 }
330 
331 /** @} */
332 
333 /**
334  * @name Time Translations
335  * @{
336  */
337 
338 #ifdef USER_HZ
339 static uint32_t user_hz = USER_HZ;
340 #else
341 static uint32_t user_hz = 100;
342 #endif
343 
344 static double ticks_per_usec = 1.0f;
345 
346 /* Retrieves the configured HZ and ticks/us value in the kernel.
347  * The value is cached. Supported ways of getting it:
348  *
349  * 1) environment variable
350  * 2) /proc/net/psched and sysconf
351  *
352  * Supports the environment variables:
353  * PROC_NET_PSCHED - may point to psched file in /proc
354  * PROC_ROOT - may point to /proc fs */
355 static void __init get_psched_settings(void)
356 {
357  char name[FILENAME_MAX];
358  FILE *fd;
359  int got_hz = 0;
360 
361  if (getenv("HZ")) {
362  long hz = strtol(getenv("HZ"), NULL, 0);
363 
364  if (LONG_MIN != hz && LONG_MAX != hz) {
365  user_hz = hz;
366  got_hz = 1;
367  }
368  }
369 
370  if (!got_hz)
371  user_hz = sysconf(_SC_CLK_TCK);
372 
373  if (getenv("TICKS_PER_USEC")) {
374  double t = strtod(getenv("TICKS_PER_USEC"), NULL);
375  ticks_per_usec = t;
376  }
377  else {
378  if (getenv("PROC_NET_PSCHED"))
379  snprintf(name, sizeof(name), "%s", getenv("PROC_NET_PSCHED"));
380  else if (getenv("PROC_ROOT"))
381  snprintf(name, sizeof(name), "%s/net/psched",
382  getenv("PROC_ROOT"));
383  else
384  strncpy(name, "/proc/net/psched", sizeof(name) - 1);
385 
386  if ((fd = fopen(name, "r"))) {
387  uint32_t ns_per_usec, ns_per_tick;
388  /* the file contains 4 hexadecimals, but we just use
389  the first two of them */
390  fscanf(fd, "%08x %08x", &ns_per_usec, &ns_per_tick);
391 
392  ticks_per_usec = (double) ns_per_usec /
393  (double) ns_per_tick;
394 
395 
396  fclose(fd);
397  }
398  }
399 }
400 
401 
402 /**
403  * Return the value of HZ
404  */
405 int nl_get_user_hz(void)
406 {
407  return user_hz;
408 }
409 
410 
411 /**
412  * Convert micro seconds to ticks
413  * @arg us micro seconds
414  * @return number of ticks
415  */
416 uint32_t nl_us2ticks(uint32_t us)
417 {
418  return us * ticks_per_usec;
419 }
420 
421 
422 /**
423  * Convert ticks to micro seconds
424  * @arg ticks number of ticks
425  * @return microseconds
426  */
427 uint32_t nl_ticks2us(uint32_t ticks)
428 {
429  return ticks / ticks_per_usec;
430 }
431 
432 int nl_str2msec(const char *str, uint64_t *result)
433 {
434  uint64_t total = 0, l;
435  int plen;
436  char *p;
437 
438  do {
439  l = strtoul(str, &p, 0);
440  if (p == str)
441  return -NLE_INVAL;
442  else if (*p) {
443  plen = strcspn(p, " \t");
444 
445  if (!plen)
446  total += l;
447  else if (!strncasecmp(p, "sec", plen))
448  total += (l * 1000);
449  else if (!strncasecmp(p, "min", plen))
450  total += (l * 1000*60);
451  else if (!strncasecmp(p, "hour", plen))
452  total += (l * 1000*60*60);
453  else if (!strncasecmp(p, "day", plen))
454  total += (l * 1000*60*60*24);
455  else
456  return -NLE_INVAL;
457 
458  str = p + plen;
459  } else
460  total += l;
461  } while (*str && *p);
462 
463  *result = total;
464 
465  return 0;
466 }
467 
468 /**
469  * Convert milliseconds to a character string
470  * @arg msec number of milliseconds
471  * @arg buf destination buffer
472  * @arg len buffer length
473  *
474  * Converts milliseconds to a character string split up in days, hours,
475  * minutes, seconds, and milliseconds and stores it in the specified
476  * destination buffer.
477  *
478  * @return The destination buffer.
479  */
480 char * nl_msec2str(uint64_t msec, char *buf, size_t len)
481 {
482  int i, split[5];
483  char *units[] = {"d", "h", "m", "s", "msec"};
484 
485 #define _SPLIT(idx, unit) if ((split[idx] = msec / unit) > 0) msec %= unit
486  _SPLIT(0, 86400000); /* days */
487  _SPLIT(1, 3600000); /* hours */
488  _SPLIT(2, 60000); /* minutes */
489  _SPLIT(3, 1000); /* seconds */
490 #undef _SPLIT
491  split[4] = msec;
492 
493  memset(buf, 0, len);
494 
495  for (i = 0; i < ARRAY_SIZE(split); i++) {
496  if (split[i] > 0) {
497  char t[64];
498  snprintf(t, sizeof(t), "%s%d%s",
499  strlen(buf) ? " " : "", split[i], units[i]);
500  strncat(buf, t, len - strlen(buf) - 1);
501  }
502  }
503 
504  return buf;
505 }
506 
507 /** @} */
508 
509 /**
510  * @name Netlink Family Translations
511  * @{
512  */
513 
514 static const struct trans_tbl nlfamilies[] = {
515  __ADD(NETLINK_ROUTE,route)
516  __ADD(NETLINK_USERSOCK,usersock)
517  __ADD(NETLINK_FIREWALL,firewall)
518  __ADD(NETLINK_INET_DIAG,inetdiag)
519  __ADD(NETLINK_NFLOG,nflog)
520  __ADD(NETLINK_XFRM,xfrm)
521  __ADD(NETLINK_SELINUX,selinux)
522  __ADD(NETLINK_ISCSI,iscsi)
523  __ADD(NETLINK_AUDIT,audit)
524  __ADD(NETLINK_FIB_LOOKUP,fib_lookup)
525  __ADD(NETLINK_CONNECTOR,connector)
526  __ADD(NETLINK_NETFILTER,netfilter)
527  __ADD(NETLINK_IP6_FW,ip6_fw)
528  __ADD(NETLINK_DNRTMSG,dnrtmsg)
529  __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent)
530  __ADD(NETLINK_GENERIC,generic)
531  __ADD(NETLINK_SCSITRANSPORT,scsitransport)
532  __ADD(NETLINK_ECRYPTFS,ecryptfs)
533 };
534 
535 char * nl_nlfamily2str(int family, char *buf, size_t size)
536 {
537  return __type2str(family, buf, size, nlfamilies,
538  ARRAY_SIZE(nlfamilies));
539 }
540 
541 int nl_str2nlfamily(const char *name)
542 {
543  return __str2type(name, nlfamilies, ARRAY_SIZE(nlfamilies));
544 }
545 
546 /**
547  * @}
548  */
549 
550 /**
551  * @name Link Layer Protocol Translations
552  * @{
553  */
554 
555 static const struct trans_tbl llprotos[] = {
556  {0, "generic"},
557  __ADD(ARPHRD_ETHER,ether)
558  __ADD(ARPHRD_EETHER,eether)
559  __ADD(ARPHRD_AX25,ax25)
560  __ADD(ARPHRD_PRONET,pronet)
561  __ADD(ARPHRD_CHAOS,chaos)
562  __ADD(ARPHRD_IEEE802,ieee802)
563  __ADD(ARPHRD_ARCNET,arcnet)
564  __ADD(ARPHRD_APPLETLK,atalk)
565  __ADD(ARPHRD_DLCI,dlci)
566  __ADD(ARPHRD_ATM,atm)
567  __ADD(ARPHRD_METRICOM,metricom)
568  __ADD(ARPHRD_IEEE1394,ieee1394)
569 #ifdef ARPHRD_EUI64
570  __ADD(ARPHRD_EUI64,eui64)
571 #endif
572  __ADD(ARPHRD_INFINIBAND,infiniband)
573  __ADD(ARPHRD_SLIP,slip)
574  __ADD(ARPHRD_CSLIP,cslip)
575  __ADD(ARPHRD_SLIP6,slip6)
576  __ADD(ARPHRD_CSLIP6,cslip6)
577  __ADD(ARPHRD_RSRVD,rsrvd)
578  __ADD(ARPHRD_ADAPT,adapt)
579  __ADD(ARPHRD_ROSE,rose)
580  __ADD(ARPHRD_X25,x25)
581 #ifdef ARPHRD_HWX25
582  __ADD(ARPHRD_HWX25,hwx25)
583 #endif
584  __ADD(ARPHRD_CAN,can)
585  __ADD(ARPHRD_PPP,ppp)
586  __ADD(ARPHRD_HDLC,hdlc)
587  __ADD(ARPHRD_LAPB,lapb)
588  __ADD(ARPHRD_DDCMP,ddcmp)
589  __ADD(ARPHRD_RAWHDLC,rawhdlc)
590  __ADD(ARPHRD_TUNNEL,ipip)
591  __ADD(ARPHRD_TUNNEL6,tunnel6)
592  __ADD(ARPHRD_FRAD,frad)
593  __ADD(ARPHRD_SKIP,skip)
594  __ADD(ARPHRD_LOOPBACK,loopback)
595  __ADD(ARPHRD_LOCALTLK,localtlk)
596  __ADD(ARPHRD_FDDI,fddi)
597  __ADD(ARPHRD_BIF,bif)
598  __ADD(ARPHRD_SIT,sit)
599  __ADD(ARPHRD_IPDDP,ip/ddp)
600  __ADD(ARPHRD_IPGRE,gre)
601  __ADD(ARPHRD_PIMREG,pimreg)
602  __ADD(ARPHRD_HIPPI,hippi)
603  __ADD(ARPHRD_ASH,ash)
604  __ADD(ARPHRD_ECONET,econet)
605  __ADD(ARPHRD_IRDA,irda)
606  __ADD(ARPHRD_FCPP,fcpp)
607  __ADD(ARPHRD_FCAL,fcal)
608  __ADD(ARPHRD_FCPL,fcpl)
609  __ADD(ARPHRD_FCFABRIC,fcfb_0)
610  __ADD(ARPHRD_FCFABRIC+1,fcfb_1)
611  __ADD(ARPHRD_FCFABRIC+2,fcfb_2)
612  __ADD(ARPHRD_FCFABRIC+3,fcfb_3)
613  __ADD(ARPHRD_FCFABRIC+4,fcfb_4)
614  __ADD(ARPHRD_FCFABRIC+5,fcfb_5)
615  __ADD(ARPHRD_FCFABRIC+6,fcfb_6)
616  __ADD(ARPHRD_FCFABRIC+7,fcfb_7)
617  __ADD(ARPHRD_FCFABRIC+8,fcfb_8)
618  __ADD(ARPHRD_FCFABRIC+9,fcfb_9)
619  __ADD(ARPHRD_FCFABRIC+10,fcfb_10)
620  __ADD(ARPHRD_FCFABRIC+11,fcfb_11)
621  __ADD(ARPHRD_FCFABRIC+12,fcfb_12)
622  __ADD(ARPHRD_IEEE802_TR,tr)
623  __ADD(ARPHRD_IEEE80211,ieee802.11)
624  __ADD(ARPHRD_PHONET,phonet)
625  __ADD(ARPHRD_CAIF, caif)
626 #ifdef ARPHRD_IEEE80211_PRISM
627  __ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism)
628 #endif
629 #ifdef ARPHRD_VOID
630  __ADD(ARPHRD_VOID,void)
631 #endif
632 #ifdef ARPHRD_NONE
633  __ADD(ARPHRD_NONE,nohdr)
634 #endif
635 };
636 
637 char * nl_llproto2str(int llproto, char *buf, size_t len)
638 {
639  return __type2str(llproto, buf, len, llprotos, ARRAY_SIZE(llprotos));
640 }
641 
642 int nl_str2llproto(const char *name)
643 {
644  return __str2type(name, llprotos, ARRAY_SIZE(llprotos));
645 }
646 
647 /** @} */
648 
649 
650 /**
651  * @name Ethernet Protocol Translations
652  * @{
653  */
654 
655 static const struct trans_tbl ether_protos[] = {
656  __ADD(ETH_P_LOOP,loop)
657  __ADD(ETH_P_PUP,pup)
658  __ADD(ETH_P_PUPAT,pupat)
659  __ADD(ETH_P_IP,ip)
660  __ADD(ETH_P_X25,x25)
661  __ADD(ETH_P_ARP,arp)
662  __ADD(ETH_P_BPQ,bpq)
663  __ADD(ETH_P_IEEEPUP,ieeepup)
664  __ADD(ETH_P_IEEEPUPAT,ieeepupat)
665  __ADD(ETH_P_DEC,dec)
666  __ADD(ETH_P_DNA_DL,dna_dl)
667  __ADD(ETH_P_DNA_RC,dna_rc)
668  __ADD(ETH_P_DNA_RT,dna_rt)
669  __ADD(ETH_P_LAT,lat)
670  __ADD(ETH_P_DIAG,diag)
671  __ADD(ETH_P_CUST,cust)
672  __ADD(ETH_P_SCA,sca)
673  __ADD(ETH_P_TEB,teb)
674  __ADD(ETH_P_RARP,rarp)
675  __ADD(ETH_P_ATALK,atalk)
676  __ADD(ETH_P_AARP,aarp)
677 #ifdef ETH_P_8021Q
678  __ADD(ETH_P_8021Q,802.1q)
679 #endif
680  __ADD(ETH_P_IPX,ipx)
681  __ADD(ETH_P_IPV6,ipv6)
682  __ADD(ETH_P_PAUSE,pause)
683  __ADD(ETH_P_SLOW,slow)
684 #ifdef ETH_P_WCCP
685  __ADD(ETH_P_WCCP,wccp)
686 #endif
687  __ADD(ETH_P_PPP_DISC,ppp_disc)
688  __ADD(ETH_P_PPP_SES,ppp_ses)
689  __ADD(ETH_P_MPLS_UC,mpls_uc)
690  __ADD(ETH_P_MPLS_MC,mpls_mc)
691  __ADD(ETH_P_ATMMPOA,atmmpoa)
692  __ADD(ETH_P_LINK_CTL,link_ctl)
693  __ADD(ETH_P_ATMFATE,atmfate)
694  __ADD(ETH_P_PAE,pae)
695  __ADD(ETH_P_AOE,aoe)
696  __ADD(ETH_P_TIPC,tipc)
697  __ADD(ETH_P_1588,ieee1588)
698  __ADD(ETH_P_FCOE,fcoe)
699  __ADD(ETH_P_FIP,fip)
700  __ADD(ETH_P_EDSA,edsa)
701  __ADD(ETH_P_EDP2,edp2)
702  __ADD(ETH_P_802_3,802.3)
703  __ADD(ETH_P_AX25,ax25)
704  __ADD(ETH_P_ALL,all)
705  __ADD(ETH_P_802_2,802.2)
706  __ADD(ETH_P_SNAP,snap)
707  __ADD(ETH_P_DDCMP,ddcmp)
708  __ADD(ETH_P_WAN_PPP,wan_ppp)
709  __ADD(ETH_P_PPP_MP,ppp_mp)
710  __ADD(ETH_P_LOCALTALK,localtalk)
711  __ADD(ETH_P_CAN,can)
712  __ADD(ETH_P_PPPTALK,ppptalk)
713  __ADD(ETH_P_TR_802_2,tr_802.2)
714  __ADD(ETH_P_MOBITEX,mobitex)
715  __ADD(ETH_P_CONTROL,control)
716  __ADD(ETH_P_IRDA,irda)
717  __ADD(ETH_P_ECONET,econet)
718  __ADD(ETH_P_HDLC,hdlc)
719  __ADD(ETH_P_ARCNET,arcnet)
720  __ADD(ETH_P_DSA,dsa)
721  __ADD(ETH_P_TRAILER,trailer)
722  __ADD(ETH_P_PHONET,phonet)
723  __ADD(ETH_P_IEEE802154,ieee802154)
724  __ADD(ETH_P_CAIF,caif)
725 };
726 
727 char *nl_ether_proto2str(int eproto, char *buf, size_t len)
728 {
729  return __type2str(eproto, buf, len, ether_protos,
730  ARRAY_SIZE(ether_protos));
731 }
732 
733 int nl_str2ether_proto(const char *name)
734 {
735  return __str2type(name, ether_protos, ARRAY_SIZE(ether_protos));
736 }
737 
738 /** @} */
739 
740 /**
741  * @name IP Protocol Translations
742  * @{
743  */
744 
745 char *nl_ip_proto2str(int proto, char *buf, size_t len)
746 {
747  struct protoent *p = getprotobynumber(proto);
748 
749  if (p) {
750  snprintf(buf, len, "%s", p->p_name);
751  return buf;
752  }
753 
754  snprintf(buf, len, "0x%x", proto);
755  return buf;
756 }
757 
758 int nl_str2ip_proto(const char *name)
759 {
760  struct protoent *p = getprotobyname(name);
761  unsigned long l;
762  char *end;
763 
764  if (p)
765  return p->p_proto;
766 
767  l = strtoul(name, &end, 0);
768  if (l == ULONG_MAX || *end != '\0')
769  return -NLE_OBJ_NOTFOUND;
770 
771  return (int) l;
772 }
773 
774 /** @} */
775 
776 /**
777  * @name Dumping Helpers
778  * @{
779  */
780 
781 /**
782  * Handle a new line while dumping
783  * @arg params Dumping parameters
784  *
785  * This function must be called before dumping any onto a
786  * new line. It will ensure proper prefixing as specified
787  * by the dumping parameters.
788  *
789  * @note This function will NOT dump any newlines itself
790  */
791 void nl_new_line(struct nl_dump_params *params)
792 {
793  params->dp_line++;
794 
795  if (params->dp_prefix) {
796  int i;
797  for (i = 0; i < params->dp_prefix; i++) {
798  if (params->dp_fd)
799  fprintf(params->dp_fd, " ");
800  else if (params->dp_buf)
801  strncat(params->dp_buf, " ",
802  params->dp_buflen -
803  sizeof(params->dp_buf) - 1);
804  }
805  }
806 
807  if (params->dp_nl_cb)
808  params->dp_nl_cb(params, params->dp_line);
809 }
810 
811 static void dump_one(struct nl_dump_params *parms, const char *fmt,
812  va_list args)
813 {
814  if (parms->dp_fd)
815  vfprintf(parms->dp_fd, fmt, args);
816  else if (parms->dp_buf || parms->dp_cb) {
817  char *buf = NULL;
818  if (vasprintf(&buf, fmt, args) >= 0) {
819  if (parms->dp_cb)
820  parms->dp_cb(parms, buf);
821  else
822  strncat(parms->dp_buf, buf,
823  parms->dp_buflen - strlen(parms->dp_buf) - 1);
824  free(buf);
825  }
826  }
827 }
828 
829 
830 /**
831  * Dump a formatted character string
832  * @arg params Dumping parameters
833  * @arg fmt printf style formatting string
834  * @arg ... Arguments to formatting string
835  *
836  * Dumps a printf style formatting string to the output device
837  * as specified by the dumping parameters.
838  */
839 void nl_dump(struct nl_dump_params *params, const char *fmt, ...)
840 {
841  va_list args;
842 
843  va_start(args, fmt);
844  dump_one(params, fmt, args);
845  va_end(args);
846 }
847 
848 void nl_dump_line(struct nl_dump_params *parms, const char *fmt, ...)
849 {
850  va_list args;
851 
852  nl_new_line(parms);
853 
854  va_start(args, fmt);
855  dump_one(parms, fmt, args);
856  va_end(args);
857 }
858 
859 
860 /** @} */
861 
862 /** @cond SKIP */
863 
864 int __trans_list_add(int i, const char *a, struct nl_list_head *head)
865 {
866  struct trans_list *tl;
867 
868  tl = calloc(1, sizeof(*tl));
869  if (!tl)
870  return -NLE_NOMEM;
871 
872  tl->i = i;
873  tl->a = strdup(a);
874 
875  nl_list_add_tail(&tl->list, head);
876 
877  return 0;
878 }
879 
880 void __trans_list_clear(struct nl_list_head *head)
881 {
882  struct trans_list *tl, *next;
883 
884  nl_list_for_each_entry_safe(tl, next, head, list) {
885  free(tl->a);
886  free(tl);
887  }
888 
889  nl_init_list_head(head);
890 }
891 
892 char *__type2str(int type, char *buf, size_t len,
893  const struct trans_tbl *tbl, size_t tbl_len)
894 {
895  int i;
896  for (i = 0; i < tbl_len; i++) {
897  if (tbl[i].i == type) {
898  snprintf(buf, len, "%s", tbl[i].a);
899  return buf;
900  }
901  }
902 
903  snprintf(buf, len, "0x%x", type);
904  return buf;
905 }
906 
907 char *__list_type2str(int type, char *buf, size_t len,
908  struct nl_list_head *head)
909 {
910  struct trans_list *tl;
911 
912  nl_list_for_each_entry(tl, head, list) {
913  if (tl->i == type) {
914  snprintf(buf, len, "%s", tl->a);
915  return buf;
916  }
917  }
918 
919  snprintf(buf, len, "0x%x", type);
920  return buf;
921 }
922 
923 char *__flags2str(int flags, char *buf, size_t len,
924  const struct trans_tbl *tbl, size_t tbl_len)
925 {
926  int i;
927  int tmp = flags;
928 
929  memset(buf, 0, len);
930 
931  for (i = 0; i < tbl_len; i++) {
932  if (tbl[i].i & tmp) {
933  tmp &= ~tbl[i].i;
934  strncat(buf, tbl[i].a, len - strlen(buf) - 1);
935  if ((tmp & flags))
936  strncat(buf, ",", len - strlen(buf) - 1);
937  }
938  }
939 
940  return buf;
941 }
942 
943 int __str2type(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
944 {
945  unsigned long l;
946  char *end;
947  int i;
948 
949  if (*buf == '\0')
950  return -NLE_INVAL;
951 
952  for (i = 0; i < tbl_len; i++)
953  if (!strcasecmp(tbl[i].a, buf))
954  return tbl[i].i;
955 
956  l = strtoul(buf, &end, 0);
957  if (l == ULONG_MAX || *end != '\0')
958  return -NLE_OBJ_NOTFOUND;
959 
960  return (int) l;
961 }
962 
963 int __list_str2type(const char *buf, struct nl_list_head *head)
964 {
965  struct trans_list *tl;
966  unsigned long l;
967  char *end;
968 
969  if (*buf == '\0')
970  return -NLE_INVAL;
971 
972  nl_list_for_each_entry(tl, head, list) {
973  if (!strcasecmp(tl->a, buf))
974  return tl->i;
975  }
976 
977  l = strtoul(buf, &end, 0);
978  if (l == ULONG_MAX || *end != '\0')
979  return -NLE_OBJ_NOTFOUND;
980 
981  return (int) l;
982 }
983 
984 int __str2flags(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
985 {
986  int i, flags = 0, len;
987  char *p = (char *) buf, *t;
988 
989  for (;;) {
990  if (*p == ' ')
991  p++;
992 
993  t = strchr(p, ',');
994  len = t ? t - p : strlen(p);
995  for (i = 0; i < tbl_len; i++)
996  if (!strncasecmp(tbl[i].a, p, len))
997  flags |= tbl[i].i;
998 
999  if (!t)
1000  return flags;
1001 
1002  p = ++t;
1003  }
1004 
1005  return 0;
1006 }
1007 
1008 void dump_from_ops(struct nl_object *obj, struct nl_dump_params *params)
1009 {
1010  int type = params->dp_type;
1011 
1012  if (type < 0 || type > NL_DUMP_MAX)
1013  BUG();
1014 
1015  params->dp_line = 0;
1016 
1017  if (params->dp_dump_msgtype) {
1018 #if 0
1019  /* XXX */
1020  char buf[64];
1021 
1022  dp_dump_line(params, 0, "%s ",
1023  nl_cache_mngt_type2name(obj->ce_ops,
1024  obj->ce_ops->co_protocol,
1025  obj->ce_msgtype,
1026  buf, sizeof(buf)));
1027 #endif
1028  params->dp_pre_dump = 1;
1029  }
1030 
1031  if (params->dp_buf)
1032  memset(params->dp_buf, 0, params->dp_buflen);
1033 
1034  if (obj->ce_ops->oo_dump[type])
1035  obj->ce_ops->oo_dump[type](obj, params);
1036 }
1037 
1038 /** @endcond */
1039 
1040 /** @} */