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