mbgtools-lx  4.2.8
lan_util.c
Go to the documentation of this file.
1 
2 /**************************************************************************
3  *
4  * $Id: lan_util.c 1.16 2018/04/06 14:58:54 martin REL_M $
5  *
6  * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
7  *
8  * Description:
9  * Utility functions useful for network programming.
10  *
11  * -----------------------------------------------------------------------
12  * $Log: lan_util.c $
13  * Revision 1.16 2018/04/06 14:58:54 martin
14  * Fixed ethtool support for older kernels / build environments.
15  * Revision 1.15 2018/02/28 16:56:39 martin
16  * Make parameters speed and duplex of check_port_status() optional.
17  * Doxygen fixes.
18  * Revision 1.14 2018/01/30 17:20:07 martin
19  * Fixed a compiler warning where a char was used as array index.
20  * Revision 1.13 2017/10/05 08:20:40 daniel
21  * Introduced check_port_status() function
22  * Revision 1.12 2017/07/05 14:07:56 martin
23  * IPv6 support functions added by hannes.
24  * Function snprint_ip4_cidr_mask() fixed by hannes. It now behaves
25  * as expected and appends the CIDR mask bits to the IP address now.
26  * Mostly use safe string functions from str_util.c.
27  * New function snprint_ptp_clock_id().
28  * Compiler warnings due to uninitialized vars quieted by thomas-b.
29  * Renamed check_octets_not_all_zero() to octets_are_all_zero(),
30  * which returns a bool now.
31  * Renamed check_mac_addr_not_all_zero() to mac_addr_all_zero(),
32  * which returns a bool now.
33  * Removed get_port_mac_addr_check().
34  * Removed definitions of old MBG_LU_... return codes, and
35  * only use standard MBG_RETURN_CODES instead.
36  * Fixed macro definition syntax to quiet clang compiler warnings.
37  * Let get_port_ip4_settings() check port link even if it
38  * returns an error (changed by daniel).
39  * Check for MBG_TGT_POSIX instead of MBG_TGT_UNIX.
40  * Doxygen comments.
41  * Revision 1.11 2015/04/01 14:31:14 hannes
42  * Fix: cidr_str_to_ip4_addr_and_net_mask: Defaults correctly to
43  * netmask 0.0.0.0 (/0) for no CIDR extension in cidr_str.
44  * Revision 1.10 2014/10/17 12:45:48 martin
45  * Let str_to_ip4_addr() return 0 if an empty string has been passed.
46  * Revision 1.9 2014/09/24 08:31:00 martin
47  * Exclude get_ip4_gateway() from build if USE_MBG_TSU is defined.
48  * Fixed some compiler warnings.
49  * Added and modified some comments.
50  * Revision 1.8 2013/10/02 07:19:13 martin
51  * New function get_port_intf_idx.
52  * Fixed naming.of local netlink support functions.
53  * Revision 1.7 2013/05/22 16:49:42 martin
54  * Fixed some return codes.
55  * Revision 1.6 2013/03/19 10:24:51 martin
56  * Fixed bugs in get_ip4_gateway(): A skipped routing entry was
57  * taken as default route, and thus a wrong default route 0.0.0.0
58  * could be returned erraneously. Also, malloc() was used without
59  * checking the result.
60  * Added conditional debug code.
61  * Revision 1.5 2013/02/19 15:13:10 martin
62  * Added some new functions.
63  * Updated doxygen comments.
64  * Revision 1.4 2012/11/02 09:16:57 martin
65  * Fixed build under Windows.
66  * Revision 1.3 2012/10/02 18:23:28Z martin
67  * Removed obsolete code to avoid compiler warning.
68  * Revision 1.2 2012/03/09 08:49:19 martin
69  * Added some commonly used functions.
70  * Revision 1.1 2011/03/04 10:01:32Z martin
71  * Initial revision.
72  *
73  **************************************************************************/
74 
75 #define _LAN_UTIL
76  #include <lan_util.h>
77 #undef _LAN_UTIL
78 
79 #include <words.h>
80 #include <str_util.h>
81 #include <mbgerror.h>
82 
83 #include <stdio.h>
84 #include <string.h>
85 #include <ctype.h>
86 
87 #if defined( MBG_TGT_POSIX )
88 
89  #if defined( MBG_TGT_LINUX )
90 
91  #include <linux/types.h>
92 
93  // Some older versions of linux/types.h don't define u8..u64
94  // for user space applications. However, if they do they also
95  // define BITS_PER_LONG, so we use this symbol to figure out
96  // if we need to define u8..u64 by ourselves.
97  #if !defined( BITS_PER_LONG )
98  typedef uint8_t u8;
99  typedef uint16_t u16;
100  typedef uint32_t u32;
101  typedef uint64_t u64;
102  #endif
103 
104  #include <linux/sockios.h>
105  #include <linux/ethtool.h>
106  #include <linux/rtnetlink.h>
107  #endif
108 
109  #include <unistd.h>
110  #include <syslog.h>
111  #include <sys/ioctl.h>
112  #include <arpa/inet.h>
113  #include <netinet/in.h>
114 
115 #else
116 
117  // dummy codes, the functions will report an error ...
118  #define SIOCGIFADDR 0
119  #define SIOCGIFNETMASK 0
120  #define SIOCGIFBRDADDR 0
121 
122  #if defined( MBG_TGT_WIN32 )
123  #define snprintf _snprintf
124  #endif
125 
126 #endif
127 
128 
129 #if !defined( DEBUG_NETLINK )
130  #if ( 0 && defined( DEBUG ) && defined( MBG_TGT_LINUX ) )
131  #define DEBUG_NETLINK 1
132  #else
133  #define DEBUG_NETLINK 0
134  #endif
135 #endif
136 
137 
138 #if DEBUG_NETLINK
139  // we need a function to output debugging information
140  #if !defined STANDALONE
141  #include <ptp2_cnf.h> // for mbglog() from the ARM PTP projects
142  #else
143  // to be provided by the application
144  extern __attribute__( ( format( printf, 2, 3 ) ) ) void mbglog( int priority, const char *fmt, ... );
145  #endif
146 #endif // DEBUG_NETLINK
147 
148 
149 
150 // Maximum size of an IPv4 address string in dotted quad format,
151 // including a terminating 0, and thus the required minimum size
152 // for a buffer to take such a string. i.e. "aaa.bbb.ccc.ddd\0".
153 #define MAX_IP4_ADDR_STR_SIZE 16
154 
155 
156 #if defined( MBG_TGT_LINUX )
157 
159 {
160  struct in_addr dstAddr;
161  struct in_addr srcAddr;
162  struct in_addr gateWay;
163  char ifName[IF_NAMESIZE];
164 };
165 
166 #endif
167 
168 
169 
170 /*HDR*/
183 int get_ip4_net_mask_bits( const IP4_ADDR *p_mask )
184 {
185  IP4_ADDR msb_mask = IP4_MSB_MASK;
186  int i;
187 
188  for ( i = 0; i < MAX_IP4_BITS; i++ )
189  {
190  if ( ( *p_mask & msb_mask ) == 0 )
191  break;
192 
193  msb_mask >>= 1;
194  }
195 
196  return i;
197 
198 } // get_ip4_net_mask_bits
199 
200 
201 
202 /*HDR*/
217 size_t snprint_ip4_addr( char *s, size_t max_len, const IP4_ADDR *p_addr, const char *info )
218 {
219  size_t n = 0;
220  ulong ul = *p_addr;
221 
222  if ( info )
223  n += snprintf_safe( s, max_len, "%s", info );
224 
225  // Don't use byte pointers here since this is not safe
226  // for both little and big endian targets.
227  n += snprintf_safe( &s[n], max_len - n, "%u.%u.%u.%u",
228  BYTE_3( ul ), BYTE_2( ul ),
229  BYTE_1( ul ), BYTE_0( ul )
230  );
231  return n;
232 
233 } // snprint_ip4_addr
234 
235 
236 
237 /*HDR*/
255 size_t snprint_ip4_cidr_addr( char *s, size_t max_len, const IP4_ADDR *p_addr,
256  const IP4_ADDR *p_mask, const char *info )
257 {
258  int cidr_mask_bits;
259  size_t n = snprint_ip4_addr( s, max_len, p_addr, info );
260 
261  cidr_mask_bits = get_ip4_net_mask_bits( p_mask );
262 
263  if ( ( cidr_mask_bits >= MIN_IP4_CIDR_NETMASK_BITS ) &&
264  ( cidr_mask_bits <= MAX_IP4_CIDR_NETMASK_BITS ) )
265  n += snprintf_safe( &s[n], max_len - n, "/%i", cidr_mask_bits );
266 
267  return n;
268 
269 } // snprint_ip4_cidr_addr
270 
271 
272 
273 /*HDR*/
291 int str_to_ip4_addr( IP4_ADDR *p_addr, const char *s )
292 {
293  IP4_ADDR tmp_ip4_addr = 0;
294  const char *cp = s;
295  int i;
296 
297  if ( strlen( s ) )
298  {
299  for ( i = 0; ; )
300  {
301  unsigned long ul = strtoul( (char *) cp, (char **) &cp, 10 );
302 
303  if ( ul > 0xFFUL ) // invalid number
304  return MBG_ERR_PARM_FMT;
305 
306  tmp_ip4_addr |= ul << ( 8 * (3 - i) );
307 
308  if ( ++i >= 4 )
309  break; // done
310 
311  if ( *cp != '.' )
312  return MBG_ERR_PARM_FMT; // invalid string format, dot expected
313 
314  cp++; // skip dot
315  }
316  }
317 
318  if ( p_addr )
319  *p_addr = tmp_ip4_addr;
320 
321  // success: return the number of evaluated chars
322  return (int) ( cp - s );
323 
324 } // str_to_ip4_addr
325 
326 
327 
328 /*HDR*/
350  const char *cidr_str )
351 {
352  IP4_ADDR mask;
353  long cidr_mask_bits;
354  const char *cp;
355  int l;
356  int rc = str_to_ip4_addr( p_addr, cidr_str );
357 
358  if ( mbg_rc_is_error( rc ) )
359  return rc;
360 
361 
362  l = (int) strlen( cidr_str );
363 
364  if ( l < rc ) // input string too short
365  return MBG_ERR_PARM_FMT;
366 
367 
368  cp = &cidr_str[rc];
369 
370  if ( *cp == 0 ) // end of string
371  {
372  // The string has no CIDR extension, so
373  // assume "/0", i.e. host mask 0.0.0.0;
374  mask = (IP4_ADDR) 0;
375  goto done;
376  }
377 
378 
379  if ( *cp != '/' )
380  return MBG_ERR_PARM_FMT;
381 
382 
383  cp++;
384  cidr_mask_bits = strtol( (char *) cp, (char **) &cp, 10 );
385 
386  if ( ( cidr_mask_bits < MIN_IP4_CIDR_NETMASK_BITS ) ||
387  ( cidr_mask_bits > MAX_IP4_CIDR_NETMASK_BITS ) )
388  return MBG_ERR_RANGE;
389 
390 
391  mask = ip4_net_mask_from_cidr( (int) cidr_mask_bits );
392 
393 done:
394  if ( p_mask )
395  *p_mask = mask;
396 
397  // success: return the number of evaluated chars
398  return (int) ( cp - cidr_str );
399 
400 } // cidr_str_to_ip4_addr_and_net_mask
401 
402 
403 
404 /*HDR*/
417 int get_ip6_net_mask_bits( const IP6_ADDR *p_mask )
418 {
419  int i;
420  int cnt = 0;
421  uint8_t msb_mask = IP6_MSB_MASK;
422 
423  for ( i = IP6_ADDR_BYTES - 1 ; i >= 0; i-- )
424  {
425  if ( p_mask->b[i] == 0xff )
426  cnt += 8;
427  else
428  {
429  for ( ; cnt < MAX_IP6_CIDR_NETMASK_BITS; cnt++ )
430  {
431  if ( ( p_mask->b[i] & msb_mask ) == 0 )
432  break;
433 
434  msb_mask >>= 1;
435  }
436  break;
437  }
438  }
439 
440  return cnt;
441 
442 } // get_ip6_net_mask_bits
443 
444 
445 
446 /*HDR*/
463 size_t snprint_ip6_addr( char *s, size_t max_len, const IP6_ADDR *p_addr, const char *info )
464 {
465  // Copied from inet_ntop.c, and reversed byte order
466 
467  IP6_ADDR_STR tmp;
468  char *tp;
469  #define NUM_WORDS ( (int) ( sizeof( IP6_ADDR_STR ) / sizeof( uint16_t ) ) )
470  uint16_t words[NUM_WORDS] = { 0 };
471  int i;
472  size_t n = 0;
473  struct
474  {
475  int base;
476  int len;
477  } best = { 0 }, cur = { 0 };
478 
479  /*
480  * Preprocess:
481  * Copy the input (bytewise) array into a wordwise array.
482  * Find the longest run of 0x00's in p_addr->b[] for :: shorthanding.
483  */
484  for ( i = IP6_ADDR_BYTES - 1; i >= 0; i-- )
485  words[(IP6_ADDR_BYTES - 1 - i) / 2] |= (p_addr->b[i] << ((1 - ((IP6_ADDR_BYTES - 1 - i) % 2)) << 3));
486 
487  best.base = -1;
488  cur.base = -1;
489 
490  for ( i = 0; i < NUM_WORDS; i++ )
491  {
492  if ( words[i] == 0 )
493  {
494  if ( cur.base == -1 )
495  cur.base = i, cur.len = 1;
496  else
497  cur.len++;
498  }
499  else
500  {
501  if ( cur.base != -1 )
502  {
503  if ( best.base == -1 || cur.len > best.len )
504  best = cur;
505 
506  cur.base = -1;
507  }
508  }
509  }
510 
511  if ( cur.base != -1 )
512  {
513  if ( best.base == -1 || cur.len > best.len )
514  best = cur;
515  }
516 
517  if ( best.base != -1 && best.len < 2 )
518  best.base = -1;
519 
520  // Format the result.
521 
522  tp = tmp;
523 
524  for ( i = 0; i < NUM_WORDS; i++ )
525  {
526  /* Are we inside the best run of 0x00's? */
527  if ( best.base != -1 && i >= best.base && i < ( best.base + best.len ) )
528  {
529  if (i == best.base)
530  *tp++ = ':';
531 
532  continue;
533  }
534 
535  /* Are we following an initial run of 0x00s or any real hex? */
536  if ( i != 0 )
537  *tp++ = ':';
538 
539  /* Is this address an encapsulated IPv4? */
540  if ( i == 6 && best.base == 0 && ( best.len == 6 || ( best.len == 5 && words[5] == 0xffff ) ) )
541  return MBG_ERR_INV_PARM; // we don't support encapsulated IPv4
542 
543  sprintf( tp, "%x", words[i] );
544  tp += strlen( tp );
545  }
546 
547  /* Was it a trailing run of 0x00's? */
548  if ( best.base != -1 && ( best.base + best.len ) == NUM_WORDS )
549  *tp++ = ':';
550 
551  *tp++ = '\0';
552 
553  /*
554  * Check for overflow, copy, and we're done.
555  */
556  if ( ( tp - tmp ) > (int) max_len )
557  return MBG_ERR_OVERFLOW;
558 
559  if ( info )
560  n += snprintf_safe( s, max_len, "%s", info );
561 
562  n += snprintf_safe( &s[n], max_len - n, "%s", tmp );
563 
564  return n;
565 
566  #undef NUM_WORDS
567 
568 } // snprint_ip6_addr
569 
570 
571 
572 /*HDR*/
592 size_t snprint_ip6_cidr_addr( char *s, size_t max_len, const IP6_ADDR *p_addr,
593  const IP6_ADDR *p_mask, const char *info )
594 {
595  size_t n = snprint_ip6_addr( s, max_len, p_addr, info );
596 
597  int cidr_mask_bits = get_ip6_net_mask_bits( p_mask );
598 
599  if ( ( cidr_mask_bits >= MIN_IP6_CIDR_NETMASK_BITS ) &&
600  ( cidr_mask_bits <= MAX_IP6_CIDR_NETMASK_BITS ) )
601  n += snprintf_safe( &s[n], max_len - n, "/%i", cidr_mask_bits );
602 
603  return n;
604 
605 } // snprint_ip6_cidr_addr
606 
607 
608 
609 /*HDR*/
629 size_t snprint_ip6_cidr_mask_addr( char *s, size_t max_len, const IP6_ADDR *p_addr,
630  const int cidr_mask_bits, const char* info )
631 {
632  size_t n;
633  IP6_ADDR mask;
634 
635  ip6_net_mask_from_cidr( &mask, cidr_mask_bits );
636 
637  n = snprint_ip6_addr( s, max_len, p_addr, info );
638 
639  if ( ( cidr_mask_bits >= MIN_IP6_CIDR_NETMASK_BITS ) &&
640  ( cidr_mask_bits <= MAX_IP6_CIDR_NETMASK_BITS ) )
641  n += snprintf_safe( &s[n], max_len - n, "/%i", cidr_mask_bits );
642 
643  return n;
644 
645 } // snprint_ip6_cidr_mask_addr
646 
647 
648 
649 /*HDR*/
673 int str_to_ip6_addr( IP6_ADDR *p_addr, const char *s )
674 {
675  // copied from inet_pton.c and reversed byte order
676  IP6_ADDR tmp = { { 0 } };
677  static const char xdigits[] = "0123456789abcdef";
678  uint8_t *tp;
679  uint8_t *startp;
680  uint8_t *colonp;
681  int ch;
682  int saw_xdigit;
683  int read_cnt = 0;
684  unsigned int val;
685 
686  if ( p_addr )
687  memset( p_addr, 0, sizeof( *p_addr ) ); // set IP address to ::
688 
689  startp = tmp.b - 1;
690  tp = startp + sizeof( tmp );
691 
692  colonp = NULL;
693 
694  /* Leading :: requires some special handling. */
695  if ( *s == ':' )
696  {
697  read_cnt++;
698 
699  if ( *++s != ':' )
700  return MBG_ERR_PARM_FMT;
701  }
702 
703  saw_xdigit = 0;
704  val = 0;
705 
706  while ( ( ch = tolower( (int) *s++ ) ) != '\0' )
707  {
708  const char *pch;
709 
710  read_cnt++;
711 
712  pch = strchr( xdigits, ch );
713 
714  if ( pch != NULL )
715  {
716  val <<= 4;
717  val |= ( pch - xdigits );
718 
719  if ( val > 0xffff ) //### TODO signed? unsigned?
720  return MBG_ERR_PARM_FMT;
721 
722  saw_xdigit = 1;
723  continue;
724  }
725 
726  if ( ch == ':' )
727  {
728  if ( !saw_xdigit )
729  {
730  if ( colonp )
731  return MBG_ERR_PARM_FMT;
732 
733  colonp = tp;
734  continue;
735 
736  }
737  else
738  if ( *s == '\0' )
739  return MBG_ERR_PARM_FMT;
740 
741  if ( tp - sizeof( uint16_t ) < startp )
742  return MBG_ERR_PARM_FMT;
743 
744  *tp-- = (uint8_t) ( val >> 8 ) & 0xff;
745  *tp-- = (uint8_t) val & 0xff;
746  saw_xdigit = 0;
747  val = 0;
748  continue;
749  }
750 
751  if ( ch == '/' ) // cidr notation. we reached the end
752  {
753  read_cnt--;
754  break;
755  }
756 
757  return MBG_ERR_PARM_FMT;
758  }
759 
760  if ( saw_xdigit )
761  {
762  if ( tp - sizeof( uint16_t ) < startp )
763  return MBG_ERR_PARM_FMT;
764 
765  *tp-- = (uint8_t) (val >> 8) & 0xff;
766  *tp-- = (uint8_t) val & 0xff;
767  }
768 
769  if ( colonp != NULL )
770  {
771  /*
772  * Since some memmove()'s erroneously fail to handle
773  * overlapping regions, we'll do the shift by hand.
774  */
775  const size_t n = colonp - tp;
776  size_t i;
777 
778  if ( tp == startp )
779  return MBG_ERR_PARM_FMT;
780 
781  for ( i = 0; i <= n; i++ )
782  {
783  startp[i] = colonp[i - n];
784  colonp[i - n] = 0;
785  }
786 
787  tp = startp;
788  }
789 
790  if ( tp != startp )
791  return MBG_ERR_PARM_FMT;
792 
793  if ( p_addr )
794  *p_addr = tmp;
795 
796  return read_cnt;
797 
798 } // str_to_ip6_addr
799 
800 
801 
802 /*HDR*/
823 int cidr_str_to_ip6_addr_and_net_mask( IP6_ADDR *p_addr, IP6_ADDR *p_mask, const char *cidr_str )
824 {
825  int mask = 0;
826  int rc = cidr_str_to_ip6_addr_and_cidr_bits( p_addr, &mask, cidr_str );
827 
828  if ( mbg_rc_is_error( rc ) )
829  return rc;
830 
831  if ( p_mask )
832  ip6_net_mask_from_cidr( p_mask, mask );
833 
834  return rc;
835 
836 } // cidr_str_to_ip6_addr_and_net_mask
837 
838 
839 
840 /*HDR*/
860  const char *cidr_str )
861 {
862  long cidr_mask_bits;
863  const char *cp;
864  ssize_t l;
865  int rc = str_to_ip6_addr( p_addr, cidr_str );
866 
867  if ( mbg_rc_is_error( rc ) )
868  return rc;
869 
870  l = strlen( cidr_str );
871 
872  if ( l < rc ) // input string too short
873  return MBG_ERR_PARM_FMT;
874 
875  cp = &cidr_str[rc];
876 
877  if ( *cp == 0 ) // end of string
878  {
879  // The string has no CIDR extension, so
880  // assume "/0", i.e. host mask ::
881  cidr_mask_bits = 0;
882  goto done;
883  }
884 
885  if ( *cp != '/' )
886  return MBG_ERR_PARM_FMT;
887 
888  cp++;
889  cidr_mask_bits = strtol( (char *) cp, (char **) &cp, 10 );
890 
891  if ( ( cidr_mask_bits < MIN_IP6_CIDR_NETMASK_BITS ) ||
892  ( cidr_mask_bits > MAX_IP6_CIDR_NETMASK_BITS ) )
893  return MBG_ERR_RANGE;
894 
895 done:
896  if ( p_cidr )
897  *p_cidr = (int) cidr_mask_bits;
898 
899  // success: return the number of evaluated chars
900  return (int) ( cp - cidr_str );
901 
902 } // cidr_str_to_ip6_addr_and_cidr_bits
903 
904 
905 
906 /*HDR*/
918 void ip6_net_mask_from_cidr( IP6_ADDR *p_mask, int netmask_bits )
919 {
920  int i = 0;
921 
922  if ( p_mask )
923  {
924  memset( p_mask, 0, sizeof( *p_mask ) );
925 
926  if ( netmask_bits < 0 )
927  netmask_bits = 0;
928  else
929  if ( netmask_bits >= IP6_ADDR_BITS )
930  netmask_bits = IP6_ADDR_BITS;
931 
932  for ( i = IP6_ADDR_BYTES - 1; i >= 0; i-- )
933  {
934  if ( netmask_bits > 8 )
935  {
936  p_mask->b[i] = 0xff;
937  netmask_bits -= 8;
938  }
939  else
940  {
941  p_mask->b[i] = (0xff << ( 8 - netmask_bits ) ) & 0xff;
942  netmask_bits = 0;
943  }
944  }
945  }
946 
947 } // ip6_net_mask_from_cidr
948 
949 
950 
951 /*HDR*/
961 void ip6_net_part_from_addr( IP6_ADDR *p_net_part, const IP6_ADDR *p_addr,
962  const IP6_ADDR *p_mask )
963 {
964  int i;
965 
966  for ( i = IP6_ADDR_BYTES; i-- > 0; )
967  p_net_part->b[i] = p_addr->b[i] & p_mask->b[i];
968 
969 } // ip6_net_part_from_addr
970 
971 
972 
973 /*HDR*/
990 size_t snprint_octets( char *s, size_t max_len, const uint8_t *octets,
991  int num_octets, char sep, const char *info )
992 {
993  size_t n = 0;
994  int i;
995 
996  if ( info )
997  n += snprintf_safe( s, max_len, "%s", info );
998 
999  for ( i = 0; i < num_octets; i++ )
1000  {
1001  if ( i && sep )
1002  n += snprintf_safe( &s[n], max_len - n, "%c", sep );
1003 
1004  n += snprintf_safe( &s[n], max_len - n, "%02X", octets[i] );
1005  }
1006 
1007  return n;
1008 
1009 } // snprint_octets
1010 
1011 
1012 
1013 /*HDR*/
1027 size_t snprint_ptp_clock_id( char *s, size_t max_len, const PTP_CLOCK_ID *p )
1028 {
1029  return snprint_octets( s, max_len, p->b, sizeof( *p ), ':', NULL );
1030 
1031 } // snprint_ptp_clock_id
1032 
1033 
1034 
1035 /*HDR*/
1049 size_t snprint_mac_addr( char *s, size_t max_len, const MBG_MAC_ADDR *p_mac_addr )
1050 {
1051  return snprint_octets( s, max_len, p_mac_addr->b, sizeof( *p_mac_addr ), MAC_SEP_CHAR, NULL );
1052 
1053 } // snprint_mac_addr
1054 
1055 
1056 
1057 /*HDR*/
1071 int str_to_octets( uint8_t *octets, int num_octets, const char *s )
1072 {
1073  char *cp = (char *) s;
1074  int i;
1075 
1076  // don't use strtok() since that functions modifies the original string
1077  for ( i = 0; i < num_octets; )
1078  {
1079  octets[i] = (uint8_t) strtoul( cp, &cp, 16 );
1080  i++;
1081 
1082  if ( *cp == 0 )
1083  break; // end of string
1084 
1085  if ( ( *cp != MAC_SEP_CHAR ) && ( *cp != MAC_SEP_CHAR_ALT ) )
1086  break; // invalid character
1087 
1088  cp++;
1089  }
1090 
1091  return i;
1092 
1093 } // str_to_octets
1094 
1095 
1096 
1097 /*HDR*/
1110 bool octets_are_all_zero( const uint8_t *octets, int num_octets )
1111 {
1112  int i;
1113 
1114  // check if any of the bytes is != 0
1115  for ( i = 0; i < num_octets; i++ )
1116  if ( octets[i] != 0 )
1117  break;
1118 
1119  return i == num_octets; // true if *all* bytes are 0
1120 
1121 } // octets_are_all_zero
1122 
1123 
1124 
1125 /*HDR*/
1135 bool mac_addr_is_all_zero( const MBG_MAC_ADDR *p_addr )
1136 {
1137  return octets_are_all_zero( p_addr->b, sizeof( p_addr->b ) );
1138 
1139 } // mac_addr_is_all_zero
1140 
1141 
1142 
1143 #if defined( MBG_TGT_POSIX )
1144 
1145 /*HDR*/
1155 int do_siocg_ioctl( const char *if_name, int ioctl_code, struct ifreq *p_ifreq )
1156 {
1157  int sock_fd;
1158  int rc;
1159 
1160  if ( strlen( if_name ) > ( IFNAMSIZ - 1 ) )
1161  return MBG_ERR_PARM_FMT;
1162 
1163  sock_fd = socket( AF_INET, SOCK_DGRAM, 0 ); //### TODO: or AF_INET6/PF_INET6 for IPv6
1164 
1165  if ( sock_fd == -1 ) // failed to open socket
1166  return mbg_get_last_socket_error( "failed to open socket in do_siocg_ioctl" );
1167 
1168  strncpy_safe( p_ifreq->ifr_name, if_name, sizeof( p_ifreq->ifr_name ) );
1169 
1170  rc = ioctl( sock_fd, ioctl_code, p_ifreq );
1171 
1172  if ( rc == -1 ) // ioctl failed, errno has been set appropriately
1173  rc = mbg_get_last_socket_error( "ioctl failed in do_siocg_ioctl" );
1174  else
1175  rc = MBG_SUCCESS;
1176 
1177  close( sock_fd );
1178 
1179  return rc;
1180 
1181 } // do_siocg_ioctl
1182 
1183 #endif // defined( MBG_TGT_POSIX )
1184 
1185 
1186 
1187 /*HDR*/
1197 int get_port_intf_idx( const char *if_name, int *p_intf_idx )
1198 {
1199  int rc = MBG_ERR_NOT_SUPP_ON_OS;
1200 
1201  #if defined( MBG_TGT_LINUX )
1202  struct ifreq ifr = { { { 0 } } };
1203 
1204  rc = do_siocg_ioctl( if_name, SIOCGIFINDEX, &ifr );
1205 
1206  if ( mbg_rc_is_success( rc ) )
1207  {
1208  *p_intf_idx = ifr.ifr_ifindex;
1209  return rc;
1210  }
1211  #endif
1212 
1213  // we get here on error only
1214  *p_intf_idx = -1;
1215 
1216  return rc;
1217 
1218 } // get_port_intf_idx
1219 
1220 
1221 
1222 /*HDR*/
1232 int get_port_mac_addr( const char *if_name, MBG_MAC_ADDR *p_mac_addr )
1233 {
1234  int rc = MBG_ERR_NOT_SUPP_ON_OS;
1235 
1236  #if defined( MBG_TGT_LINUX )
1237  struct ifreq ifr = { { { 0 } } };
1238 
1239  rc = do_siocg_ioctl( if_name, SIOCGIFHWADDR, &ifr );
1240 
1241  if ( mbg_rc_is_success( rc ) )
1242  {
1243  memcpy( p_mac_addr, ifr.ifr_hwaddr.sa_data, sizeof( *p_mac_addr ) );
1244  return rc;
1245  }
1246  #endif
1247 
1248  // we get here on error only
1249  memset( p_mac_addr, 0, sizeof( *p_mac_addr ) );
1250 
1251  return rc;
1252 
1253 } // get_port_mac_addr
1254 
1255 
1256 
1257 /*HDR*/
1267 int check_port_link( const char *if_name )
1268 {
1269  int rc = MBG_ERR_NOT_SUPP_ON_OS;
1270 
1271  #if defined( MBG_TGT_LINUX )
1272  struct ifreq ifr = { { { 0 } } };
1273  struct ethtool_value edata = { 0 };
1274 
1275  edata.cmd = ETHTOOL_GLINK; // defined in ethtool.h
1276  ifr.ifr_data = (caddr_t) &edata;
1277 
1278  rc = do_siocg_ioctl( if_name, SIOCETHTOOL, &ifr );
1279 
1280  if ( mbg_rc_is_success( rc ) )
1281  rc = ( edata.data == 0 ) ? 0 : 1;
1282  #endif
1283 
1284  return rc;
1285 
1286 } // check_port_link
1287 
1288 
1289 
1290 /*HDR*/
1302 int check_port_status( const char *if_name, int *p_speed, int *p_duplex )
1303 {
1304  int rc = MBG_ERR_NOT_SUPP_ON_OS;
1305 
1306  #if defined( MBG_TGT_LINUX )
1307  struct ifreq ifr = { { { 0 } } };
1308  struct ethtool_cmd cmd = { 0 };
1309  int ok;
1310 
1311  ifr.ifr_data = (void *) &cmd;
1312  cmd.cmd = ETHTOOL_GSET; // "Get settings"
1313 
1314  rc = do_siocg_ioctl( if_name, SIOCETHTOOL, &ifr );
1315 
1316  ok = mbg_rc_is_success( rc );
1317 
1318  if ( p_speed )
1319  {
1320  #if defined( ETH_TEST_FL_EXTERNAL_LB_DONE )
1321  // ethtool_cmd_speed() is only provided by kernels ~3.7-rc1 and
1322  // newer, which should also define ETH_TEST_FL_EXTERNAL_LB_DONE.
1323  // The function assembles a 32 bit value from two 16 bit fields.
1324  *p_speed = ok ? ethtool_cmd_speed( &cmd ) : 0; // [MHz]
1325  #else
1326  // Older kernels only provide a single 16 bit 'speed' field.
1327  *p_speed = ok ? cmd.speed : 0; // [MHz]
1328  #endif
1329  }
1330 
1331  if ( p_duplex )
1332  *p_duplex = ok ? cmd.duplex : -1; // 0x00 == half, 0x01 == full
1333 
1334  #endif
1335 
1336  return rc;
1337 
1338 } // check_port_status
1339 
1340 
1341 
1342 static /*HDR*/
1361 int get_specific_port_ip4_addr( const char *if_name, IP4_ADDR *p_addr, int sigioc_code )
1362 {
1363  int rc = MBG_ERR_NOT_SUPP_ON_OS;
1364 
1365  #if defined( MBG_TGT_LINUX )
1366  struct ifreq ifr = { { { 0 } } };
1367 
1368  rc = do_siocg_ioctl( if_name, sigioc_code, &ifr );
1369 
1370  if ( mbg_rc_is_success( rc ) )
1371  {
1372  *p_addr = ntohl( ( (struct sockaddr_in *) &ifr.ifr_addr )->sin_addr.s_addr );
1373  return rc;
1374  }
1375  #endif
1376 
1377  // we get here on error only
1378  *p_addr = 0; // make empty address
1379 
1380  return rc;
1381 
1382 } // get_specific_port_ip4_addr
1383 
1384 
1385 
1386 /*HDR*/
1404 int get_port_ip4_addr( const char *if_name, IP4_ADDR *p_addr )
1405 {
1406  return get_specific_port_ip4_addr( if_name, p_addr, SIOCGIFADDR );
1407 
1408 } // get_port_ip4_addr
1409 
1410 
1411 
1412 /*HDR*/
1430 int get_port_ip4_netmask( const char *if_name, IP4_ADDR *p_addr )
1431 {
1432  return get_specific_port_ip4_addr( if_name, p_addr, SIOCGIFNETMASK );
1433 
1434 } // get_port_ip4_netmask
1435 
1436 
1437 
1438 /*HDR*/
1456 int get_port_ip4_broad_addr( const char *if_name, IP4_ADDR *p_addr )
1457 {
1458  return get_specific_port_ip4_addr( if_name, p_addr, SIOCGIFBRDADDR );
1459 
1460 } // get_port_ip4_broad_addr
1461 
1462 
1463 
1464 #if defined( MBG_TGT_LINUX )
1465 
1466 static /*HDR*/
1472 int nl_read( int sock_fd, char *buf_ptr, size_t buf_size, int seq_num, int pid )
1473 {
1474  struct nlmsghdr *nl_hdr;
1475  int read_len = 0;
1476  int msg_len = 0;
1477 
1478  do
1479  {
1480  // receive response from the kernel, can be several chunks
1481  if ( ( read_len = recv( sock_fd, buf_ptr, buf_size - msg_len, 0 ) ) == -1 )
1482  {
1483  int rc = mbg_get_last_socket_error( NULL );
1484  #if DEBUG_NETLINK
1485  mbglog( LOG_ERR, "%s: Failed to receive netlink packet: %s",
1486  __func__, mbg_strerror( rc ) );
1487  #endif
1488  return rc;
1489  }
1490 
1491  nl_hdr = (struct nlmsghdr *) buf_ptr;
1492 
1493  // check if the header is valid
1494  if ( ( NLMSG_OK( nl_hdr, read_len ) == 0 ) || ( nl_hdr->nlmsg_type == NLMSG_ERROR ) )
1495  {
1496  #if DEBUG_NETLINK
1497  mbglog( LOG_ERR, "%s: Invalid header in received netlink packet",
1498  __func__ );
1499  #endif
1500  return MBG_ERR_DATA_FMT;
1501  }
1502 
1503  // check if the its the last message
1504  if ( nl_hdr->nlmsg_type == NLMSG_DONE )
1505  {
1506  #if DEBUG_NETLINK
1507  mbglog( LOG_ERR, "%s: Reached last message in received packet",
1508  __func__ );
1509  #endif
1510  break;
1511  }
1512 
1513  // move the pointer to buffer appropriately
1514  buf_ptr += read_len;
1515  msg_len += read_len;
1516 
1517  // check if its a multi part message
1518  if ( ( nl_hdr->nlmsg_flags & NLM_F_MULTI ) == 0 )
1519  {
1520  // return if it's not a multi part message
1521  #if DEBUG_NETLINK
1522  mbglog( LOG_ERR, "%s: Received packet is not a multi part message",
1523  __func__ );
1524  #endif
1525  break;
1526  }
1527 
1528  } while ( ( nl_hdr->nlmsg_seq != seq_num ) || ( nl_hdr->nlmsg_pid != pid ) );
1529 
1530  #if DEBUG_NETLINK
1531  mbglog( LOG_ERR, "%s: Received packet has len %i",
1532  __func__, msg_len );
1533  #endif
1534 
1535  return msg_len;
1536 
1537 } // nl_read
1538 
1539 
1540 
1541 #if DEBUG_NETLINK
1542 
1543 static /*HDR*/
1544 void nl_log_bytes( const char *fnc, const char *info, const void *p, int n_bytes )
1545 {
1546  char ws[80];
1547  size_t n = 0;
1548  int i;
1549 
1550  for ( i = 0; i < n_bytes; i++ )
1551  n += snprintf_safe( &ws[n], sizeof( ws ) - n, " %i", BYTE_OF( * (uint8_t *) p, i ) );
1552 
1553  mbglog( LOG_INFO, "%s: attibute %s, copying %i bytes:%s",
1554  fnc, info, n_bytes, ws );
1555 
1556 } // nl_log_bytes
1557 
1558 #endif
1559 
1560 
1561 
1562 static /*HDR*/
1563 int nl_parse_routes( struct nlmsghdr *nl_hdr, struct route_info *rt_info )
1564 {
1565  // parse the route info returned
1566  struct rtmsg *rt_msg;
1567  struct rtattr *rt_attr;
1568  int rt_len;
1569 
1570  rt_msg = (struct rtmsg *) NLMSG_DATA( nl_hdr );
1571 
1572  // If the route is not for AF_INET then return.
1573  // This could be also IPv6 routes.
1574  if ( rt_msg->rtm_family != AF_INET ) //##++ TODO: PF_INET6 for IPv6
1575  {
1576  #if DEBUG_NETLINK
1577  mbglog( LOG_ERR, "%s: Route is not AF_INET (%li), but %li",
1578  __func__, (long) AF_INET, (long) rt_msg->rtm_family );
1579  #endif
1580  return -1;
1581  }
1582 
1583  // If the route does not belong to main routing table then return.
1584  if ( rt_msg->rtm_table != RT_TABLE_MAIN )
1585  {
1586  #if DEBUG_NETLINK
1587  mbglog( LOG_ERR, "%s: Route does not belong to main table (%li), but %li",
1588  __func__, (long) RT_TABLE_MAIN, (long) rt_msg->rtm_table );
1589  #endif
1590  return -1;
1591  }
1592 
1593 
1594  // get the rtattr field
1595  rt_attr = (struct rtattr *) RTM_RTA( rt_msg );
1596  rt_len = RTM_PAYLOAD( nl_hdr );
1597 
1598  for ( ; RTA_OK( rt_attr, rt_len ); rt_attr = RTA_NEXT( rt_attr, rt_len ) )
1599  {
1600  #if DEBUG_NETLINK
1601  mbglog( LOG_ERR, "rt_attr at %p, %i bytes left", rt_attr, rt_len );
1602  #endif
1603 
1604  switch ( rt_attr->rta_type )
1605  {
1606  case RTA_OIF:
1607  if_indextoname( *(int *)RTA_DATA( rt_attr ), rt_info->ifName );
1608  #if DEBUG_NETLINK
1609  mbglog( LOG_ERR, "%s: attibute RTA_OIF, IF name: %s",
1610  __func__, rt_info->ifName );
1611  #endif
1612  break;
1613 
1614  case RTA_GATEWAY:
1615  memcpy( &rt_info->gateWay, RTA_DATA( rt_attr ), sizeof( rt_info->gateWay ) );
1616  #if DEBUG_NETLINK
1617  nl_log_bytes( __func__, "RTA_GATEWAY", &rt_info->gateWay, sizeof( rt_info->gateWay ) );
1618  #endif
1619  break;
1620 
1621  case RTA_PREFSRC:
1622  memcpy( &rt_info->srcAddr , RTA_DATA( rt_attr ), sizeof( rt_info->srcAddr ) );
1623  #if DEBUG_NETLINK
1624  nl_log_bytes( __func__, "RTA_PREFSRC", &rt_info->srcAddr, sizeof( rt_info->srcAddr ) );
1625  #endif
1626  break;
1627 
1628  case RTA_DST:
1629  memcpy( &rt_info->dstAddr, RTA_DATA( rt_attr ), sizeof( rt_info->dstAddr ) );
1630  #if DEBUG_NETLINK
1631  nl_log_bytes( __func__, "RTA_DST", &rt_info->dstAddr, sizeof( rt_info->dstAddr ) );
1632  #endif
1633  break;
1634 
1635  #if DEBUG_NETLINK
1636  case RTA_TABLE:
1637  {
1638  // The RTA_TABLE attribute was added to the kernel source in 2006 to support
1639  // more than 255 routing tables. Originally the number of the routing table
1640  // to which an entry belongs had been passed only in struct rtmsg::rtm_table,
1641  // which is only 8 bits wide and should still hold the 8 LSBs of the full
1642  // routing table number for compatibility, so this should still work for the
1643  // standard routing tables, including the main table we are inspecting here.
1644  //
1645  // Whether this can be compiled in depends on the version of linux/rtnetlink.h
1646  // used by the compiler. Unfortunately RTA_TABLE is part of an enum, so you
1647  // can't simply use #ifdef RTA_TABLE to include this code conditionally.
1648  uint32_t rta_table;
1649  memcpy( &rta_table, RTA_DATA( rt_attr ), sizeof( rta_table ) );
1650  mbglog( LOG_ERR, "%s: attibute RTA_TABLE %i (%i)",
1651  __func__, rta_table, rt_msg->rtm_table );
1652  }
1653  break;
1654 
1655  default:
1656  mbglog( LOG_ERR, "%s: Found unknown route type %li",
1657  __func__, (long) rt_attr->rta_type );
1658  #endif
1659  }
1660  }
1661 
1662  return 0;
1663 
1664 } // nl_parse_routes
1665 
1666 #endif // defined( MBG_TGT_LINUX )
1667 
1668 
1669 
1670 /*HDR*/
1680 {
1681  int rc = MBG_ERR_NOT_SUPP_ON_OS;
1682 
1683 #if defined( MBG_TGT_LINUX )
1684  struct nlmsghdr *nlmsg;
1685  struct route_info route_info;
1686  char msg_buf[8192]; // pretty large buffer, why 8192 ?
1687  int sock_fd;
1688  int len;
1689  int msg_seq = 0;
1690  int idx;
1691 
1692  // create socket
1693  if ( ( sock_fd = socket( PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE ) ) == -1 )
1694  {
1695  rc = mbg_get_last_socket_error( NULL );
1696  #if DEBUG_NETLINK
1697  mbglog( LOG_ERR, "%s: Failed to create netlink socket: %s",
1698  __func__, mbg_strerror( rc ) );
1699  #endif
1700  goto out;
1701  }
1702 
1703 
1704  // initialize buffer with request message
1705  memset( msg_buf, 0, sizeof( msg_buf ) );
1706 
1707  // point the header and the msg structure pointers into the buffer
1708  nlmsg = (struct nlmsghdr *) msg_buf;
1709 
1710  // fill in the nlmsg header
1711  nlmsg->nlmsg_len = NLMSG_LENGTH( sizeof( struct rtmsg ) ); // length of message
1712  nlmsg->nlmsg_type = RTM_GETROUTE; // get the routes from kernel routing table
1713 
1714  nlmsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // the message is a request for dump
1715  nlmsg->nlmsg_seq = msg_seq++; // sequence of the message packet
1716  nlmsg->nlmsg_pid = getpid(); // PID of process sending the request
1717 
1718  // send the request
1719  if ( send( sock_fd, nlmsg, nlmsg->nlmsg_len, 0 ) == -1 )
1720  {
1721  rc = mbg_get_last_socket_error( NULL );
1722  #if DEBUG_NETLINK
1723  mbglog( LOG_ERR, "%s: Failed to write to netlink socket: %s",
1724  __func__, mbg_strerror( rc ) );
1725  #endif
1726  goto out;
1727  }
1728 
1729  // read the response
1730  if ( ( len = nl_read( sock_fd, msg_buf, sizeof( msg_buf ), msg_seq, getpid() ) ) < 0 )
1731  {
1732  #if DEBUG_NETLINK
1733  mbglog( LOG_ERR, "%s: Failed to read from netlink socket",
1734  __func__ );
1735  #endif
1736  rc = len;
1737  goto out;
1738  }
1739 
1740  #if DEBUG_NETLINK
1741  mbglog( LOG_ERR, "%s: Read %i bytes from netlink socket", __func__, len );
1742  #endif
1743 
1744  // parse and print the response
1745  for ( idx = 0; NLMSG_OK( nlmsg, len ); nlmsg = NLMSG_NEXT( nlmsg, len ), idx++ )
1746  {
1747  memset( &route_info, 0, sizeof( route_info ) );
1748 
1749  #if DEBUG_NETLINK
1750  mbglog( LOG_ERR, "\nnl_msg at %p, %i bytes left", nlmsg, len );
1751  #endif
1752 
1753 
1754  if ( nl_parse_routes( nlmsg, &route_info ) < 0 )
1755  continue; // don't check route_info if it has not been set up
1756 
1757  #if DEBUG_NETLINK
1758  {
1759  char ws[100];
1760  int l = sizeof( ws );
1761  int n = 0;
1762 
1763  // inet_ntoa() uses a static buffer which is overwritten on every call
1764  //##++ TODO: rather than inet_ntoa use inet_ntop which can also handle IPv6
1765  n += snprintf_safe( &ws[n], l - n, "src %s", (char *) inet_ntoa( route_info.srcAddr ) );
1766  n += snprintf_safe( &ws[n], l - n, ", dst %s", (char *) inet_ntoa( route_info.dstAddr ) );
1767  n += snprintf_safe( &ws[n], l - n, ", gw %s", (char *) inet_ntoa( route_info.gateWay ) );
1768 
1769  mbglog( LOG_ERR, "%s: route %i: %s, if \"%s\"",
1770  __func__, idx, ws, route_info.ifName );
1771  }
1772  #endif
1773 
1774  // check if default IPv4 gateway
1775  //##++ TODO: rather than inet_ntoa use inet_ntop which can also handle IPv6
1776  if ( strstr( (char *) inet_ntoa( route_info.dstAddr ), "0.0.0.0" ) )
1777  {
1778  *p_addr = ntohl( route_info.gateWay.s_addr );
1779  rc = MBG_SUCCESS;
1780  // Actually we could stop searching now. However, in case of debug
1781  // we'll continue to examine the rest of the routing message.
1782  #if DEBUG_NETLINK
1783  //##++ TODO: rather than inet_ntoa use inet_ntop which can also handle IPv6
1784  mbglog( LOG_ERR, "%s: Default gateway found: %s",
1785  __func__, (char *) inet_ntoa( route_info.gateWay ) );
1786  #else
1787  break;
1788  #endif
1789  }
1790  }
1791 
1792 out:
1793  if ( sock_fd >= 0 )
1794  close( sock_fd );
1795 
1796 #endif // defined( MBG_TGT_LINUX )
1797 
1798  if ( mbg_rc_is_error( rc ) )
1799  *p_addr = 0;
1800 
1801  return rc;
1802 
1803 } // get_ip4_gateway
1804 
1805 
1806 
1807 /*HDR*/
1826 int get_port_ip4_addr_str( const char *if_name, char *p_addr_buf, int buf_size )
1827 {
1828  IP4_ADDR addr;
1829 
1830  int rc = get_port_ip4_addr( if_name, &addr );
1831 
1832  snprint_ip4_addr( p_addr_buf, buf_size, &addr, NULL );
1833 
1834  return rc;
1835 
1836 } // get_port_ip4_addr_str
1837 
1838 
1839 
1840 /*HDR*/
1859 int get_port_ip4_netmask_str( const char *if_name, char *p_addr_buf, int buf_size )
1860 {
1861  IP4_ADDR addr;
1862 
1863  int rc = get_port_ip4_netmask( if_name, &addr );
1864 
1865  snprint_ip4_addr( p_addr_buf, buf_size, &addr, NULL );
1866 
1867  return rc;
1868 
1869 } // get_port_ip4_netmask_str
1870 
1871 
1872 
1873 /*HDR*/
1892 int get_port_ip4_broad_addr_str( const char *if_name, char *p_addr_buf, int buf_size )
1893 {
1894  IP4_ADDR addr;
1895 
1896  int rc = get_port_ip4_broad_addr( if_name, &addr );
1897 
1898  snprint_ip4_addr( p_addr_buf, buf_size, &addr, NULL );
1899 
1900  return rc;
1901 
1902 } // get_port_ip4_broad_addr_str
1903 
1904 
1905 
1906 /*HDR*/
1923 int get_port_ip4_settings( const char *if_name, IP4_SETTINGS *p )
1924 {
1925  int link_up;
1926  int rc;
1927 
1928  memset( p, 0, sizeof( *p ) );
1929 
1930  rc = get_port_ip4_addr( if_name, &p->ip_addr );
1931 
1932  if ( mbg_rc_is_error( rc ) )
1933  goto out;
1934 
1935 
1936  rc = get_port_ip4_netmask( if_name, &p->netmask );
1937 
1938  if ( mbg_rc_is_error( rc ) )
1939  goto out;
1940 
1941 
1942  rc = get_port_ip4_broad_addr( if_name, &p->broad_addr );
1943 
1944  if ( mbg_rc_is_error( rc ) )
1945  goto out;
1946 
1947 
1948 #ifndef USE_MBG_TSU
1949  rc = get_ip4_gateway( &p->gateway );
1950 
1951  if ( mbg_rc_is_error( rc ) )
1952  goto out;
1953 #endif
1954 
1955 #if 0 //### TODO
1956  // We could also try to check VLAN and DHCP settings here,
1957  // but as of now, this is specific to an application.
1958 
1959  // ##++++ The VLAN and DHCP status info collected below
1960  // just return what has been configured previously by this program,
1961  // however, it does not reflect any changes which have been made
1962  // manually, e.g. via the command line.
1963  if ( vlan_enabled )
1964  {
1965  p->flags |= IP4_MSK_VLAN;
1966  p->vlan_cfg = vlan_cfg;
1967  }
1968 
1969  if ( dhcp_enabled )
1970  p->flags |= IP4_MSK_DHCP;
1971 #endif
1972 
1973 out:
1974 
1975  // Check linkup independent from success of getting IP4 parameters
1976  link_up = check_port_link( if_name );
1977 
1978  if ( link_up )
1979  p->flags |= IP4_MSK_LINK;
1980 
1981  return rc;
1982 
1983 } // get_port_ip4_settings
1984 
1985 
size_t snprint_mac_addr(char *s, size_t max_len, const MBG_MAC_ADDR *p_mac_addr)
Print a MAC address to a string.
Definition: lan_util.c:1049
#define MAC_SEP_CHAR_ALT
Definition: lan_util.h:98
struct in_addr dstAddr
Definition: lan_util.c:160
int cidr_str_to_ip6_addr_and_cidr_bits(IP6_ADDR *p_addr, int *p_cidr, const char *cidr_str)
Convert a string in CIDR notation to an IP6_ADDR and net mask bits.
Definition: lan_util.c:859
The MAC address of a network interface.
Definition: gpsdefs.h:11031
Settings of an IPv4-only network interface.
Definition: gpsdefs.h:11239
char * strncpy_safe(char *dst, const char *src, size_t max_len)
A portable, safe implementation of strncpy()
Definition: str_util.c:247
uint32_t IP4_ADDR
An IPv4 address.
Definition: gpsdefs.h:11045
#define MAX_IP6_CIDR_NETMASK_BITS
Definition: lan_util.h:113
static int get_specific_port_ip4_addr(const char *if_name, IP4_ADDR *p_addr, int sigioc_code)
Retrieve some IPv4 address-like info from a network interface.
Definition: lan_util.c:1361
#define BYTE_2(_x)
Definition: words.h:428
void ip6_net_part_from_addr(IP6_ADDR *p_net_part, const IP6_ADDR *p_addr, const IP6_ADDR *p_mask)
Determine the network part of an IPv6 address based on the net mask.
Definition: lan_util.c:961
static int nl_parse_routes(struct nlmsghdr *nl_hdr, struct route_info *rt_info)
Definition: lan_util.c:1563
uint8_t b[6]
Definition: gpsdefs.h:11033
#define MBG_ERR_PARM_FMT
parameter string format error
Definition: mbgerror.h:365
#define MBG_ERR_INV_PARM
Invalid parameter.
Definition: mbgerror.h:329
int get_port_ip4_addr(const char *if_name, IP4_ADDR *p_addr)
Retrieve the IPv4 address of a network interface.
Definition: lan_util.c:1404
uint8_t u8
Definition: lan_util.c:98
struct in_addr gateWay
Definition: lan_util.c:162
unsigned short uint16_t
Definition: words.h:213
struct in_addr srcAddr
Definition: lan_util.c:161
#define IP6_ADDR_BITS
The number of bits used for an IPv6 address.
Definition: gpsdefs.h:11053
char IP6_ADDR_STR[(43+1)]
A buffer for an IPv6 address string.
Definition: gpsdefs.h:11091
uint64_t u64
Definition: lan_util.c:101
#define BYTE_0(_x)
Definition: words.h:426
#define mbg_rc_is_success(_rc)
Definition: mbgerror.h:618
void ip6_net_mask_from_cidr(IP6_ADDR *p_mask, int netmask_bits)
Compute an IPv6 net mask according to the number of CIDR netmask bits.
Definition: lan_util.c:918
#define MBG_ERR_RANGE
input parameter was out of range
Definition: mbgerror.h:347
bool octets_are_all_zero(const uint8_t *octets, int num_octets)
Check if an array of octets is all zero.
Definition: lan_util.c:1110
uint8_t b[8]
Definition: gpsdefs.h:13040
see IP4_BIT_LINK
Definition: gpsdefs.h:11342
A PTP clock identity.
Definition: gpsdefs.h:13038
uint16_t u16
Definition: lan_util.c:99
see IP4_BIT_DHCP
Definition: gpsdefs.h:11341
IP4_ADDR ip_addr
the IP address
Definition: gpsdefs.h:11241
static __mbg_inline IP4_ADDR ip4_net_mask_from_cidr(int netmask_bits)
Compute an IP4 net mask according to the number of CIDR netmask bits.
Definition: lan_util.h:130
see IP4_BIT_VLAN
Definition: gpsdefs.h:11343
size_t snprint_ip6_cidr_mask_addr(char *s, size_t max_len, const IP6_ADDR *p_addr, const int cidr_mask_bits, const char *info)
Print an IPv6 address plus number of net mask bits to string in CIDR notation.
Definition: lan_util.c:629
#define NUM_WORDS
#define IP4_MSB_MASK
Definition: lan_util.h:104
#define MAX_IP4_CIDR_NETMASK_BITS
Definition: lan_util.h:107
int cidr_str_to_ip6_addr_and_net_mask(IP6_ADDR *p_addr, IP6_ADDR *p_mask, const char *cidr_str)
Convert a string in CIDR notation to an IP6_ADDR and net mask.
Definition: lan_util.c:823
int do_siocg_ioctl(const char *if_name, int ioctl_code, struct ifreq *p_ifreq)
Do a SIOCGxxx IOCTL call to read specific information from a LAN interface.
Definition: lan_util.c:1155
MBG_VLAN_CFG vlan_cfg
VLAN configuration.
Definition: gpsdefs.h:11246
#define MIN_IP4_CIDR_NETMASK_BITS
Definition: lan_util.h:106
int str_to_octets(uint8_t *octets, int num_octets, const char *s)
Set a MAC ID or a similar array of octets from a string.
Definition: lan_util.c:1071
uint16_t flags
see MBG_IP4_FLAG_MASKS
Definition: gpsdefs.h:11245
size_t snprint_ip4_cidr_addr(char *s, size_t max_len, const IP4_ADDR *p_addr, const IP4_ADDR *p_mask, const char *info)
Print an IPv4 address plus net mask in CIDR notation to a string.
Definition: lan_util.c:255
int get_port_intf_idx(const char *if_name, int *p_intf_idx)
Retrieve the index of a specific network interface.
Definition: lan_util.c:1197
bool mac_addr_is_all_zero(const MBG_MAC_ADDR *p_addr)
Check if a MAC address is all zero.
Definition: lan_util.c:1135
int get_ip4_net_mask_bits(const IP4_ADDR *p_mask)
Count the number of sequential bits in an IPv4 net mask.
Definition: lan_util.c:183
int get_ip4_gateway(IP4_ADDR *p_addr)
Retrieve the IPv4 gateway (default route)
Definition: lan_util.c:1679
int get_port_ip4_netmask_str(const char *if_name, char *p_addr_buf, int buf_size)
Retrieve the IPv4 net mask of a network interface as string.
Definition: lan_util.c:1859
int get_port_ip4_broad_addr_str(const char *if_name, char *p_addr_buf, int buf_size)
Retrieve the IPv4 broadcast address of a network interface as string.
Definition: lan_util.c:1892
#define BYTE_1(_x)
Definition: words.h:427
#define MAC_SEP_CHAR
Definition: lan_util.h:94
unsigned char uint8_t
Definition: words.h:210
#define MBG_SUCCESS
Error codes used with Meinberg devices and drivers.
Definition: mbgerror.h:259
uint8_t b[(128/8)]
bytes holding the address bits (not the string notation), b[0] == LSBs
Definition: gpsdefs.h:11063
int get_port_ip4_broad_addr(const char *if_name, IP4_ADDR *p_addr)
Retrieve the IPv4 broadcast address of a network interface.
Definition: lan_util.c:1456
size_t snprint_ip6_cidr_addr(char *s, size_t max_len, const IP6_ADDR *p_addr, const IP6_ADDR *p_mask, const char *info)
Print an IPv6 address plus net mask to string in CIDR notation.
Definition: lan_util.c:592
#define MAX_IP4_BITS
Definition: lan_util.h:102
int str_to_ip6_addr(IP6_ADDR *p_addr, const char *s)
Convert a string to an IP6_ADDR.
Definition: lan_util.c:673
IP4_ADDR netmask
the network mask
Definition: gpsdefs.h:11242
int check_port_link(const char *if_name)
Check the link state of a network interface.
Definition: lan_util.c:1267
char ifName[IF_NAMESIZE]
Definition: lan_util.c:163
int get_port_ip4_addr_str(const char *if_name, char *p_addr_buf, int buf_size)
Retrieve the IPv4 address of a network interface as string.
Definition: lan_util.c:1826
#define IP6_ADDR_BYTES
The number of bytes used for an IPv6 address.
Definition: gpsdefs.h:11056
int get_port_ip4_settings(const char *if_name, IP4_SETTINGS *p)
Retrieve the current IPv4 settings of a network interface.
Definition: lan_util.c:1923
static int nl_read(int sock_fd, char *buf_ptr, size_t buf_size, int seq_num, int pid)
Read a requested message from the netlink socket.
Definition: lan_util.c:1472
int snprintf_safe(char *s, size_t max_len, const char *fmt,...)
A portable, safe implementation of snprintf()
Definition: str_util.c:156
#define MBG_ERR_DATA_FMT
invalid data format
Definition: mbgerror.h:359
int check_port_status(const char *if_name, int *p_speed, int *p_duplex)
Check the state of a network interface.
Definition: lan_util.c:1302
IP4_ADDR gateway
the default gateway
Definition: gpsdefs.h:11244
#define IP6_MSB_MASK
Definition: lan_util.h:110
#define MBG_ERR_OVERFLOW
range or buffer overflow
Definition: mbgerror.h:333
int get_port_ip4_netmask(const char *if_name, IP4_ADDR *p_addr)
Retrieve the IPv4 net mask of a network interface.
Definition: lan_util.c:1430
size_t snprint_ip4_addr(char *s, size_t max_len, const IP4_ADDR *p_addr, const char *info)
Print an IPv4 address to a dotted quad formatted string.
Definition: lan_util.c:217
int mbg_get_last_socket_error(const char *info)
Get and translate last error after socket function call.
Definition: mbgerror.c:1038
#define mbg_rc_is_error(_rc)
Definition: mbgerror.h:617
int get_ip6_net_mask_bits(const IP6_ADDR *p_mask)
Count the number of sequential bits in an IPv6 net mask.
Definition: lan_util.c:417
const char * mbg_strerror(int mbg_errno)
Return an error string associated with the MBG_ERROR_CODES.
Definition: mbgerror.c:685
int cidr_str_to_ip4_addr_and_net_mask(IP4_ADDR *p_addr, IP4_ADDR *p_mask, const char *cidr_str)
Convert a string in CIDR notation to an IP4_ADDR and net mask.
Definition: lan_util.c:349
#define BYTE_OF(_v, _n)
Definition: words.h:440
unsigned __int64 uint64_t
Definition: words.h:250
#define MIN_IP6_CIDR_NETMASK_BITS
Definition: lan_util.h:112
size_t snprint_ip6_addr(char *s, size_t max_len, const IP6_ADDR *p_addr, const char *info)
Print an IPv6 address in optimized format to a string.
Definition: lan_util.c:463
size_t snprint_octets(char *s, size_t max_len, const uint8_t *octets, int num_octets, char sep, const char *info)
Print a MAC ID or similar array of octets to a string.
Definition: lan_util.c:990
int str_to_ip4_addr(IP4_ADDR *p_addr, const char *s)
Convert a string to an IP4_ADDR.
Definition: lan_util.c:291
#define MBG_ERR_NOT_SUPP_ON_OS
Function is not supported on this operating system.
Definition: mbgerror.h:289
IP4_ADDR broad_addr
the broadcast address
Definition: gpsdefs.h:11243
#define BYTE_3(_x)
Definition: words.h:429
unsigned long ulong
Definition: words.h:292
size_t snprint_ptp_clock_id(char *s, size_t max_len, const PTP_CLOCK_ID *p)
Print a PTP_CLOCK_ID to a string.
Definition: lan_util.c:1027
int get_port_mac_addr(const char *if_name, MBG_MAC_ADDR *p_mac_addr)
Retrieve the MAC address of a network interface.
Definition: lan_util.c:1232
An IPv6 address.
Definition: gpsdefs.h:11061
uint32_t u32
Definition: lan_util.c:100