Codebase list lldpd / e00b9d3
Imported Upstream version 0.2 Vincent Bernat 15 years ago
22 changed file(s) with 1999 addition(s) and 394 deletion(s). Raw diff Collapse all Expand all
0 lldpd (0.2)
1
2 * Add privilege separation
3 * Add FDP support
4 * Support CDP encapsulated into native VLAN
5 * Various fixes
6
7 -- Vincent Bernat <bernat@luffy.cx>
8
9 lldpd (0.1)
10
11 * Initial release
12
13 -- Vincent Bernat <bernat@luffy.cx>
14
1919 be mapped on the bonding device. You can bridge vlan but not add vlans
2020 on bridges. More complex setups may give false results.
2121
22 lldpctl allows to query information collected through the command line.
22 lldpd uses privilege separation to increase its security. Two
23 processes, one running as root and doing minimal stuff and the other
24 running as an unprivileged user into a chroot doing most of the stuff,
25 are cooperating. You need to create a user called "_lldpd" in a group
26 "_lldpd" (this can be change with ./configure). You also need to
27 create an empty directory "/var/run/lldpd" (it needs to be owned by
28 root, not "_lldpd"!).
2329
24 lldpd also implements CDP (Cisco Discovery Protocol), SONMP (Nortel
25 Discovery Protocol) and EDP (Extreme Discovery Protocol). However,
26 recent versions of IOS should support LLDP and most Extreme stuff
27 support LLDP. When a EDP, CDP or SONMP frame is received on a given
28 interface, lldpd starts sending EDP, CDP or SONMP frame on this
29 interface. Informations collected through EDP/CDP/SONMP are integrated
30 with other informations and can be queried with lldpctl or through
31 SNMP.
30 lldpctl allows to query information collected through the command
31 line. If you don't want to run it as root, just install it setuid or
32 setgid _lldpd.
33
34 lldpd also implements CDP (Cisco Discovery Protocol), FDP (Foundry
35 Discovery Protocol), SONMP (Nortel Discovery Protocol) and EDP
36 (Extreme Discovery Protocol). However, recent versions of IOS should
37 support LLDP and most Extreme stuff support LLDP. When a EDP, CDP or
38 SONMP frame is received on a given interface, lldpd starts sending
39 EDP, CDP, FDP or SONMP frame on this interface. Informations collected
40 through EDP/CDP/FDP/SONMP are integrated with other informations and
41 can be queried with lldpctl or through SNMP.
3242
3343 For bonding, you need 2.6.24 (in previous version, PACKET_ORIGDEV
3444 affected only non multicast packets). See:
00 /* config.h.in. Generated from configure.ac by autoheader. */
1
2 /* Define to 1 if you have the declaration of `ADVERTISED_2500baseX_Full', and
3 to 0 if you don't. */
4 #undef HAVE_DECL_ADVERTISED_2500BASEX_FULL
5
6 /* Define to 1 if you have the declaration of `ETHERTYPE_VLAN', and to 0 if
7 you don't. */
8 #undef HAVE_DECL_ETHERTYPE_VLAN
9
10 /* Define to 1 if you have the declaration of `PACKET_ORIGDEV', and to 0 if
11 you don't. */
12 #undef HAVE_DECL_PACKET_ORIGDEV
113
214 /* Define to 1 if you have the declaration of `TAILQ_EMPTY', and to 0 if you
315 don't. */
3244
3345 /* Define to indicate the Net-SNMP library */
3446 #undef HAVE_NETSNMP
47
48 /* Define to 1 if `f_create_from_tstring_new' is member of `netsnmp_tdomain'.
49 */
50 #undef HAVE_NETSNMP_TDOMAIN_F_CREATE_FROM_TSTRING_NEW
3551
3652 /* Define to 1 if you have the <stdint.h> header file. */
3753 #undef HAVE_STDINT_H
84100 /* Define to the version of this package. */
85101 #undef PACKAGE_VERSION
86102
103 /* Chroot directory */
104 #undef PRIVSEP_CHROOT
105
106 /* Group for privilege separation */
107 #undef PRIVSEP_GROUP
108
109 /* User for privilege separation */
110 #undef PRIVSEP_USER
111
87112 /* Define to 1 if you have the ANSI C header files. */
88113 #undef STDC_HEADERS
89114
00 #! /bin/sh
11 # Guess values for system-dependent variables and create Makefiles.
2 # Generated by GNU Autoconf 2.61 for lldpd 0.1.
2 # Generated by GNU Autoconf 2.61 for lldpd 0.2.
33 #
44 # Report bugs to <bernat@luffy.cx>.
55 #
573573 # Identity of this package.
574574 PACKAGE_NAME='lldpd'
575575 PACKAGE_TARNAME='lldpd'
576 PACKAGE_VERSION='0.1'
577 PACKAGE_STRING='lldpd 0.1'
576 PACKAGE_VERSION='0.2'
577 PACKAGE_STRING='lldpd 0.2'
578578 PACKAGE_BUGREPORT='bernat@luffy.cx'
579579
580580 ac_unique_file="src/lldpd.c"
12101210 # Omit some internal or obsolete options to make the list less imposing.
12111211 # This message is too long to be a string in the A/UX 3.1 sh.
12121212 cat <<_ACEOF
1213 \`configure' configures lldpd 0.1 to adapt to many kinds of systems.
1213 \`configure' configures lldpd 0.2 to adapt to many kinds of systems.
12141214
12151215 Usage: $0 [OPTION]... [VAR=VALUE]...
12161216
12761276
12771277 if test -n "$ac_init_help"; then
12781278 case $ac_init_help in
1279 short | recursive ) echo "Configuration of lldpd 0.1:";;
1279 short | recursive ) echo "Configuration of lldpd 0.2:";;
12801280 esac
12811281 cat <<\_ACEOF
12821282
12901290 --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
12911291 --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
12921292 --with-snmp Enable the use of SNMP
1293 --with-privsep-user Which user to use for privilege separation
1294 --with-privsep-group Which group to use for privilege separation
1295 --with-privsep-chroot Which directory to use to chroot lldpd
12931296
12941297 Some influential environment variables:
12951298 CC C compiler command
13651368 test -n "$ac_init_help" && exit $ac_status
13661369 if $ac_init_version; then
13671370 cat <<\_ACEOF
1368 lldpd configure 0.1
1371 lldpd configure 0.2
13691372 generated by GNU Autoconf 2.61
13701373
13711374 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
13791382 This file contains any messages produced by compilers while
13801383 running configure, to aid debugging if configure makes a mistake.
13811384
1382 It was created by lldpd $as_me 0.1, which was
1385 It was created by lldpd $as_me 0.2, which was
13831386 generated by GNU Autoconf 2.61. Invocation command line was
13841387
13851388 $ $0 $@
20692072
20702073 # Define the identity of the package.
20712074 PACKAGE='lldpd'
2072 VERSION='0.1'
2075 VERSION='0.2'
20732076
20742077
20752078 cat >>confdefs.h <<_ACEOF
33313334 fi
33323335
33333336
3337
3338 # Check whether --with-privsep-user was given.
3339 if test "${with_privsep_user+set}" = set; then
3340 withval=$with_privsep_user;
3341 cat >>confdefs.h <<_ACEOF
3342 #define PRIVSEP_USER "$withval"
3343 _ACEOF
3344
3345 else
3346
3347 cat >>confdefs.h <<_ACEOF
3348 #define PRIVSEP_USER "_lldpd"
3349 _ACEOF
3350
3351 fi
3352
3353
3354 # Check whether --with-privsep-group was given.
3355 if test "${with_privsep_group+set}" = set; then
3356 withval=$with_privsep_group;
3357 cat >>confdefs.h <<_ACEOF
3358 #define PRIVSEP_GROUP "$withval"
3359 _ACEOF
3360
3361 else
3362
3363 cat >>confdefs.h <<_ACEOF
3364 #define PRIVSEP_GROUP "_lldpd"
3365 _ACEOF
3366
3367 fi
3368
3369
3370 # Check whether --with-privsep-chroot was given.
3371 if test "${with_privsep_chroot+set}" = set; then
3372 withval=$with_privsep_chroot;
3373 cat >>confdefs.h <<_ACEOF
3374 #define PRIVSEP_CHROOT "$withval"
3375 _ACEOF
3376
3377 else
3378
3379 cat >>confdefs.h <<_ACEOF
3380 #define PRIVSEP_CHROOT "/var/run/lldpd"
3381 _ACEOF
3382
3383 fi
3384
3385
33343386 # Checks for header files.
33353387
33363388 { echo "$as_me:$LINENO: checking whether TAILQ_FIRST is declared" >&5
36563708 fi
36573709 { echo "$as_me:$LINENO: result: $ac_cv_have_decl_PACKET_ORIGDEV" >&5
36583710 echo "${ECHO_T}$ac_cv_have_decl_PACKET_ORIGDEV" >&6; }
3711 if test $ac_cv_have_decl_PACKET_ORIGDEV = yes; then
3712
3713 cat >>confdefs.h <<_ACEOF
3714 #define HAVE_DECL_PACKET_ORIGDEV 1
3715 _ACEOF
3716
3717
3718 else
3719 cat >>confdefs.h <<_ACEOF
3720 #define HAVE_DECL_PACKET_ORIGDEV 0
3721 _ACEOF
3722
3723
3724 fi
3725
36593726
36603727 { echo "$as_me:$LINENO: checking whether ADVERTISED_2500baseX_Full is declared" >&5
36613728 echo $ECHO_N "checking whether ADVERTISED_2500baseX_Full is declared... $ECHO_C" >&6; }
37103777 fi
37113778 { echo "$as_me:$LINENO: result: $ac_cv_have_decl_ADVERTISED_2500baseX_Full" >&5
37123779 echo "${ECHO_T}$ac_cv_have_decl_ADVERTISED_2500baseX_Full" >&6; }
3780 if test $ac_cv_have_decl_ADVERTISED_2500baseX_Full = yes; then
3781
3782 cat >>confdefs.h <<_ACEOF
3783 #define HAVE_DECL_ADVERTISED_2500BASEX_FULL 1
3784 _ACEOF
3785
3786
3787 else
3788 cat >>confdefs.h <<_ACEOF
3789 #define HAVE_DECL_ADVERTISED_2500BASEX_FULL 0
3790 _ACEOF
3791
3792
3793 fi
3794
3795
3796 { echo "$as_me:$LINENO: checking whether ETHERTYPE_VLAN is declared" >&5
3797 echo $ECHO_N "checking whether ETHERTYPE_VLAN is declared... $ECHO_C" >&6; }
3798 if test "${ac_cv_have_decl_ETHERTYPE_VLAN+set}" = set; then
3799 echo $ECHO_N "(cached) $ECHO_C" >&6
3800 else
3801 cat >conftest.$ac_ext <<_ACEOF
3802 /* confdefs.h. */
3803 _ACEOF
3804 cat confdefs.h >>conftest.$ac_ext
3805 cat >>conftest.$ac_ext <<_ACEOF
3806 /* end confdefs.h. */
3807 #include <net/ethernet.h>
3808
3809 int
3810 main ()
3811 {
3812 #ifndef ETHERTYPE_VLAN
3813 (void) ETHERTYPE_VLAN;
3814 #endif
3815
3816 ;
3817 return 0;
3818 }
3819 _ACEOF
3820 rm -f conftest.$ac_objext
3821 if { (ac_try="$ac_compile"
3822 case "(($ac_try" in
3823 *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
3824 *) ac_try_echo=$ac_try;;
3825 esac
3826 eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
3827 (eval "$ac_compile") 2>conftest.er1
3828 ac_status=$?
3829 grep -v '^ *+' conftest.er1 >conftest.err
3830 rm -f conftest.er1
3831 cat conftest.err >&5
3832 echo "$as_me:$LINENO: \$? = $ac_status" >&5
3833 (exit $ac_status); } && {
3834 test -z "$ac_c_werror_flag" ||
3835 test ! -s conftest.err
3836 } && test -s conftest.$ac_objext; then
3837 ac_cv_have_decl_ETHERTYPE_VLAN=yes
3838 else
3839 echo "$as_me: failed program was:" >&5
3840 sed 's/^/| /' conftest.$ac_ext >&5
3841
3842 ac_cv_have_decl_ETHERTYPE_VLAN=no
3843 fi
3844
3845 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
3846 fi
3847 { echo "$as_me:$LINENO: result: $ac_cv_have_decl_ETHERTYPE_VLAN" >&5
3848 echo "${ECHO_T}$ac_cv_have_decl_ETHERTYPE_VLAN" >&6; }
3849 if test $ac_cv_have_decl_ETHERTYPE_VLAN = yes; then
3850
3851 cat >>confdefs.h <<_ACEOF
3852 #define HAVE_DECL_ETHERTYPE_VLAN 1
3853 _ACEOF
3854
3855
3856 else
3857 cat >>confdefs.h <<_ACEOF
3858 #define HAVE_DECL_ETHERTYPE_VLAN 0
3859 _ACEOF
3860
3861
3862 fi
3863
37133864
37143865
37153866 # Checks for typedefs, structures, and compiler characteristics.
48464997 { (exit 1); exit 1; }; }
48474998 fi
48484999
5000 { echo "$as_me:$LINENO: checking for netsnmp_tdomain.f_create_from_tstring_new" >&5
5001 echo $ECHO_N "checking for netsnmp_tdomain.f_create_from_tstring_new... $ECHO_C" >&6; }
5002 if test "${ac_cv_member_netsnmp_tdomain_f_create_from_tstring_new+set}" = set; then
5003 echo $ECHO_N "(cached) $ECHO_C" >&6
5004 else
5005 cat >conftest.$ac_ext <<_ACEOF
5006 /* confdefs.h. */
5007 _ACEOF
5008 cat confdefs.h >>conftest.$ac_ext
5009 cat >>conftest.$ac_ext <<_ACEOF
5010 /* end confdefs.h. */
5011
5012 #include <net-snmp/net-snmp-config.h>
5013 #include <net-snmp/net-snmp-includes.h>
5014 #include <net-snmp/library/snmp_transport.h>
5015
5016
5017 int
5018 main ()
5019 {
5020 static netsnmp_tdomain ac_aggr;
5021 if (ac_aggr.f_create_from_tstring_new)
5022 return 0;
5023 ;
5024 return 0;
5025 }
5026 _ACEOF
5027 rm -f conftest.$ac_objext
5028 if { (ac_try="$ac_compile"
5029 case "(($ac_try" in
5030 *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
5031 *) ac_try_echo=$ac_try;;
5032 esac
5033 eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
5034 (eval "$ac_compile") 2>conftest.er1
5035 ac_status=$?
5036 grep -v '^ *+' conftest.er1 >conftest.err
5037 rm -f conftest.er1
5038 cat conftest.err >&5
5039 echo "$as_me:$LINENO: \$? = $ac_status" >&5
5040 (exit $ac_status); } && {
5041 test -z "$ac_c_werror_flag" ||
5042 test ! -s conftest.err
5043 } && test -s conftest.$ac_objext; then
5044 ac_cv_member_netsnmp_tdomain_f_create_from_tstring_new=yes
5045 else
5046 echo "$as_me: failed program was:" >&5
5047 sed 's/^/| /' conftest.$ac_ext >&5
5048
5049 cat >conftest.$ac_ext <<_ACEOF
5050 /* confdefs.h. */
5051 _ACEOF
5052 cat confdefs.h >>conftest.$ac_ext
5053 cat >>conftest.$ac_ext <<_ACEOF
5054 /* end confdefs.h. */
5055
5056 #include <net-snmp/net-snmp-config.h>
5057 #include <net-snmp/net-snmp-includes.h>
5058 #include <net-snmp/library/snmp_transport.h>
5059
5060
5061 int
5062 main ()
5063 {
5064 static netsnmp_tdomain ac_aggr;
5065 if (sizeof ac_aggr.f_create_from_tstring_new)
5066 return 0;
5067 ;
5068 return 0;
5069 }
5070 _ACEOF
5071 rm -f conftest.$ac_objext
5072 if { (ac_try="$ac_compile"
5073 case "(($ac_try" in
5074 *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
5075 *) ac_try_echo=$ac_try;;
5076 esac
5077 eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
5078 (eval "$ac_compile") 2>conftest.er1
5079 ac_status=$?
5080 grep -v '^ *+' conftest.er1 >conftest.err
5081 rm -f conftest.er1
5082 cat conftest.err >&5
5083 echo "$as_me:$LINENO: \$? = $ac_status" >&5
5084 (exit $ac_status); } && {
5085 test -z "$ac_c_werror_flag" ||
5086 test ! -s conftest.err
5087 } && test -s conftest.$ac_objext; then
5088 ac_cv_member_netsnmp_tdomain_f_create_from_tstring_new=yes
5089 else
5090 echo "$as_me: failed program was:" >&5
5091 sed 's/^/| /' conftest.$ac_ext >&5
5092
5093 ac_cv_member_netsnmp_tdomain_f_create_from_tstring_new=no
5094 fi
5095
5096 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
5097 fi
5098
5099 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
5100 fi
5101 { echo "$as_me:$LINENO: result: $ac_cv_member_netsnmp_tdomain_f_create_from_tstring_new" >&5
5102 echo "${ECHO_T}$ac_cv_member_netsnmp_tdomain_f_create_from_tstring_new" >&6; }
5103 if test $ac_cv_member_netsnmp_tdomain_f_create_from_tstring_new = yes; then
5104
5105 cat >>confdefs.h <<_ACEOF
5106 #define HAVE_NETSNMP_TDOMAIN_F_CREATE_FROM_TSTRING_NEW 1
5107 _ACEOF
5108
5109
5110 fi
5111
48495112
48505113 # Checks for library functions.
48515114
56225885 # report actual input values of CONFIG_FILES etc. instead of their
56235886 # values after options handling.
56245887 ac_log="
5625 This file was extended by lldpd $as_me 0.1, which was
5888 This file was extended by lldpd $as_me 0.2, which was
56265889 generated by GNU Autoconf 2.61. Invocation command line was
56275890
56285891 CONFIG_FILES = $CONFIG_FILES
56755938 _ACEOF
56765939 cat >>$CONFIG_STATUS <<_ACEOF
56775940 ac_cs_version="\\
5678 lldpd config.status 0.1
5941 lldpd config.status 0.2
56795942 configured by $0, generated by GNU Autoconf 2.61,
56805943 with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
56815944
11 # Process this file with autoconf to produce a configure script.
22
33 AC_PREREQ(2.61)
4 AC_INIT(lldpd, 0.1, bernat@luffy.cx)
4 AC_INIT(lldpd, 0.2, bernat@luffy.cx)
55 AM_INIT_AUTOMAKE([foreign])
66 AC_CONFIG_SRCDIR([src/lldpd.c])
77 AC_CONFIG_HEADER([config.h])
2121 )
2222 AM_CONDITIONAL([USE_SNMP], [test "${with_snmp}" != "no"])
2323
24 AC_ARG_WITH(privsep-user,
25 AC_HELP_STRING([--with-privsep-user],
26 [Which user to use for privilege separation]),
27 AC_DEFINE_UNQUOTED([PRIVSEP_USER], "$withval", [User for privilege separation]),
28 AC_DEFINE_UNQUOTED([PRIVSEP_USER], "_lldpd", [User for privilege separation]))
29 AC_ARG_WITH(privsep-group,
30 AC_HELP_STRING([--with-privsep-group],
31 [Which group to use for privilege separation]),
32 AC_DEFINE_UNQUOTED([PRIVSEP_GROUP], "$withval", [Group for privilege separation]),
33 AC_DEFINE_UNQUOTED([PRIVSEP_GROUP], "_lldpd", [Group for privilege separation]))
34 AC_ARG_WITH(privsep-chroot,
35 AC_HELP_STRING([--with-privsep-chroot],
36 [Which directory to use to chroot lldpd]),
37 AC_DEFINE_UNQUOTED([PRIVSEP_CHROOT], "$withval", [Chroot directory]),
38 AC_DEFINE_UNQUOTED([PRIVSEP_CHROOT], "/var/run/lldpd", [Chroot directory]))
39
2440 # Checks for header files.
2541 AC_CHECK_DECLS([TAILQ_FIRST, TAILQ_NEXT, TAILQ_FOREACH, TAILQ_EMPTY],[],[],[[#include <sys/queue.h>]])
26 AC_CHECK_DECL([PACKET_ORIGDEV],[],[],[[#include <linux/if_packet.h>]])
27 AC_CHECK_DECL([ADVERTISED_2500baseX_Full],[],[],[[#include <linux/ethtool.h>]])
42 AC_CHECK_DECLS([PACKET_ORIGDEV],[],[],[[#include <linux/if_packet.h>]])
43 AC_CHECK_DECLS([ADVERTISED_2500baseX_Full],[],[],[[#include <linux/ethtool.h>]])
44 AC_CHECK_DECLS([ETHERTYPE_VLAN],[],[],[[#include <net/ethernet.h>]])
2845
2946 # Checks for typedefs, structures, and compiler characteristics.
3047 AC_C_CONST
3148 AC_CHECK_TYPES([int16_t, u_int16_t, int8_t, u_int8_t, int32_t, u_int32_t],[],[AC_MSG_ERROR([mandatory type not found])])
49 AC_CHECK_MEMBERS([netsnmp_tdomain.f_create_from_tstring_new],,,
50 [
51 #include <net-snmp/net-snmp-config.h>
52 #include <net-snmp/net-snmp-includes.h>
53 #include <net-snmp/library/snmp_transport.h>
54 ])
3255
3356 # Checks for library functions.
3457 AC_REPLACE_FUNCS([strlcpy])
2020 .Nd LLDP daemon
2121 .Sh SYNOPSIS
2222 .Nm
23 .Op Fl dxcse
23 .Op Fl dvxcse
2424 .Op Fl m Ar management
2525 .Op Fl p Ar probe time
2626 .Sh DESCRIPTION
5353 will run in the foreground and log to
5454 .Em stderr .
5555 This option can be specified many times to increase verbosity.
56 .It Fl v
57 Listen on VLAN as well. This option might be needed if your equipment
58 send frames on VLAN instead of physical interface. This option enables
59 .Nm
60 to receive frames on VLAN interfaces as well. If you don't need this
61 option, do not set it.
5662 .It Fl x
5763 Enable SNMP subagent
5864 With this option,
6167 information about local system and remote systems through SNMP.
6268 .It Fl c
6369 Enable the support of CDP protocol to deal with Cisco routers that do
70 not speak LLDP.
71 .It Fl f
72 Enable the support of FDP protocol to deal with Foundry routers that do
6473 not speak LLDP.
6574 .It Fl s
6675 Enable the support of SONMP protocol to deal with Nortel routers and
00 sbin_PROGRAMS = lldpd lldpctl
11
22 COMMON = log.c ctl.c lldpd.h lldp.h cdp.h compat.h sonmp.h llc.h edp.h
3 lldpd_SOURCES = lldpd.c lldp.c cdp.c sonmp.c edp.c iov.c features.c $(COMMON)
3 lldpd_SOURCES = lldpd.c lldp.c cdp.c sonmp.c edp.c iov.c features.c client.c priv.c privsep_fdpass.c $(COMMON)
44 lldpctl_SOURCES = lldpctl.c $(COMMON)
55
66 lldpd_LDADD = @LIBOBJS@
77 lldpctl_LDADD = @LIBOBJS@
88
99 if USE_SNMP
10 lldpd_SOURCES += agent.c
10 lldpd_SOURCES += agent.c agent_priv.c
1111 lldpd_LDADD += @NETSNMP_LIB@
1212 endif
3030 PRE_UNINSTALL = :
3131 POST_UNINSTALL = :
3232 sbin_PROGRAMS = lldpd$(EXEEXT) lldpctl$(EXEEXT)
33 @USE_SNMP_TRUE@am__append_1 = agent.c
33 @USE_SNMP_TRUE@am__append_1 = agent.c agent_priv.c
3434 @USE_SNMP_TRUE@am__append_2 = @NETSNMP_LIB@
3535 subdir = src
3636 DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in strlcpy.c
4949 lldpctl_OBJECTS = $(am_lldpctl_OBJECTS)
5050 lldpctl_DEPENDENCIES = @LIBOBJS@
5151 am__lldpd_SOURCES_DIST = lldpd.c lldp.c cdp.c sonmp.c edp.c iov.c \
52 features.c log.c ctl.c lldpd.h lldp.h cdp.h compat.h sonmp.h \
53 llc.h edp.h agent.c
54 @USE_SNMP_TRUE@am__objects_2 = agent.$(OBJEXT)
52 features.c client.c priv.c privsep_fdpass.c log.c ctl.c \
53 lldpd.h lldp.h cdp.h compat.h sonmp.h llc.h edp.h agent.c \
54 agent_priv.c
55 @USE_SNMP_TRUE@am__objects_2 = agent.$(OBJEXT) agent_priv.$(OBJEXT)
5556 am_lldpd_OBJECTS = lldpd.$(OBJEXT) lldp.$(OBJEXT) cdp.$(OBJEXT) \
5657 sonmp.$(OBJEXT) edp.$(OBJEXT) iov.$(OBJEXT) features.$(OBJEXT) \
58 client.$(OBJEXT) priv.$(OBJEXT) privsep_fdpass.$(OBJEXT) \
5759 $(am__objects_1) $(am__objects_2)
5860 lldpd_OBJECTS = $(am_lldpd_OBJECTS)
5961 am__DEPENDENCIES_1 =
158160 top_srcdir = @top_srcdir@
159161 COMMON = log.c ctl.c lldpd.h lldp.h cdp.h compat.h sonmp.h llc.h edp.h
160162 lldpd_SOURCES = lldpd.c lldp.c cdp.c sonmp.c edp.c iov.c features.c \
161 $(COMMON) $(am__append_1)
163 client.c priv.c privsep_fdpass.c $(COMMON) $(am__append_1)
162164 lldpctl_SOURCES = lldpctl.c $(COMMON)
163165 lldpd_LDADD = @LIBOBJS@ $(am__append_2)
164166 lldpctl_LDADD = @LIBOBJS@
233235
234236 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strlcpy.Po@am__quote@
235237 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/agent.Po@am__quote@
238 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/agent_priv.Po@am__quote@
236239 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdp.Po@am__quote@
240 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Po@am__quote@
237241 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctl.Po@am__quote@
238242 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edp.Po@am__quote@
239243 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/features.Po@am__quote@
242246 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lldpctl.Po@am__quote@
243247 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lldpd.Po@am__quote@
244248 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
249 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/priv.Po@am__quote@
250 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/privsep_fdpass.Po@am__quote@
245251 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sonmp.Po@am__quote@
246252
247253 .c.o:
435435 return (u_char *)&long_ret;
436436 case LLDP_SNMP_STATS_RX_DISCARDED:
437437 case LLDP_SNMP_STATS_RX_ERRORS:
438 /* We discard only frame with errors. Therefore, the two values
439 * are equal */
438440 long_ret = hardware->h_rx_discarded_cnt;
439441 return (u_char *)&long_ret;
440442 case LLDP_SNMP_STATS_RX_TLVDISCARDED:
441443 case LLDP_SNMP_STATS_RX_TLVUNRECOGNIZED:
442 /* Not really handled */
443 long_ret = 0;
444 /* We discard only unrecognized TLV. Malformed TLV
445 implies dropping the whole frame */
446 long_ret = hardware->h_rx_unrecognized_cnt;
444447 return (u_char *)&long_ret;
445448 case LLDP_SNMP_STATS_RX_AGEOUTS:
446449 long_ret = hardware->h_rx_ageout_cnt;
794797
795798 scfg = cfg;
796799
800 /* We are chrooted, we don't want to handle persistent states */
801 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
802 NETSNMP_DS_LIB_DONT_PERSIST_STATE, TRUE);
803 /* Do not load any MIB */
804 setenv("MIBS", "", 1);
805
806 /* We provide our UNIX domain transport */
807 agent_priv_register_domain();
808
797809 init_agent("lldpAgent");
798
799810 REGISTER_MIB("lldp", lldp_vars, variable8, lldp_oid);
800
801811 init_snmp("lldpAgent");
802812
803813 if ((rc = register_sysORTable(lldp_oid, OID_LENGTH(lldp_oid),
0 /*
1 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
2 *
3 * Permission to use, copy, modify, and distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16 /* Some of the code here (agent_priv_unix_*) has been adapted from code from
17 * Net-SNMP project (snmplib/snmpUnixDomain.c). Net-SNMP project is licensed
18 * using BSD and BSD-like licenses. I don't know the exact license of the file
19 * snmplib/snmpUnixDomain.c. */
20
21 #include "lldpd.h"
22
23 #include <unistd.h>
24 #include <errno.h>
25
26 #include <net-snmp/net-snmp-config.h>
27 #include <net-snmp/net-snmp-includes.h>
28 #include <net-snmp/agent/net-snmp-agent-includes.h>
29 #include <net-snmp/agent/snmp_vars.h>
30 #include <net-snmp/agent/util_funcs.h>
31 #include <net-snmp/library/snmpUnixDomain.h>
32
33 oid netsnmp_UnixDomain[] = { TRANSPORT_DOMAIN_LOCAL };
34 static netsnmp_tdomain unixDomain;
35
36 static char *
37 agent_priv_unix_fmtaddr(netsnmp_transport *t, void *data, int len)
38 {
39 /* We don't bother to implement the full function */
40 return strdup("Local Unix socket with privilege separation: unknown");
41 }
42
43 static int
44 agent_priv_unix_recv(netsnmp_transport *t, void *buf, int size,
45 void **opaque, int *olength)
46 {
47 int rc = -1;
48 socklen_t tolen = sizeof(struct sockaddr_un);
49 struct sockaddr *to = NULL;
50
51 if (t == NULL || t->sock < 0)
52 goto recv_error;
53 to = (struct sockaddr *)malloc(sizeof(struct sockaddr_un));
54 if (to == NULL)
55 goto recv_error;
56 memset(to, 0, tolen);
57 if (getsockname(t->sock, to, &tolen) != 0)
58 goto recv_error;
59 while (rc < 0) {
60 rc = recv(t->sock, buf, size, 0);
61 if (rc < 0 && errno != EINTR) {
62 LLOG_WARN("unable to receive from fd %d",
63 t->sock);
64 goto recv_error;
65 }
66 }
67 *opaque = (void*)to;
68 *olength = sizeof(struct sockaddr_un);
69 return rc;
70
71 recv_error:
72 free(to);
73 *opaque = NULL;
74 *olength = 0;
75 return -1;
76 }
77
78 static int
79 agent_priv_unix_send(netsnmp_transport *t, void *buf, int size,
80 void **opaque, int *olength)
81 {
82 int rc = -1;
83 if (t != NULL && t->sock >= 0) {
84 while (rc < 0) {
85 rc = send(t->sock, buf, size, 0);
86 if (rc < 0 && errno != EINTR) {
87 break;
88 }
89 }
90 }
91 return rc;
92 }
93
94 static int
95 agent_priv_unix_close(netsnmp_transport *t)
96 {
97 int rc = 0;
98
99 if (t->sock >= 0) {
100 rc = close(t->sock);
101 t->sock = -1;
102 return rc;
103 }
104 return -1;
105 }
106
107 static int
108 agent_priv_unix_accept(netsnmp_transport *t)
109 {
110 LLOG_WARNX("should not have been called");
111 return -1;
112 }
113
114 netsnmp_transport *
115 agent_priv_unix_transport(const char *string, int len, int local)
116 {
117 struct sockaddr_un addr;
118 netsnmp_transport *t = NULL;
119
120 if (local) {
121 LLOG_WARNX("should not have been called for local transport");
122 return NULL;
123 }
124 if (!string)
125 return NULL;
126 if (len > 0 && len < (sizeof(addr.sun_path) - 1)) {
127 addr.sun_family = AF_UNIX;
128 memset(addr.sun_path, 0, sizeof(addr.sun_path));
129 strncpy(addr.sun_path, string, len);
130 } else {
131 LLOG_WARNX("path too long for Unix domain transport");
132 return NULL;
133 }
134
135 if ((t = (netsnmp_transport *)
136 malloc(sizeof(netsnmp_transport))) == NULL)
137 return NULL;
138
139 memset(t, 0, sizeof(netsnmp_transport));
140
141 t->domain = netsnmp_UnixDomain;
142 t->domain_length =
143 sizeof(netsnmp_UnixDomain) / sizeof(netsnmp_UnixDomain[0]);
144
145 if ((t->sock = priv_snmp_socket(&addr)) < 0) {
146 netsnmp_transport_free(t);
147 return NULL;
148 }
149
150 t->flags = NETSNMP_TRANSPORT_FLAG_STREAM;
151
152 if ((t->remote = (u_char *)
153 malloc(strlen(addr.sun_path))) == NULL) {
154 agent_priv_unix_close(t);
155 netsnmp_transport_free(t);
156 return NULL;
157 }
158 memcpy(t->remote, addr.sun_path, strlen(addr.sun_path));
159 t->remote_length = strlen(addr.sun_path);
160
161 t->msgMaxSize = 0x7fffffff;
162 t->f_recv = agent_priv_unix_recv;
163 t->f_send = agent_priv_unix_send;
164 t->f_close = agent_priv_unix_close;
165 t->f_accept = agent_priv_unix_accept;
166 t->f_fmtaddr = agent_priv_unix_fmtaddr;
167
168 return t;
169 }
170
171 netsnmp_transport *
172 #if !HAVE_NETSNMP_TDOMAIN_F_CREATE_FROM_TSTRING_NEW
173 agent_priv_unix_create_tstring(const char *string, int local)
174 #else
175 agent_priv_unix_create_tstring(const char *string, int local, char *default_target)
176 #endif
177 {
178 #if HAVE_NETSNMP_TDOMAIN_F_CREATE_FROM_TSTRING_NEW
179 if ((!string || *string == '\0') && default_target &&
180 *default_target != '\0') {
181 string = default_target;
182 }
183 #endif
184 if (!string)
185 return NULL;
186 return agent_priv_unix_transport(string, strlen(string), local);
187 }
188
189 netsnmp_transport *
190 agent_priv_unix_create_ostring(const u_char * o, size_t o_len, int local)
191 {
192 return agent_priv_unix_transport((char *)o, o_len, local);
193 }
194
195 void
196 agent_priv_register_domain()
197 {
198 unixDomain.name = netsnmp_UnixDomain;
199 unixDomain.name_length = sizeof(netsnmp_UnixDomain) / sizeof(oid);
200 unixDomain.prefix = (const char**)calloc(2, sizeof(char *));
201 unixDomain.prefix[0] = "unix";
202 #if !HAVE_NETSNMP_TDOMAIN_F_CREATE_FROM_TSTRING_NEW
203 unixDomain.f_create_from_tstring = agent_priv_unix_create_tstring;
204 #else
205 unixDomain.f_create_from_tstring_new = agent_priv_unix_create_tstring;
206 #endif
207 unixDomain.f_create_from_ostring = agent_priv_unix_create_ostring;
208 netsnmp_tdomain_register(&unixDomain);
209 }
1313 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1414 */
1515
16 /* We also supports FDP which is very similar to CDPv1 */
1617 #include "lldpd.h"
1718
1819 #include <errno.h>
2425 {
2526 struct cdp_header ch;
2627 struct ethllc llc;
27 const u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR;
28 const u_int8_t llcorg[] = LLC_ORG_CISCO;
28 u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR;
29 u_int8_t llcorg[] = LLC_ORG_CISCO;
2930 struct iovec *iov = NULL;
3031 struct cdp_tlv_head device;
3132 struct cdp_tlv_head port;
4041 if ((iov = (struct iovec*)realloc(iov, (++c + 1) * \
4142 sizeof(struct iovec))) == NULL) \
4243 fatal(NULL);
44
45 /* Handle FDP */
46 if (version == 0) {
47 const u_int8_t fdpmcastaddr[] = FDP_MULTICAST_ADDR;
48 const u_int8_t fdpllcorg[] = LLC_ORG_FOUNDRY;
49 memcpy(mcastaddr, fdpmcastaddr, sizeof(mcastaddr));
50 memcpy(llcorg, fdpllcorg, sizeof(llcorg));
51 }
4352
4453 /* Ether + LLC */
4554 memset(&llc, 0, sizeof(llc));
5766
5867 /* CDP header */
5968 memset(&ch, 0, sizeof(ch));
60 ch.version = version;
69 if (version == 0)
70 ch.version = 1;
71 else
72 ch.version = version;
6173 ch.ttl = chassis->c_ttl;
6274 IOV_NEW;
6375 iov[c].iov_base = &ch;
103115 iov[c].iov_base = hardware->h_lport.p_descr;
104116 iov[c].iov_len = strlen(hardware->h_lport.p_descr);
105117
106 /* Capaibilities */
107 memset(&cap, 0, sizeof(cap));
108 cap.head.tlv_type = htons(CDP_TLV_CAPABILITIES);
109 cap.head.tlv_len = htons(sizeof(cap));
110 cap.cap = 0;
111 if (chassis->c_cap_enabled & LLDP_CAP_ROUTER)
112 cap.cap |= CDP_CAP_ROUTER;
113 if (chassis->c_cap_enabled & LLDP_CAP_BRIDGE)
114 cap.cap |= CDP_CAP_BRIDGE;
115 cap.cap = htonl(cap.cap);
116 IOV_NEW;
117 iov[c].iov_base = &cap;
118 iov[c].iov_len = sizeof(cap);
119
118 /* Capabilities */
119 if (version != 0) {
120 memset(&cap, 0, sizeof(cap));
121 cap.head.tlv_type = htons(CDP_TLV_CAPABILITIES);
122 cap.head.tlv_len = htons(sizeof(cap));
123 cap.cap = 0;
124 if (chassis->c_cap_enabled & LLDP_CAP_ROUTER)
125 cap.cap |= CDP_CAP_ROUTER;
126 if (chassis->c_cap_enabled & LLDP_CAP_BRIDGE)
127 cap.cap |= CDP_CAP_BRIDGE;
128 cap.cap = htonl(cap.cap);
129 IOV_NEW;
130 iov[c].iov_base = &cap;
131 iov[c].iov_len = sizeof(cap);
132 }
133
120134 /* Software version */
121135 memset(&soft, 0, sizeof(soft));
122136 soft.tlv_type = htons(CDP_TLV_SOFTWARE);
164178 return 0;
165179 }
166180
181 /* cdp_decode also decodes FDP */
167182 int
168183 cdp_decode(struct lldpd *cfg, char *frame, int s,
169184 struct lldpd_hardware *hardware,
181196 char *software = NULL, *platform = NULL;
182197 int software_len = 0, platform_len = 0;
183198 const unsigned char cdpaddr[] = CDP_MULTICAST_ADDR;
184 int i, f, len, rlen;
199 const unsigned char fdpaddr[] = CDP_MULTICAST_ADDR;
200 int i, f, len, rlen, fdp = 0;
185201
186202 if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
187203 LLOG_WARN("failed to allocate remote chassis");
201217
202218 llc = (struct ethllc *)frame;
203219 if (memcmp(&llc->ether.dhost, cdpaddr, sizeof(cdpaddr)) != 0) {
204 LLOG_INFO("frame not targeted at CDP multicast address received on %s",
205 hardware->h_ifname);
206 goto malformed;
220 if (memcmp(&llc->ether.dhost, fdpaddr, sizeof(fdpaddr)) != 0)
221 fdp = 1;
222 else {
223 LLOG_INFO("frame not targeted at CDP/FDP multicast address received on %s",
224 hardware->h_ifname);
225 goto malformed;
226 }
207227 }
208228 if (ntohs(llc->ether.size) > s - sizeof(struct ieee8023)) {
209229 LLOG_WARNX("incorrect 802.3 frame size reported on %s",
211231 goto malformed;
212232 }
213233 if (llc->protoid != htons(LLC_PID_CDP)) {
214 LLOG_DEBUG("incorrect LLC protocol ID received on %s",
215 hardware->h_ifname);
234 if ((llc->protoid != htons(LLC_PID_DRIP)) &&
235 (llc->protoid != htons(LLC_PID_PAGP)) &&
236 (llc->protoid != htons(LLC_PID_PVSTP)) &&
237 (llc->protoid != htons(LLC_PID_UDLD)) &&
238 (llc->protoid != htons(LLC_PID_VTP)) &&
239 (llc->protoid != htons(LLC_PID_DTP)) &&
240 (llc->protoid != htons(LLC_PID_STP)))
241 LLOG_DEBUG("incorrect LLC protocol ID received on %s",
242 hardware->h_ifname);
216243 goto malformed;
217244 }
218245 f = sizeof(struct ethllc);
219246 ch = (struct cdp_header *)(frame + f);
220247 if ((ch->version != 1) && (ch->version != 2)) {
221 LLOG_WARNX("incorrect CDP version (%d) for frame received on %s",
248 LLOG_WARNX("incorrect CDP/FDP version (%d) for frame received on %s",
222249 ch->version, hardware->h_ifname);
223250 goto malformed;
224251 }
228255 cksum = iov_checksum(&iov, 1, 1);
229256 /* An off-by-one error may happen. Just ignore it */
230257 if ((cksum != 0) && (cksum != 0xfffe)) {
231 LLOG_INFO("incorrect CDP checksum for frame received on %s (%d)",
258 LLOG_INFO("incorrect CDP/FDP checksum for frame received on %s (%d)",
232259 hardware->h_ifname, cksum);
233260 goto malformed;
234261 }
236263 f += sizeof(struct cdp_header);
237264 while (f < s) {
238265 if (f + sizeof(struct cdp_tlv_head) > s) {
239 LLOG_WARNX("CDP TLV header is too large for "
266 LLOG_WARNX("CDP/FDP TLV header is too large for "
240267 "frame received on %s",
241268 hardware->h_ifname);
242269 goto malformed;
244271 tlv = (struct cdp_tlv_head *)(frame + f);
245272 len = ntohs(tlv->tlv_len) - sizeof(struct cdp_tlv_head);
246273 if ((len < 0) || (f + sizeof(struct cdp_tlv_head) + len > s)) {
247 LLOG_WARNX("incorrect size in CDP TLV header for frame "
274 LLOG_WARNX("incorrect size in CDP/FDP TLV header for frame "
248275 "received on %s",
249276 hardware->h_ifname);
250277 goto malformed;
268295 break;
269296 case CDP_TLV_ADDRESSES:
270297 if (len < 4) {
271 LLOG_WARNX("incorrect size in CDP TLV header for frame "
298 LLOG_WARNX("incorrect size in CDP/FDP TLV header for frame "
272299 "received on %s",
273300 hardware->h_ifname);
274301 goto malformed;
324351 f += len;
325352 break;
326353 case CDP_TLV_CAPABILITIES:
354 if (fdp) {
355 /* Capabilities are ignored with FDP */
356 f += sizeof(struct cdp_tlv_head) + len;
357 chassis->c_cap_enabled = chassis->c_cap_available = LLDP_CAP_BRIDGE;
358 break;
359 }
327360 f += sizeof(struct cdp_tlv_head);
328361 if (len != 4) {
329362 LLOG_WARNX("incorrect size for capabilities TLV "
353386 f += len;
354387 break;
355388 default:
356 LLOG_DEBUG("unknown CDP TLV type (%d) received on %s",
389 LLOG_DEBUG("unknown CDP/FDP TLV type (%d) received on %s",
357390 ntohs(tlv->tlv_type), hardware->h_ifname);
358391 f += sizeof(struct cdp_tlv_head) + len;
392 hardware->h_rx_unrecognized_cnt++;
359393 }
360394 }
361395 if (!software && platform) {
393427 (port->p_descr == NULL) ||
394428 (chassis->c_ttl == 0) ||
395429 (chassis->c_cap_enabled == 0)) {
396 LLOG_WARNX("some mandatory tlv are missing for frame received on %s",
430 LLOG_WARNX("some mandatory CDP/FDP tlv are missing for frame received on %s",
397431 hardware->h_ifname);
398432 goto malformed;
399433 }
428462 }
429463
430464 int
465 fdp_send(struct lldpd *global, struct lldpd_chassis *chassis,
466 struct lldpd_hardware *hardware)
467 {
468 return cdp_send(global, chassis, hardware, 0);
469 }
470
471 int
431472 cdp_guess(char *frame, int len, int version)
432473 {
433474 const u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR;
1919 #define CDP_MULTICAST_ADDR { \
2020 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc \
2121 }
22 #define FDP_MULTICAST_ADDR { \
23 0x01, 0xe0, 0x52, 0xcc, 0xcc, 0xcc, \
24 }
2225 #define LLC_ORG_CISCO { 0x00, 0x00, 0x0c }
26 #define LLC_ORG_FOUNDRY { 0x00, 0xe0, 0x52 }
2327 #define LLC_PID_CDP 0x2000
28 /* Other protocols */
29 #define LLC_PID_DRIP 0x102
30 #define LLC_PID_PAGP 0x104
31 #define LLC_PID_PVSTP 0x10b
32 #define LLC_PID_UDLD 0x111
33 #define LLC_PID_VTP 0x2003
34 #define LLC_PID_DTP 0x2004
35 #define LLC_PID_STP 0x200a
2436
2537 struct cdp_header {
2638 u_int8_t version;
0 /*
1 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
2 *
3 * Permission to use, copy, modify, and distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16 #include "lldpd.h"
17
18 struct client_handle client_handles[] = {
19 { HMSG_NONE, client_handle_none },
20 { HMSG_GET_INTERFACES, client_handle_get_interfaces },
21 { HMSG_GET_CHASSIS, client_handle_get_port_related },
22 { HMSG_GET_PORT, client_handle_get_port_related },
23 { HMSG_GET_VLANS, client_handle_get_port_related },
24 { HMSG_SHUTDOWN, client_handle_shutdown },
25 { 0, NULL } };
26
27 void
28 client_handle_client(struct lldpd *cfg, struct lldpd_client *client,
29 char *buffer, int n)
30 {
31 struct hmsg *h; /* Reception */
32 struct hmsg *t; /* Sending */
33 struct client_handle *ch;
34
35 if (n < sizeof(struct hmsg_hdr)) {
36 LLOG_WARNX("too short message request received");
37 return;
38 }
39 h = (struct hmsg *)buffer;
40 n -= sizeof(struct hmsg_hdr);
41 if (n != h->hdr.len) {
42 LLOG_WARNX("incorrect message size received from %d",
43 h->hdr.pid);
44 return;
45 }
46
47 if ((t = (struct hmsg*)calloc(1, MAX_HMSGSIZE)) == NULL) {
48 LLOG_WARNX("unable to allocate memory to answer to %d",
49 h->hdr.pid);
50 return;
51 }
52 ctl_msg_init(t, h->hdr.type);
53 for (ch = client_handles; ch->handle != NULL; ch++) {
54 if (ch->type == h->hdr.type) {
55 ch->handle(cfg, h, t);
56 if (t->hdr.len == -1) {
57 t->hdr.len = 0;
58 t->hdr.type = HMSG_NONE;
59 }
60 if (ctl_msg_send(client->fd, t) == -1)
61 LLOG_WARN("unable to send answer to client %d",
62 h->hdr.pid);
63 free(t);
64 return;
65 }
66 }
67
68 LLOG_WARNX("unknown message request (%d) received from %d",
69 h->hdr.type, h->hdr.pid);
70 free(t);
71 return;
72 }
73
74 void
75 client_handle_shutdown(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
76 {
77 LLOG_INFO("received shutdown request from client %d",
78 r->hdr.pid);
79 exit(0);
80 }
81
82 void
83 client_handle_none(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
84 {
85 LLOG_INFO("received noop request from client %d",
86 r->hdr.pid);
87 s->hdr.len = -1;
88 }
89
90 void
91 client_handle_get_interfaces(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
92 {
93 struct lldpd_interface *iff, *iff_next;
94 struct lldpd_hardware *hardware;
95 void *p;
96
97 /* Build the list of interfaces */
98 TAILQ_HEAD(, lldpd_interface) ifs;
99 TAILQ_INIT(&ifs);
100 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
101 if ((iff = (struct lldpd_interface*)malloc(sizeof(
102 struct lldpd_interface))) == NULL)
103 fatal(NULL);
104 iff->name = hardware->h_ifname;
105 TAILQ_INSERT_TAIL(&ifs, iff, next);
106 }
107
108 p = &s->data;
109 if (ctl_msg_pack_list(STRUCT_LLDPD_INTERFACE, &ifs,
110 sizeof(struct lldpd_interface), s, &p) == -1) {
111 LLOG_WARNX("unable to pack list of interfaces");
112 s->hdr.len = -1;
113 }
114
115 /* Free the temporary list */
116 for (iff = TAILQ_FIRST(&ifs);
117 iff != NULL;
118 iff = iff_next) {
119 iff_next = TAILQ_NEXT(iff, next);
120 TAILQ_REMOVE(&ifs, iff, next);
121 free(iff);
122 }
123 }
124
125 void
126 client_handle_get_port_related(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
127 {
128 char *ifname;
129 struct lldpd_hardware *hardware;
130 void *p;
131
132 ifname = (char*)(&r->data);
133 if (ifname[r->hdr.len - 1] != 0) {
134 LLOG_WARNX("bad message format for get port related message");
135 s->hdr.len = -1;
136 return;
137 }
138 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
139 if (strncmp(ifname, hardware->h_ifname, IFNAMSIZ) == 0) {
140 if ((hardware->h_rport == NULL) ||
141 (hardware->h_rchassis == NULL)) {
142 s->hdr.len = 0;
143 s->hdr.type = HMSG_NONE;
144 return;
145 }
146 p = &s->data;
147 switch (r->hdr.type) {
148 case HMSG_GET_VLANS:
149 if (ctl_msg_pack_list(STRUCT_LLDPD_VLAN,
150 &hardware->h_rport->p_vlans,
151 sizeof(struct lldpd_vlan), s, &p) == -1) {
152 LLOG_WARNX("unable to send vlans information for "
153 "interface %s for %d", ifname, r->hdr.pid);
154 s->hdr.len = -1;
155 return;
156 }
157 break;
158 case HMSG_GET_PORT:
159 if (ctl_msg_pack_structure(STRUCT_LLDPD_PORT,
160 hardware->h_rport,
161 sizeof(struct lldpd_port), s, &p) == -1) {
162 LLOG_WARNX("unable to send port information for "
163 "interface %s for %d", ifname, r->hdr.pid);
164 s->hdr.len = -1;
165 return;
166 }
167 break;
168 case HMSG_GET_CHASSIS:
169 if (ctl_msg_pack_structure(STRUCT_LLDPD_CHASSIS,
170 hardware->h_rchassis,
171 sizeof(struct lldpd_chassis), s, &p) == -1) {
172 LLOG_WARNX("unable to send chassis information for "
173 "interface %s for %d", ifname, r->hdr.pid);
174 s->hdr.len = -1;
175 return;
176 }
177 break;
178 default:
179 LLOG_WARNX("don't know what to do");
180 s->hdr.len = -1;
181 return;
182 }
183 return;
184 }
185 }
186 LLOG_WARNX("requested interface %s by %d was not found",
187 ifname, r->hdr.pid);
188 s->hdr.len = -1;
189 return;
190 }
5454 #if !HAVE_DECL_PACKET_ORIGDEV
5555 #define PACKET_ORIGDEV 9
5656 #endif
57
58 #if !HAVE_DECL_ETHERTYPE_VLAN
59 #define ETHERTYPE_VLAN 0x8100
60 #endif
2222 #include <sys/un.h>
2323
2424 int
25 ctl_create(struct lldpd *cfg, char *name)
25 ctl_create(char *name)
2626 {
2727 int s;
2828 struct sockaddr_un su;
4040 rc = errno; close(s); errno = rc;
4141 return -1;
4242 }
43 TAILQ_INIT(&cfg->g_clients);
4443 return s;
4544 }
4645
138137 }
139138
140139 void
141 ctl_cleanup(int c, char *name)
142 {
143 close(c);
140 ctl_cleanup(char *name)
141 {
144142 if (unlink(name) == -1)
145143 LLOG_WARN("unable to unlink %s", name);
146144 }
109109 break;
110110 }
111111 }
112 if (info.port == -1) {
112 if (deviceslot[i] == NULL) {
113113 info.slot = htons(8);
114114 info.port = htons(if_nametoindex(hardware->h_ifname));
115115 }
407407 default:
408408 LLOG_DEBUG("unknown EDP TLV type (%d) received on %s",
409409 tlv->tlv_type, hardware->h_ifname);
410 hardware->h_rx_unrecognized_cnt++;
410411 }
411412 f += len;
412413 }
6363 if ((snprintf(path, SYSFS_PATH_MAX,
6464 SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_FDB, name)) >= SYSFS_PATH_MAX)
6565 LLOG_WARNX("path truncated");
66 if ((f = open(path, 0)) < 0) {
66 if ((f = priv_open(path)) < 0) {
6767 return old_iface_is_bridge(cfg, name);
6868 }
6969 close(f);
116116 SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_PORT_ATTR,
117117 name)) >= SYSFS_PATH_MAX)
118118 LLOG_WARNX("path truncated");
119 if ((f = open(path, 0)) < 0) {
119 if ((f = priv_open(path)) < 0) {
120120 return old_iface_is_bridged(cfg, name);
121121 }
122122 close(f);
522522 default:
523523 /* Unknown Dot3 TLV, ignore it */
524524 f += size;
525 hardware->h_rx_unrecognized_cnt++;
525526 }
526527 } else {
527 LLOG_WARNX("unknown org tlv received on %s",
528 hardware->h_ifname);
529 goto malformed;
528 LLOG_INFO("unknown org tlv received on %s",
529 hardware->h_ifname);
530 hardware->h_rx_unrecognized_cnt++;
531 f += size;
530532 }
531533 break;
532534 default:
2323 #include <fcntl.h>
2424 #include <fnmatch.h>
2525 #include <time.h>
26 #include <netdb.h>
26 #include <libgen.h>
2727 #include <sys/utsname.h>
2828 #include <sys/types.h>
2929 #include <sys/socket.h>
3131 #include <sys/time.h>
3232 #include <sys/ioctl.h>
3333 #include <arpa/inet.h>
34 #include <netpacket/packet.h>
3534 #include <ifaddrs.h>
3635 #include <net/if_arp.h>
3736 #include <linux/filter.h>
3837 #include <linux/if_vlan.h>
38 #include <linux/if_packet.h>
3939 #include <linux/sockios.h>
40 #include <linux/ethtool.h>
4140
4241 #ifdef USE_SNMP
4342 #include <net-snmp/net-snmp-config.h>
4948 void usage(void);
5049
5150 int lldpd_iface_init(struct lldpd *, struct lldpd_hardware *);
51 int lldpd_iface_init_vlan(struct lldpd *, struct lldpd_vif *);
52 void lldpd_iface_init_mtu(struct lldpd *, struct lldpd_hardware *);
5253 int lldpd_iface_close(struct lldpd *, struct lldpd_hardware *);
5354 void lldpd_iface_multicast(struct lldpd *, const char *, int);
5455
6364 { 0x6, 0, 0, 0x0000ffff }, \
6465 { 0x6, 0, 0, 0x00000000 },
6566 struct sock_filter lldpd_filter_lldp_f[] = { LLDPD_FILTER_LLDP_F };
67 /* "ether dst 01:e0:52:cc:cc:cc" */
68 #define LLDPD_FILTER_FDP_F \
69 { 0x20, 0, 0, 0x00000002 }, \
70 { 0x15, 0, 3, 0x52cccccc }, \
71 { 0x28, 0, 0, 0x00000000 }, \
72 { 0x15, 0, 1, 0x000001e0 }, \
73 { 0x6, 0, 0, 0x0000ffff }, \
74 { 0x6, 0, 0, 0x00000000 },
75 struct sock_filter lldpd_filter_fdp_f[] = { LLDPD_FILTER_FDP_F };
6676 /* "ether dst 01:00:0c:cc:cc:cc" */
6777 #define LLDPD_FILTER_CDP_F \
6878 { 0x20, 0, 0, 0x00000002 }, \
96106 { 0x20, 0, 0, 0x00000002 }, \
97107 { 0x15, 0, 2, 0xc200000e }, \
98108 { 0x28, 0, 0, 0x00000000 }, \
99 { 0x15, 8, 9, 0x00000180 }, \
109 { 0x15, 11, 12, 0x00000180 }, \
100110 { 0x20, 0, 0, 0x00000002 }, \
101111 { 0x15, 0, 2, 0x2b000000 }, \
102112 { 0x28, 0, 0, 0x00000000 }, \
103 { 0x15, 4, 5, 0x000000e0 }, \
113 { 0x15, 7, 8, 0x000000e0 }, \
104114 { 0x15, 1, 0, 0x0ccccccc }, \
105 { 0x15, 0, 3, 0x81000100 }, \
115 { 0x15, 0, 2, 0x81000100 }, \
106116 { 0x28, 0, 0, 0x00000000 }, \
107 { 0x15, 0, 1, 0x00000100 }, \
117 { 0x15, 3, 4, 0x00000100 }, \
118 { 0x15, 0, 3, 0x52cccccc }, \
119 { 0x28, 0, 0, 0x00000000 }, \
120 { 0x15, 0, 1, 0x000001e0 }, \
108121 { 0x6, 0, 0, 0x0000ffff }, \
109122 { 0x6, 0, 0, 0x00000000 },
110123 struct sock_filter lldpd_filter_any_f[] = { LLDPD_FILTER_ANY_F };
121134 SONMP_MULTICAST_ADDR, lldpd_filter_sonmp_f, sizeof(lldpd_filter_sonmp_f) },
122135 { LLDPD_MODE_EDP, 0, "EDP", 'e', edp_send, edp_decode, NULL,
123136 EDP_MULTICAST_ADDR, lldpd_filter_edp_f, sizeof(lldpd_filter_edp_f) },
137 { LLDPD_MODE_FDP, 0, "FDP", 'f', fdp_send, cdp_decode, NULL,
138 FDP_MULTICAST_ADDR, lldpd_filter_fdp_f, sizeof(lldpd_filter_fdp_f) },
124139 { 0, 0, "any", ' ', NULL, NULL, NULL,
125140 {0,0,0,0,0,0}, lldpd_filter_any_f, sizeof(lldpd_filter_any_f) }
126141 };
129144 struct lldpd_hardware *);
130145 struct lldpd_hardware *lldpd_port_add(struct lldpd *, struct ifaddrs *);
131146 void lldpd_loop(struct lldpd *);
132 void lldpd_hangup(int);
133147 void lldpd_shutdown(int);
134148 void lldpd_exit();
135149 void lldpd_send_all(struct lldpd *);
137151 int lldpd_guess_type(struct lldpd *, char *, int);
138152 void lldpd_decode(struct lldpd *, char *, int,
139153 struct lldpd_hardware *, int);
140 void lldpd_handle_client(struct lldpd *, struct lldpd_client *,
141 char *, int);
142
143 void lldpd_handle_none(struct lldpd *, struct hmsg *,
144 struct hmsg *);
145 void lldpd_handle_get_interfaces(struct lldpd *, struct hmsg *,
146 struct hmsg *);
147 void lldpd_handle_get_port_related(struct lldpd *, struct hmsg *,
148 struct hmsg *);
149 void lldpd_handle_shutdown(struct lldpd *, struct hmsg *,
150 struct hmsg *);
151
152 struct client_handle {
153 enum hmsg_type type;
154 void (*handle)(struct lldpd*, struct hmsg*, struct hmsg*);
155 };
156
157 struct client_handle client_handles[] = {
158 { HMSG_NONE, lldpd_handle_none },
159 { HMSG_GET_INTERFACES, lldpd_handle_get_interfaces },
160 { HMSG_GET_CHASSIS, lldpd_handle_get_port_related },
161 { HMSG_GET_PORT, lldpd_handle_get_port_related },
162 { HMSG_GET_VLANS, lldpd_handle_get_port_related },
163 { HMSG_SHUTDOWN, lldpd_handle_shutdown },
164 { 0, NULL } };
165154
166155 char **saved_argv;
167156
170159 {
171160 extern const char *__progname;
172161 #ifndef USE_SNMP
173 fprintf(stderr, "usage: %s [-d] [-c] [-s] [-e] [-p|-P] [-m ip]\n", __progname);
162 fprintf(stderr, "usage: %s [-dvcse] [-p|-P] [-m ip]\n", __progname);
174163 #else /* USE_SNMP */
175 fprintf(stderr, "usage: %s [-d] [-c] [-s] [-e] [-p|-P] [-m ip] [-x]\n", __progname);
164 fprintf(stderr, "usage: %s [-dvcsex] [-p|-P] [-m ip]\n", __progname);
176165 #endif /* USE_SNMP */
177166 exit(1);
178167 }
179168
180 int
181 lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
182 {
183 struct sockaddr_ll sa;
169 void
170 lldpd_iface_init_mtu(struct lldpd *global, struct lldpd_hardware *hardware)
171 {
184172 struct ifreq ifr;
185 int master; /* Bond device */
186 char if_bond[IFNAMSIZ];
187 int un = 1;
188 short int filter;
189173
190174 /* get MTU */
191175 memset(&ifr, 0, sizeof(ifr));
195179 hardware->h_mtu = 1500;
196180 } else
197181 hardware->h_mtu = ifr.ifr_mtu;
198
199 /* Open listening socket to receive/send frames */
200 if ((hardware->h_raw = socket(PF_PACKET, SOCK_RAW,
201 htons(ETH_P_ALL))) < 0)
202 return errno;
203 memset(&sa, 0, sizeof(sa));
204 sa.sll_family = AF_PACKET;
205 sa.sll_protocol = 0;
206 sa.sll_ifindex = if_nametoindex(hardware->h_ifname);
207 if (bind(hardware->h_raw, (struct sockaddr*)&sa, sizeof(sa)) < 0)
208 return errno;
182 }
183
184 int
185 lldpd_iface_init_vlan(struct lldpd *global, struct lldpd_vif *vif)
186 {
187 int status;
188 short int filter;
189
190 lldpd_iface_init_mtu(global, (struct lldpd_hardware*)vif);
191 status = priv_iface_init((struct lldpd_hardware*)vif, -1);
192 if (status != 0)
193 return status;
194
195 if (global->g_multi)
196 filter = LLDPD_MODE_ANY;
197 else
198 filter = LLDPD_MODE_LLDP;
199
200 if (lldpd_iface_switchto(global, filter,
201 (struct lldpd_hardware*)vif) == -1) {
202 LLOG_WARNX("unable to apply filter");
203 return ENETDOWN;
204 }
205
206 lldpd_iface_multicast(global, vif->vif_ifname, 0);
207
208 LLOG_DEBUG("vlan interface %s initialized (fd=%d)", vif->vif_ifname,
209 vif->vif_raw);
210 return 0;
211 }
212
213 int
214 lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware)
215 {
216 int master; /* Bond device */
217 char if_bond[IFNAMSIZ];
218 int status;
219 short int filter;
220
221 lldpd_iface_init_mtu(global, hardware);
222 status = priv_iface_init(hardware, -1);
223 if (status != 0)
224 return status;
209225
210226 if ((master = iface_is_enslaved(global, hardware->h_ifname)) != -1) {
211227 /* With bonding device, we need to listen on the bond ! */
217233 hardware->h_raw_real = hardware->h_raw;
218234 hardware->h_master = master;
219235 hardware->h_raw = -1;
220 if ((hardware->h_raw = socket(PF_PACKET, SOCK_RAW,
221 htons(ETH_P_ALL))) < 0)
222 return errno;
223 memset(&sa, 0, sizeof(sa));
224 sa.sll_family = AF_PACKET;
225 sa.sll_protocol = 0;
226 sa.sll_ifindex = master;
227 if (bind(hardware->h_raw, (struct sockaddr*)&sa,
228 sizeof(sa)) < 0)
229 return errno;
230 /* With bonding, we need to listen to bond device. We use
231 * setsockopt() PACKET_ORIGDEV to get physical device instead of
232 * bond device */
233 if (setsockopt(hardware->h_raw, SOL_PACKET,
234 PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
235 LLOG_WARN("unable to setsockopt for master bonding device of %s. "
236 "You will get inaccurate results",
237 hardware->h_ifname);
238 }
236 status = priv_iface_init(hardware, master);
237 if (status != 0) {
238 close(hardware->h_raw_real);
239 if (hardware->h_raw != -1)
240 close(hardware->h_raw);
241 return status;
242 }
239243 }
240244
241245 if (global->g_multi)
259263 void
260264 lldpd_iface_multicast(struct lldpd *global, const char *name, int remove)
261265 {
262 struct ifreq ifr;
263 int i;
266 int i, rc;
264267
265268 for (i=0; global->g_protocols[i].mode != 0; i++) {
266269 if (!global->g_protocols[i].enabled) continue;
267 memset(&ifr, 0, sizeof(ifr));
268 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
269 memcpy(ifr.ifr_hwaddr.sa_data,
270 global->g_protocols[i].mac, ETH_ALEN);
271 if (ioctl(global->g_sock, (remove)?SIOCDELMULTI:SIOCADDMULTI,
272 &ifr) < 0) {
273 if (errno == ENOENT)
274 return;
275 LLOG_INFO("unable to %s %s address to multicast filter for %s",
276 (remove)?"delete":"add",
277 global->g_protocols[i].name,
278 name);
270 if ((rc = priv_iface_multicast(name,
271 global->g_protocols[i].mac, !remove)) != 0) {
272 errno = rc;
273 if (errno != ENOENT)
274 LLOG_INFO("unable to %s %s address to multicast filter for %s",
275 (remove)?"delete":"add",
276 global->g_protocols[i].name,
277 name);
279278 }
280279 }
281280 }
391390 lldpd_cleanup(struct lldpd *cfg)
392391 {
393392 struct lldpd_hardware *hardware, *hardware_next;
393 struct lldpd_vif *vif, *vif_next;
394394
395395 for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL;
396396 hardware = hardware_next) {
411411 }
412412 }
413413 }
414 for (vif = TAILQ_FIRST(&cfg->g_vif); vif != NULL;
415 vif = vif_next) {
416 vif_next = TAILQ_NEXT(vif, vif_entries);
417 if (vif->vif_flags == 0) {
418 TAILQ_REMOVE(&cfg->g_vif, vif, vif_entries);
419 lldpd_iface_close(cfg, (struct lldpd_hardware*)vif);
420 free(vif);
421 }
422 }
423 }
424
425 struct lldpd_vif *
426 lldpd_port_add_vlan(struct lldpd *cfg, struct ifaddrs *ifa)
427 {
428 struct lldpd_vif *vif;
429 struct lldpd_hardware *hardware;
430 struct vlan_ioctl_args ifv;
431
432 TAILQ_FOREACH(vif, &cfg->g_vif, vif_entries) {
433 if (strcmp(vif->vif_ifname, ifa->ifa_name) == 0)
434 break;
435 }
436
437 if (vif == NULL) {
438 if ((vif = (struct lldpd_vif *)
439 calloc(1, sizeof(struct lldpd_vif))) == NULL)
440 return NULL;
441 vif->vif_raw = -1;
442 vif->vif_raw_real = -1;
443 }
444 strlcpy(vif->vif_ifname, ifa->ifa_name, sizeof(vif->vif_ifname));
445 vif->vif_flags = ifa->ifa_flags;
446
447 if (vif->vif_raw == -1) {
448
449 if (lldpd_iface_init_vlan(cfg, vif) != 0) {
450 free(vif);
451 return NULL;
452 }
453
454 /* Find the real interface */
455 vif->vif_real = NULL;
456 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
457 memset(&ifv, 0, sizeof(ifv));
458 ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
459 strlcpy(ifv.device1, ifa->ifa_name, sizeof(ifv.device1));
460 if ((ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) &&
461 (strncmp(hardware->h_ifname,
462 ifv.u.device2,
463 sizeof(ifv.u.device2)) == 0))
464 vif->vif_real = hardware;
465 }
466 if (vif->vif_real == NULL) {
467 LLOG_WARNX("unable to find real interface for %s",
468 ifa->ifa_name);
469 free(vif);
470 return NULL;
471 }
472
473 TAILQ_INSERT_TAIL(&cfg->g_vif, vif, vif_entries);
474 }
475
476 return vif;
414477 }
415478
416479 struct lldpd_hardware *
420483 struct lldpd_hardware *hardware;
421484 struct lldpd_port *port;
422485 struct lldpd_vlan *vlan;
423 struct ifreq ifr;
424486 struct vlan_ioctl_args ifv;
425487 struct ethtool_cmd ethc;
426488 u_int8_t *lladdr;
490552 if ((vlan = (struct lldpd_vlan *)
491553 calloc(1, sizeof(struct lldpd_vlan))) == NULL)
492554 continue;
493 if (asprintf(&vlan->v_name, "%s", oifa->ifa_name) == -1) {
555 if ((vlan->v_name = strdup(oifa->ifa_name)) == NULL) {
494556 free(vlan);
495557 continue;
496558 }
510572 freeifaddrs(oifap);
511573
512574 /* MAC/PHY */
513 memset(&ifr, 0, sizeof(ifr));
514 memset(&ethc, 0, sizeof(ethc));
515 strlcpy(ifr.ifr_name, hardware->h_ifname, sizeof(ifr.ifr_name));
516 ifr.ifr_data = (caddr_t)&ethc;
517 ethc.cmd = ETHTOOL_GSET;
518 if (ioctl(cfg->g_sock, SIOCETHTOOL, &ifr) == 0) {
575 if (priv_ethtool(hardware->h_ifname, &ethc) == 0) {
519576 int j;
520577 int advertised_ethtool_to_rfc3636[][2] = {
521578 {ADVERTISED_10baseT_Half, LLDP_DOT3_LINK_AUTONEG_10BASE_T},
568625 break;
569626 }
570627 if (ethc.port == PORT_AUI) port->p_mau_type = LLDP_DOT3_MAU_AUI;
571 }
628 } else
629 LLOG_DEBUG("unable to get eth info for %s", hardware->h_ifname);
572630
573631 if (!INTERFACE_OPENED(hardware)) {
574632
575633 if (lldpd_iface_init(cfg, hardware) != 0) {
634 LLOG_WARN("unable to initialize %s", hardware->h_ifname);
576635 lldpd_vlan_cleanup(&hardware->h_lport);
577 free(hardware->h_lladdr);
578636 free(hardware->h_proto_macs);
579637 free(hardware);
580638 return (NULL);
617675 struct lldpd_port *port;
618676 struct lldpd_hardware *ohardware, *firstnull = NULL, *older = NULL;
619677 int guess = LLDPD_MODE_LLDP;
678
679 /* Discard VLAN frames */
680 if ((s >= sizeof(struct ieee8023)) &&
681 (((struct ieee8023*)frame)->size == htons(ETHERTYPE_VLAN)))
682 return;
620683
621684 if ((hardware->h_rlastframe != NULL) &&
622685 (hardware->h_rlastframe->size == s) &&
850913 }
851914
852915 void
853 lldpd_handle_client(struct lldpd *cfg, struct lldpd_client *client,
854 char *buffer, int n)
855 {
856 struct hmsg *h; /* Reception */
857 struct hmsg *t; /* Sending */
858 struct client_handle *ch;
859
860 if (n < sizeof(struct hmsg_hdr)) {
861 LLOG_WARNX("too short message request received");
862 return;
863 }
864 h = (struct hmsg *)buffer;
865 n -= sizeof(struct hmsg_hdr);
866 if (n != h->hdr.len) {
867 LLOG_WARNX("incorrect message size received from %d",
868 h->hdr.pid);
869 return;
870 }
871
872 if ((t = (struct hmsg*)calloc(1, MAX_HMSGSIZE)) == NULL) {
873 LLOG_WARNX("unable to allocate memory to answer to %d",
874 h->hdr.pid);
875 return;
876 }
877 ctl_msg_init(t, h->hdr.type);
878 for (ch = client_handles; ch->handle != NULL; ch++) {
879 if (ch->type == h->hdr.type) {
880 ch->handle(cfg, h, t);
881 if (t->hdr.len == -1) {
882 t->hdr.len = 0;
883 t->hdr.type = HMSG_NONE;
884 }
885 if (ctl_msg_send(client->fd, t) == -1)
886 LLOG_WARN("unable to send answer to client %d",
887 h->hdr.pid);
888 free(t);
889 return;
890 }
891 }
892
893 LLOG_WARNX("unknown message request (%d) received from %d",
894 h->hdr.type, h->hdr.pid);
895 free(t);
896 return;
897 }
898
899 void
900 lldpd_handle_shutdown(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
901 {
902 LLOG_INFO("received shutdown request from client %d",
903 r->hdr.pid);
904 exit(0);
905 }
906
907 void
908 lldpd_handle_none(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
909 {
910 LLOG_INFO("received noop request from client %d",
911 r->hdr.pid);
912 s->hdr.len = -1;
913 }
914
915 void
916 lldpd_handle_get_interfaces(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
917 {
918 struct lldpd_interface *iff, *iff_next;
916 lldpd_recv_all(struct lldpd *cfg)
917 {
919918 struct lldpd_hardware *hardware;
920 void *p;
921
922 /* Build the list of interfaces */
923 TAILQ_HEAD(, lldpd_interface) ifs;
924 TAILQ_INIT(&ifs);
925 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
926 if ((iff = (struct lldpd_interface*)malloc(sizeof(
927 struct lldpd_interface))) == NULL)
928 fatal(NULL);
929 iff->name = hardware->h_ifname;
930 TAILQ_INSERT_TAIL(&ifs, iff, next);
931 }
932
933 p = &s->data;
934 if (ctl_msg_pack_list(STRUCT_LLDPD_INTERFACE, &ifs,
935 sizeof(struct lldpd_interface), s, &p) == -1) {
936 LLOG_WARNX("unable to pack list of interfaces");
937 s->hdr.len = -1;
938 }
939
940 /* Free the temporary list */
941 for (iff = TAILQ_FIRST(&ifs);
942 iff != NULL;
943 iff = iff_next) {
944 iff_next = TAILQ_NEXT(iff, next);
945 TAILQ_REMOVE(&ifs, iff, next);
946 free(iff);
947 }
948 }
949
950 void
951 lldpd_handle_get_port_related(struct lldpd *cfg, struct hmsg *r, struct hmsg *s)
952 {
953 char *ifname;
954 struct lldpd_hardware *hardware;
955 void *p;
956
957 ifname = (char*)(&r->data);
958 if (ifname[r->hdr.len - 1] != 0) {
959 LLOG_WARNX("bad message format for get port related message");
960 s->hdr.len = -1;
961 return;
962 }
963 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
964 if (strncmp(ifname, hardware->h_ifname, IFNAMSIZ) == 0) {
965 if ((hardware->h_rport == NULL) ||
966 (hardware->h_rchassis == NULL)) {
967 s->hdr.len = 0;
968 s->hdr.type = HMSG_NONE;
969 return;
970 }
971 p = &s->data;
972 switch (r->hdr.type) {
973 case HMSG_GET_VLANS:
974 if (ctl_msg_pack_list(STRUCT_LLDPD_VLAN,
975 &hardware->h_rport->p_vlans,
976 sizeof(struct lldpd_vlan), s, &p) == -1) {
977 LLOG_WARNX("unable to send vlans information for "
978 "interface %s for %d", ifname, r->hdr.pid);
979 s->hdr.len = -1;
980 return;
981 }
982 break;
983 case HMSG_GET_PORT:
984 if (ctl_msg_pack_structure(STRUCT_LLDPD_PORT,
985 hardware->h_rport,
986 sizeof(struct lldpd_port), s, &p) == -1) {
987 LLOG_WARNX("unable to send port information for "
988 "interface %s for %d", ifname, r->hdr.pid);
989 s->hdr.len = -1;
990 return;
991 }
992 break;
993 case HMSG_GET_CHASSIS:
994 if (ctl_msg_pack_structure(STRUCT_LLDPD_CHASSIS,
995 hardware->h_rchassis,
996 sizeof(struct lldpd_chassis), s, &p) == -1) {
997 LLOG_WARNX("unable to send chassis information for "
998 "interface %s for %d", ifname, r->hdr.pid);
999 s->hdr.len = -1;
1000 return;
1001 }
1002 break;
1003 default:
1004 LLOG_WARNX("don't know what to do");
1005 s->hdr.len = -1;
1006 return;
1007 }
1008 return;
1009 }
1010 }
1011 LLOG_WARNX("requested interface %s by %d was not found",
1012 ifname, r->hdr.pid);
1013 s->hdr.len = -1;
1014 return;
1015 }
1016
1017 void
1018 lldpd_recv_all(struct lldpd *cfg)
1019 {
1020 struct lldpd_hardware *hardware;
919 struct lldpd_vif *vif;
1021920 struct lldpd_client *client, *client_next;
1022921 fd_set rfds;
1023922 struct timeval tv;
1057956 nfds = hardware->h_raw_real;
1058957 }
1059958 }
959 TAILQ_FOREACH(vif, &cfg->g_vif, vif_entries) {
960 if ((vif->vif_flags & IFF_UP) == 0)
961 continue;
962 FD_SET(vif->vif_raw, &rfds);
963 if (nfds < vif->vif_raw)
964 nfds = vif->vif_raw;
965 }
1060966 TAILQ_FOREACH(client, &cfg->g_clients, next) {
1061967 FD_SET(client->fd, &rfds);
1062968 if (nfds < client->fd)
1090996 snmp_timeout();
1091997 }
1092998 #endif /* USE_SNMP */
999 TAILQ_FOREACH(vif, &cfg->g_vif, vif_entries) {
1000 if (!FD_ISSET(vif->vif_raw, &rfds))
1001 continue;
1002 if ((buffer = (char *)malloc(
1003 vif->vif_mtu)) == NULL) {
1004 LLOG_WARN("failed to alloc reception buffer");
1005 continue;
1006 }
1007 fromlen = sizeof(from);
1008 if ((n = recvfrom(vif->vif_raw,
1009 buffer,
1010 vif->vif_mtu, 0,
1011 (struct sockaddr *)&from,
1012 &fromlen)) == -1) {
1013 LLOG_WARN("error while receiving frame on vlan %s",
1014 vif->vif_ifname);
1015 vif->vif_real->h_rx_discarded_cnt++;
1016 free(buffer);
1017 continue;
1018 }
1019 if (from.sll_pkttype == PACKET_OUTGOING) {
1020 free(buffer);
1021 continue;
1022 }
1023 if (!((cfg->g_multi) &&
1024 (vif->vif_real->h_mode != LLDPD_MODE_ANY) &&
1025 (lldpd_guess_type(cfg, buffer, n) !=
1026 vif->vif_real->h_mode))) {
1027 vif->vif_real->h_rx_cnt++;
1028 lldpd_decode(cfg, buffer, n, vif->vif_real, 0);
1029 }
1030
1031 free(buffer);
1032 }
10931033 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
10941034 /* We could have received something on _real_
10951035 * interface. However, even in this case, this could be
11651105 continue;
11661106 }
11671107 if (n > 0)
1168 lldpd_handle_client(cfg, client, buffer, n);
1108 client_handle_client(cfg, client, buffer, n);
11691109 else
11701110 ctl_close(cfg, client->fd); /* Will use TAILQ_REMOVE ! */
11711111 free(buffer);
12081148 struct ifaddrs *ifap, *ifa;
12091149 struct sockaddr_ll *sdl;
12101150 struct lldpd_hardware *hardware;
1151 struct lldpd_vif *vif;
12111152 int f;
12121153 char status;
12131154 struct utsname *un;
1214 struct hostent *hp;
1155 char *hp;
12151156
12161157 /* Set system name and description */
12171158 if ((un = (struct utsname*)malloc(sizeof(struct utsname))) == NULL)
12181159 fatal(NULL);
12191160 if (uname(un) != 0)
12201161 fatal("failed to get system information");
1221 if ((hp = gethostbyname(un->nodename)) == NULL)
1162 if ((hp = priv_gethostbyname()) == NULL)
12221163 fatal("failed to get system name");
12231164 free(cfg->g_lchassis.c_name);
12241165 free(cfg->g_lchassis.c_descr);
1225 if (asprintf(&cfg->g_lchassis.c_name, "%s",
1226 hp->h_name) == -1)
1227 fatal("failed to set system name");
1166 if ((cfg->g_lchassis.c_name = strdup(hp)) == NULL)
1167 fatal(NULL);
12281168 if (asprintf(&cfg->g_lchassis.c_descr, "%s %s %s %s",
12291169 un->sysname, un->release, un->version, un->machine) == -1)
12301170 fatal("failed to set system description");
12321172
12331173 /* Check forwarding */
12341174 cfg->g_lchassis.c_cap_enabled = 0;
1235 if ((f = open("/proc/sys/net/ipv4/ip_forward", 0)) >= 0) {
1236 if ((read(f, &status, 1) == 1) && (status == '1'))
1175 if ((f = priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
1176 if ((read(f, &status, 1) == 1) && (status == '1')) {
12371177 cfg->g_lchassis.c_cap_enabled = LLDP_CAP_ROUTER;
1178 }
12381179 close(f);
12391180 }
12401181
12411182 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
12421183 hardware->h_flags = 0;
1184 TAILQ_FOREACH(vif, &cfg->g_vif, vif_entries)
1185 vif->vif_flags = 0;
12431186
12441187 if (getifaddrs(&ifap) != 0)
12451188 fatal("lldpd_loop: failed to get interface list");
12731216 }
12741217 }
12751218
1219 if (ifa->ifa_addr == NULL ||
1220 ifa->ifa_addr->sa_family != PF_PACKET)
1221 continue;
1222
1223 sdl = (struct sockaddr_ll *)ifa->ifa_addr;
1224 if (sdl->sll_hatype != ARPHRD_ETHER || !sdl->sll_halen)
1225 continue;
1226
12761227 if (iface_is_bridge(cfg, ifa->ifa_name)) {
12771228 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_BRIDGE;
12781229 continue;
12821233 (iface_is_bond(cfg, ifa->ifa_name)))
12831234 continue;
12841235
1285 if (ifa->ifa_addr == NULL ||
1286 ifa->ifa_addr->sa_family != PF_PACKET)
1287 continue;
1288
12891236 if (!(ifa->ifa_flags & IFF_MULTICAST))
12901237 continue;
12911238
1292 sdl = (struct sockaddr_ll *)ifa->ifa_addr;
1293 if (sdl->sll_hatype != ARPHRD_ETHER || !sdl->sll_halen)
1294 continue;
1295
12961239 if (iface_is_wireless(cfg, ifa->ifa_name))
12971240 cfg->g_lchassis.c_cap_enabled |= LLDP_CAP_WLAN;
1298
12991241
13001242 if (lldpd_port_add(cfg, ifa) == NULL)
13011243 LLOG_WARNX("failed to allocate port %s, skip it",
13021244 ifa->ifa_name);
13031245 }
13041246
1247 /* Handle VLAN */
1248 if (cfg->g_listen_vlans) {
1249 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
1250 if ((iface_is_vlan(cfg, ifa->ifa_name)) &&
1251 (lldpd_port_add_vlan(cfg, ifa) == NULL)) {
1252 LLOG_WARNX("unable to allocate vlan %s, skip it",
1253 ifa->ifa_name);
1254 }
1255 }
1256 }
1257
13051258 freeifaddrs(ifap);
13061259
13071260 lldpd_cleanup(cfg);
13111264 }
13121265
13131266 void
1314 lldpd_hangup(int sig)
1315 {
1316 /* Re-execute */
1317 LLOG_INFO("sighup received, reloading");
1318 lldpd_exit();
1319 execv(saved_argv[0], saved_argv);
1320 }
1321
1322 void
13231267 lldpd_shutdown(int sig)
13241268 {
13251269 LLOG_INFO("signal received, exiting");
13331277 lldpd_exit()
13341278 {
13351279 struct lldpd_hardware *hardware;
1336 ctl_cleanup(gcfg->g_ctl, LLDPD_CTL_SOCKET);
1280 struct lldpd_vif *vif;
1281 close(gcfg->g_ctl);
1282 priv_ctl_cleanup();
13371283 TAILQ_FOREACH(hardware, &gcfg->g_hardware, h_entries) {
13381284 if (INTERFACE_OPENED(hardware))
13391285 lldpd_iface_close(gcfg, hardware);
1286 }
1287 TAILQ_FOREACH(vif, &gcfg->g_vif, vif_entries) {
1288 if (vif->vif_raw != -1)
1289 lldpd_iface_close(gcfg, (struct lldpd_hardware*)vif);
13401290 }
13411291 #ifdef USE_SNMP
13421292 if (gcfg->g_snmp)
13501300 struct lldpd *cfg;
13511301 int ch, snmp = 0, debug = 0;
13521302 char *mgmtp = NULL;
1353 char *popt, opts[] = "dxm:p:@ ";
1354 int probe = 0, i, found;
1303 char *popt, opts[] = "vdxm:p:@ ";
1304 int probe = 0, i, found, vlan = 0;
13551305
13561306 saved_argv = argv;
13571307
13661316 *popt = '\0';
13671317 while ((ch = getopt(argc, argv, opts)) != -1) {
13681318 switch (ch) {
1319 case 'v':
1320 vlan = 1;
1321 break;
13691322 case 'd':
13701323 debug++;
13711324 break;
13941347
13951348 log_init(debug);
13961349
1350 if (!debug) {
1351 int pid;
1352 char *spid;
1353 if (daemon(0, 0) != 0)
1354 fatal("failed to detach daemon");
1355 if ((pid = open(LLDPD_PID_FILE,
1356 O_TRUNC | O_CREAT | O_WRONLY)) == -1)
1357 fatal("unable to open pid file " LLDPD_PID_FILE);
1358 if (asprintf(&spid, "%d\n", getpid()) == -1)
1359 fatal("unable to create pid file " LLDPD_PID_FILE);
1360 if (write(pid, spid, strlen(spid)) == -1)
1361 fatal("unable to write pid file " LLDPD_PID_FILE);
1362 free(spid);
1363 close(pid);
1364 }
1365
1366 priv_init(PRIVSEP_CHROOT);
1367
13971368 if (probe == 0) probe = LLDPD_TTL;
13981369
13991370 if ((cfg = (struct lldpd *)
14001371 calloc(1, sizeof(struct lldpd))) == NULL)
14011372 fatal(NULL);
14021373
1403 if (mgmtp != NULL)
1404 cfg->g_mgmt_pattern = mgmtp;
1374 cfg->g_mgmt_pattern = mgmtp;
1375 cfg->g_listen_vlans = vlan;
14051376
14061377 /* Get ioctl socket */
14071378 if ((cfg->g_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
14261397 cfg->g_multi--;
14271398
14281399 TAILQ_INIT(&cfg->g_hardware);
1400 TAILQ_INIT(&cfg->g_vif);
14291401
14301402 #ifdef USE_SNMP
14311403 if (snmp) {
14351407 #endif /* USE_SNMP */
14361408
14371409 /* Create socket */
1438 if ((cfg->g_ctl = ctl_create(cfg, LLDPD_CTL_SOCKET)) == -1)
1439 fatal("unable to create control socket " LLDPD_CTL_SOCKET);
1440
1441 if (!debug && daemon(0, 0) != 0) {
1442 ctl_cleanup(cfg->g_ctl, LLDPD_CTL_SOCKET);
1443 fatal("failed to detach daemon");
1444 }
1410 if ((cfg->g_ctl = priv_ctl_create(cfg)) == -1)
1411 fatalx("unable to create control socket " LLDPD_CTL_SOCKET);
1412 TAILQ_INIT(&cfg->g_clients);
1413
14451414 gcfg = cfg;
14461415 if (atexit(lldpd_exit) != 0) {
1447 ctl_cleanup(cfg->g_ctl, LLDPD_CTL_SOCKET);
1416 close(cfg->g_ctl);
1417 priv_ctl_cleanup();
14481418 fatal("unable to set exit function");
14491419 }
1450 if (!debug) {
1451 int pid;
1452 char *spid;
1453 if ((pid = open(LLDPD_PID_FILE,
1454 O_TRUNC | O_CREAT | O_WRONLY)) == -1)
1455 fatal("unable to open pid file " LLDPD_PID_FILE);
1456 if (asprintf(&spid, "%d\n", getpid()) == -1)
1457 fatal("unable to create pid file " LLDPD_PID_FILE);
1458 if (write(pid, spid, strlen(spid)) == -1)
1459 fatal("unable to write pid file " LLDPD_PID_FILE);
1460 free(spid);
1461 close(pid);
1462 }
14631420
14641421 /* Signal handling */
1465 signal(SIGHUP, lldpd_hangup);
1422 signal(SIGHUP, lldpd_shutdown);
14661423 signal(SIGINT, lldpd_shutdown);
14671424 signal(SIGTERM, lldpd_shutdown);
14681425
3232 #endif
3333 #include <net/ethernet.h>
3434 #include <netinet/in.h>
35 #include <linux/ethtool.h>
3536
3637 #include "compat.h"
3738 #include "lldp.h"
110111 #define LLDPD_MODE_CDPV2 3
111112 #define LLDPD_MODE_SONMP 4
112113 #define LLDPD_MODE_EDP 5
114 #define LLDPD_MODE_FDP 6
113115 int h_mode;
114116
115117 int h_flags;
121123 u_int64_t h_rx_cnt;
122124 u_int64_t h_rx_discarded_cnt;
123125 u_int64_t h_rx_ageout_cnt;
126 u_int64_t h_rx_unrecognized_cnt;
124127
125128 u_int8_t *h_proto_macs;
126129 time_t h_start_probe;
135138 struct lldpd_frame *h_rlastframe;
136139 struct lldpd_port *h_rport;
137140 struct lldpd_chassis *h_rchassis;
141 };
142
143 /* lldpd_vif can be casted to lldpd_hardware on some cases */
144 struct lldpd_vif {
145 TAILQ_ENTRY(lldpd_vif) vif_entries;
146 int vif_raw;
147 int vif_raw_real; /* Not used */
148 int vif_master; /* Not used */
149 int vif_mode; /* Not used */
150 int vif_flags;
151 int vif_mtu;
152 char vif_ifname[IFNAMSIZ];
153
154 /* No more compatibility with struct lldpd_hardware from here */
155 struct lldpd_hardware *vif_real;
138156 };
139157
140158 struct lldpd_interface {
173191 struct protocol *g_protocols;
174192 int g_multi; /* Set to 1 if multiple protocols */
175193 int g_probe_time;
194 int g_listen_vlans;
176195
177196 time_t g_lastsent;
178197 int g_lastrid;
189208 struct lldpd_chassis g_lchassis;
190209
191210 TAILQ_HEAD(, lldpd_hardware) g_hardware;
211 TAILQ_HEAD(, lldpd_vif) g_vif;
192212 };
193213
194214 enum hmsg_type {
228248 /* cdp.c */
229249 int cdpv1_send(PROTO_SEND_SIG);
230250 int cdpv2_send(PROTO_SEND_SIG);
251 int fdp_send(PROTO_SEND_SIG);
231252 int cdp_decode(PROTO_DECODE_SIG);
232253 int cdpv1_guess(PROTO_GUESS_SIG);
233254 int cdpv2_guess(PROTO_GUESS_SIG);
241262 int edp_decode(PROTO_DECODE_SIG);
242263
243264 /* ctl.c */
244 int ctl_create(struct lldpd *, char *);
265 int ctl_create(char *);
245266 int ctl_connect(char *);
246 void ctl_cleanup(int, char *);
267 void ctl_cleanup(char *);
247268 int ctl_accept(struct lldpd *, int);
248269 int ctl_close(struct lldpd *, int);
249270 void ctl_msg_init(struct hmsg *, enum hmsg_type);
281302 void agent_shutdown();
282303 void agent_init(struct lldpd *, int);
283304
305 /* agent_priv.c */
306 void agent_priv_register_domain();
307
284308 /* strlcpy.c */
285309 size_t strlcpy(char *, const char *, size_t);
286310
288312 void iov_dump(struct lldpd_frame **, struct iovec *, int);
289313 u_int16_t iov_checksum(struct iovec *, int, int);
290314
315 /* client.c */
316 struct client_handle {
317 enum hmsg_type type;
318 void (*handle)(struct lldpd*, struct hmsg*, struct hmsg*);
319 };
320
321 void client_handle_client(struct lldpd *, struct lldpd_client *,
322 char *, int);
323 void client_handle_none(struct lldpd *, struct hmsg *,
324 struct hmsg *);
325 void client_handle_get_interfaces(struct lldpd *, struct hmsg *,
326 struct hmsg *);
327 void client_handle_get_port_related(struct lldpd *, struct hmsg *,
328 struct hmsg *);
329 void client_handle_shutdown(struct lldpd *, struct hmsg *,
330 struct hmsg *);
331
332 /* priv.c */
333 void priv_init(char*);
334 int priv_ctl_create();
335 void priv_ctl_cleanup();
336 char *priv_gethostbyname();
337 int priv_open(char*);
338 int priv_ethtool(char*, struct ethtool_cmd*);
339 int priv_iface_init(struct lldpd_hardware *, int);
340 int priv_iface_multicast(char *, u_int8_t *, int);
341 int priv_snmp_socket(struct sockaddr_un *);
342
343 /* privsep_fdpass.c */
344 int receive_fd(int);
345 void send_fd(int, int);
346
291347 #endif /* _LLDPD_H */
0 /*
1 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
2 *
3 * Permission to use, copy, modify, and distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16 /* This file contains code for privilege separation. When an error arises in
17 * monitor (which is running as root), it just stops instead of trying to
18 * recover. This module also contains proxies to privileged operations. In this
19 * case, error can be non fatal. */
20
21 #include "lldpd.h"
22
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <regex.h>
33 #include <fcntl.h>
34 #include <pwd.h>
35 #include <grp.h>
36 #include <sys/utsname.h>
37 #include <sys/ioctl.h>
38 #include <netdb.h>
39 #include <linux/sockios.h>
40 #include <linux/if_packet.h>
41
42 enum {
43 PRIV_PING,
44 PRIV_CREATE_CTL_SOCKET,
45 PRIV_DELETE_CTL_SOCKET,
46 PRIV_GET_HOSTNAME,
47 PRIV_OPEN,
48 PRIV_ETHTOOL,
49 PRIV_IFACE_INIT,
50 PRIV_IFACE_MULTICAST,
51 PRIV_SNMP_SOCKET,
52 };
53
54 static int may_read(int, void *, size_t);
55 static void must_read(int, void *, size_t);
56 static void must_write(int, void *, size_t);
57
58 int remote; /* Other side */
59 int monitored = -1; /* Child */
60 int sock = -1;
61
62 /* UID/GID of unprivileged user */
63 gid_t gid = 0;
64 uid_t uid = 0;
65
66 /* Proxies */
67
68 void
69 priv_ping()
70 {
71 int cmd, rc;
72 cmd = PRIV_PING;
73 must_write(remote, &cmd, sizeof(int));
74 must_read(remote, &rc, sizeof(int));
75 LLOG_DEBUG("monitor ready");
76 }
77
78 /* Proxy for ctl_create, no argument since this is the monitor that decides the
79 * location of the socket */
80 int
81 priv_ctl_create()
82 {
83 int cmd, rc;
84 cmd = PRIV_CREATE_CTL_SOCKET;
85 must_write(remote, &cmd, sizeof(int));
86 must_read(remote, &rc, sizeof(int));
87 if (rc == -1)
88 return -1;
89 return receive_fd(remote);
90 }
91
92 /* Proxy for ctl_cleanup */
93 void
94 priv_ctl_cleanup()
95 {
96 int cmd, rc;
97 cmd = PRIV_DELETE_CTL_SOCKET;
98 must_write(remote, &cmd, sizeof(int));
99 must_read(remote, &rc, sizeof(int));
100 }
101
102 /* Proxy for gethostbyname */
103 char *
104 priv_gethostbyname()
105 {
106 int cmd, rc;
107 static char *buf = NULL;
108 cmd = PRIV_GET_HOSTNAME;
109 must_write(remote, &cmd, sizeof(int));
110 must_read(remote, &rc, sizeof(int));
111 if ((buf = (char*)realloc(buf, rc+1)) == NULL)
112 fatal(NULL);
113 must_read(remote, buf, rc+1);
114 return buf;
115 }
116
117 /* Proxy for open */
118 int
119 priv_open(char *file)
120 {
121 int cmd, len, rc;
122 cmd = PRIV_OPEN;
123 must_write(remote, &cmd, sizeof(int));
124 len = strlen(file);
125 must_write(remote, &len, sizeof(int));
126 must_write(remote, file, len + 1);
127 must_read(remote, &rc, sizeof(int));
128 if (rc == -1)
129 return rc;
130 return receive_fd(remote);
131 }
132
133 /* Proxy for ethtool ioctl */
134 int
135 priv_ethtool(char *ifname, struct ethtool_cmd *ethc)
136 {
137 int cmd, rc, len;
138 cmd = PRIV_ETHTOOL;
139 must_write(remote, &cmd, sizeof(int));
140 len = strlen(ifname);
141 must_write(remote, &len, sizeof(int));
142 must_write(remote, ifname, len + 1);
143 must_read(remote, &rc, sizeof(int));
144 if (rc != 0)
145 return rc;
146 must_read(remote, ethc, sizeof(struct ethtool_cmd));
147 return rc;
148 }
149
150 int
151 priv_iface_init(struct lldpd_hardware *hardware, int master)
152 {
153 int cmd, rc;
154 cmd = PRIV_IFACE_INIT;
155 must_write(remote, &cmd, sizeof(int));
156 must_write(remote, &master, sizeof(int));
157 must_write(remote, hardware->h_ifname, IFNAMSIZ);
158 must_read(remote, &rc, sizeof(int));
159 if (rc != 0)
160 return rc; /* It's errno */
161 hardware->h_raw = receive_fd(remote);
162 return 0;
163 }
164
165 int
166 priv_iface_multicast(char *name, u_int8_t *mac, int add)
167 {
168 int cmd, rc;
169 cmd = PRIV_IFACE_MULTICAST;
170 must_write(remote, &cmd, sizeof(int));
171 must_write(remote, name, IFNAMSIZ);
172 must_write(remote, mac, ETH_ALEN);
173 must_write(remote, &add, sizeof(int));
174 must_read(remote, &rc, sizeof(int));
175 return rc;
176 }
177
178 int
179 priv_snmp_socket(struct sockaddr_un *addr)
180 {
181 int cmd, rc;
182 cmd = PRIV_SNMP_SOCKET;
183 must_write(remote, &cmd, sizeof(int));
184 must_write(remote, addr, sizeof(struct sockaddr_un));
185 must_read(remote, &rc, sizeof(int));
186 if (rc < 0)
187 return rc;
188 return receive_fd(remote);
189 }
190
191 void
192 asroot_ping()
193 {
194 int rc = 1;
195 must_write(remote, &rc, sizeof(int));
196 }
197
198 void
199 asroot_ctl_create()
200 {
201 int rc;
202 if ((rc = ctl_create(LLDPD_CTL_SOCKET)) == -1) {
203 LLOG_WARN("[priv]: unable to create control socket");
204 must_write(remote, &rc, sizeof(int));
205 return;
206 }
207 if (chown(LLDPD_CTL_SOCKET, uid, gid) == -1)
208 LLOG_WARN("[priv]: unable to chown control socket");
209 if (chmod(LLDPD_CTL_SOCKET,
210 S_IRUSR | S_IWUSR | S_IXUSR |
211 S_IRGRP | S_IWGRP | S_IXGRP) == -1)
212 LLOG_WARN("[priv]: unable to chmod control socket");
213 must_write(remote, &rc, sizeof(int));
214 send_fd(remote, rc);
215 close(rc);
216 }
217
218 void
219 asroot_ctl_cleanup()
220 {
221 int rc = 0;
222 ctl_cleanup(LLDPD_CTL_SOCKET);
223
224 /* Ack */
225 must_write(remote, &rc, sizeof(int));
226 }
227
228 void
229 asroot_gethostbyname()
230 {
231 struct utsname un;
232 struct hostent *hp;
233 int len;
234 if (uname(&un) != 0)
235 fatal("[priv]: failed to get system information");
236 if ((hp = gethostbyname(un.nodename)) == NULL)
237 fatal("[priv]: failed to get system name");
238 len = strlen(hp->h_name);
239 must_write(remote, &len, sizeof(int));
240 must_write(remote, hp->h_name, strlen(hp->h_name) + 1);
241 }
242
243 void
244 asroot_open()
245 {
246 const char* authorized[] = {
247 "/proc/sys/net/ipv4/ip_forward",
248 "/sys/class/net/[^.][^/]*/brforward",
249 "/sys/class/net/[^.][^/]*/brport",
250 NULL
251 };
252 char **f;
253 char *file;
254 int fd, len, rc;
255 regex_t preg;
256
257 must_read(remote, &len, sizeof(len));
258 if ((file = (char *)malloc(len + 1)) == NULL)
259 fatal(NULL);
260 must_read(remote, file, len);
261 file[len] = '\0';
262
263 for (f=authorized; *f != NULL; f++) {
264 if (regcomp(&preg, *f, REG_NOSUB) != 0)
265 /* Should not happen */
266 fatal("unable to compile a regex");
267 if (regexec(&preg, file, 0, NULL, 0) == 0) {
268 regfree(&preg);
269 break;
270 }
271 regfree(&preg);
272 }
273 if (*f == NULL) {
274 LLOG_WARNX("[priv]: not authorized to open %s", file);
275 rc = -1;
276 must_write(remote, &rc, sizeof(int));
277 free(file);
278 return;
279 }
280 if ((fd = open(file, 0)) == -1) {
281 rc = -1;
282 must_write(remote, &rc, sizeof(int));
283 free(file);
284 return;
285 }
286 free(file);
287 must_write(remote, &fd, sizeof(int));
288 send_fd(remote, fd);
289 close(fd);
290 }
291
292 void
293 asroot_ethtool()
294 {
295 struct ifreq ifr;
296 struct ethtool_cmd ethc;
297 int len, rc;
298 char *ifname;
299
300 memset(&ifr, 0, sizeof(ifr));
301 memset(&ethc, 0, sizeof(ethc));
302 must_read(remote, &len, sizeof(int));
303 if ((ifname = (char*)malloc(len + 1)) == NULL)
304 fatal(NULL);
305 must_read(remote, ifname, len);
306 ifname[len] = '\0';
307 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
308 free(ifname);
309 ifr.ifr_data = (caddr_t)&ethc;
310 ethc.cmd = ETHTOOL_GSET;
311 if ((rc = ioctl(sock, SIOCETHTOOL, &ifr)) != 0) {
312 LLOG_DEBUG("[priv]: unable to ioctl ETHTOOL for %s",
313 ifr.ifr_name);
314 must_write(remote, &rc, sizeof(int));
315 close(sock);
316 return;
317 }
318 must_write(remote, &rc, sizeof(int));
319 must_write(remote, &ethc, sizeof(struct ethtool_cmd));
320 }
321
322 void
323 asroot_iface_init()
324 {
325 struct sockaddr_ll sa;
326 int un = 1;
327 int s, master;
328 char ifname[IFNAMSIZ];
329
330 must_read(remote, &master, sizeof(int));
331 must_read(remote, ifname, IFNAMSIZ);
332 ifname[IFNAMSIZ-1] = '\0';
333
334 /* Open listening socket to receive/send frames */
335 if ((s = socket(PF_PACKET, SOCK_RAW,
336 htons(ETH_P_ALL))) < 0) {
337 must_write(remote, &errno, sizeof(errno));
338 return;
339 }
340 memset(&sa, 0, sizeof(sa));
341 sa.sll_family = AF_PACKET;
342 sa.sll_protocol = 0;
343 if (master == -1)
344 sa.sll_ifindex = if_nametoindex(ifname);
345 else
346 sa.sll_ifindex = master;
347 if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
348 must_write(remote, &errno, sizeof(errno));
349 close(s);
350 return;
351 }
352
353 if (master != -1) {
354 /* With bonding, we need to listen to bond device. We use
355 * setsockopt() PACKET_ORIGDEV to get physical device instead of
356 * bond device */
357 if (setsockopt(s, SOL_PACKET,
358 PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
359 LLOG_WARN("[priv]: unable to setsockopt for master bonding device of %s. "
360 "You will get inaccurate results",
361 ifname);
362 }
363 }
364 errno = 0;
365 must_write(remote, &errno, sizeof(errno));
366 send_fd(remote, s);
367 close(s);
368 }
369
370 void
371 asroot_iface_multicast()
372 {
373 int add, rc = 0;
374 struct ifreq ifr;
375 memset(&ifr, 0, sizeof(ifr));
376 must_read(remote, ifr.ifr_name, IFNAMSIZ);
377 ifr.ifr_name[IFNAMSIZ-1] = '\0';
378 must_read(remote, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
379 must_read(remote, &add, sizeof(int));
380
381 if (ioctl(sock, (add)?SIOCADDMULTI:SIOCDELMULTI,
382 &ifr) < 0) {
383 must_write(remote, &errno, sizeof(errno));
384 return;
385 }
386
387 must_write(remote, &rc, sizeof(rc));
388 }
389
390 static void
391 asroot_snmp_socket()
392 {
393 int sock, rc;
394 static struct sockaddr_un *addr = NULL;
395 struct sockaddr_un bogus;
396
397 if (!addr) {
398 addr = (struct sockaddr_un *)malloc(sizeof(struct sockaddr_un));
399 must_read(remote, addr, sizeof(struct sockaddr_un));
400 } else
401 /* We have already been asked to connect to a socket. We will
402 * connect to the same socket. */
403 must_read(remote, &bogus, sizeof(struct sockaddr_un));
404 if (addr->sun_family != AF_UNIX)
405 fatal("someone is trying to trick me");
406 addr->sun_path[sizeof(addr->sun_path)-1] = '\0';
407
408 if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
409 LLOG_WARN("[priv]: cannot open socket");
410 must_write(remote, &sock, sizeof(int));
411 return;
412 }
413 if ((rc = connect(sock, (struct sockaddr *) addr,
414 sizeof(struct sockaddr_un))) != 0) {
415 LLOG_INFO("[priv]: cannot connect to %s", addr->sun_path);
416 close(sock);
417 rc = -1;
418 must_write(remote, &rc, sizeof(int));
419 return;
420 }
421 must_write(remote, &rc, sizeof(int));
422 send_fd(remote, sock);
423 close(sock);
424 }
425
426 struct dispatch_actions {
427 int msg;
428 void(*function)(void);
429 };
430
431 struct dispatch_actions actions[] = {
432 {PRIV_PING, asroot_ping},
433 {PRIV_CREATE_CTL_SOCKET, asroot_ctl_create},
434 {PRIV_DELETE_CTL_SOCKET, asroot_ctl_cleanup},
435 {PRIV_GET_HOSTNAME, asroot_gethostbyname},
436 {PRIV_OPEN, asroot_open},
437 {PRIV_ETHTOOL, asroot_ethtool},
438 {PRIV_IFACE_INIT, asroot_iface_init},
439 {PRIV_IFACE_MULTICAST, asroot_iface_multicast},
440 {PRIV_SNMP_SOCKET, asroot_snmp_socket},
441 {-1, NULL}
442 };
443
444 /* Main loop, run as root */
445 void
446 priv_loop()
447 {
448 int cmd;
449 struct dispatch_actions *a;
450
451 while (!may_read(remote, &cmd, sizeof(int))) {
452 for (a = actions; a->function != NULL; a++) {
453 if (cmd == a->msg) {
454 a->function();
455 break;
456 }
457 }
458 if (a->function == NULL)
459 fatal("[priv]: bogus message received");
460 }
461 /* Should never be there */
462 }
463
464 void
465 priv_exit()
466 {
467 int status;
468 int rc;
469 if ((rc = waitpid(monitored, &status, WNOHANG)) == 0) {
470 LLOG_DEBUG("[priv]: killing child");
471 kill(monitored, SIGTERM);
472 }
473 if ((rc = waitpid(monitored, &status, WNOHANG)) == -1)
474 _exit(0);
475 LLOG_DEBUG("[priv]: waiting for child %d to terminate", monitored);
476 }
477
478 /* If priv parent gets a TERM or HUP, pass it through to child instead */
479 static void
480 sig_pass_to_chld(int sig)
481 {
482 int oerrno = errno;
483 if (monitored != -1)
484 kill(monitored, sig);
485 errno = oerrno;
486 }
487
488 /* if parent gets a SIGCHLD, it will exit */
489 static void
490 sig_chld(int sig)
491 {
492 LLOG_DEBUG("[priv]: received signal %d, exiting", sig);
493 priv_exit();
494 }
495
496 /* Initialization */
497 void
498 priv_init(char *chrootdir)
499 {
500 int pair[2];
501 struct passwd *user;
502 struct group *group;
503 gid_t gidset[1];
504
505 /* Create socket pair */
506 if (socketpair(AF_LOCAL, SOCK_DGRAM, PF_UNSPEC, pair) < 0)
507 fatal("[priv]: unable to create socket pair for privilege separation");
508
509 /* Get users */
510 if ((user = getpwnam(PRIVSEP_USER)) == NULL)
511 fatal("[priv]: no " PRIVSEP_USER " user for privilege separation");
512 uid = user->pw_uid;
513 if ((group = getgrnam(PRIVSEP_GROUP)) == NULL)
514 fatal("[priv]: no " PRIVSEP_GROUP " group for privilege separation");
515 gid = group->gr_gid;
516
517 /* Spawn off monitor */
518 if ((monitored = fork()) < 0)
519 fatal("[priv]: unable to fork monitor");
520 switch (monitored) {
521 case 0:
522 /* We are in the children, drop privileges */
523 if (chroot(chrootdir) == -1)
524 fatal("[priv]: unable to chroot");
525 if (chdir("/") != 0)
526 fatal("[priv]: unable to chdir");
527 gidset[0] = gid;
528 if (setresgid(gid, gid, gid) == -1)
529 fatal("[priv]: setresgid() failed");
530 if (setgroups(1, gidset) == -1)
531 fatal("[priv]: setgroups() failed");
532 if (setresuid(uid, uid, uid) == -1)
533 fatal("[priv]: setresuid() failed");
534 remote = pair[0];
535 close(pair[1]);
536 priv_ping();
537 break;
538 default:
539 /* We are in the monitor */
540 remote = pair[1];
541 close(pair[0]);
542 if (atexit(priv_exit) != 0)
543 fatal("[priv]: unable to set exit function");
544 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
545 fatal("[priv]: unable to get a socket");
546 }
547
548 signal(SIGALRM, sig_pass_to_chld);
549 signal(SIGTERM, sig_pass_to_chld);
550 signal(SIGHUP, sig_pass_to_chld);
551 signal(SIGINT, sig_pass_to_chld);
552 signal(SIGQUIT, sig_pass_to_chld);
553 signal(SIGCHLD, sig_chld);
554 priv_loop();
555 exit(0);
556 }
557 }
558
559 /* Stolen from sbin/pflogd/privsep.c from OpenBSD */
560 /*
561 * Copyright (c) 2003 Can Erkin Acar
562 * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
563 *
564 * Permission to use, copy, modify, and distribute this software for any
565 * purpose with or without fee is hereby granted, provided that the above
566 * copyright notice and this permission notice appear in all copies.
567 *
568 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
569 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
570 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
571 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
572 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
573 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
574 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
575 */
576
577 /* Read all data or return 1 for error. */
578 static int
579 may_read(int fd, void *buf, size_t n)
580 {
581 char *s = buf;
582 ssize_t res, pos = 0;
583
584 while (n > pos) {
585 res = read(fd, s + pos, n - pos);
586 switch (res) {
587 case -1:
588 if (errno == EINTR || errno == EAGAIN)
589 continue;
590 case 0:
591 return (1);
592 default:
593 pos += res;
594 }
595 }
596 return (0);
597 }
598
599 /* Read data with the assertion that it all must come through, or
600 * else abort the process. Based on atomicio() from openssh. */
601 static void
602 must_read(int fd, void *buf, size_t n)
603 {
604 char *s = buf;
605 ssize_t res, pos = 0;
606
607 while (n > pos) {
608 res = read(fd, s + pos, n - pos);
609 switch (res) {
610 case -1:
611 if (errno == EINTR || errno == EAGAIN)
612 continue;
613 case 0:
614 _exit(0);
615 default:
616 pos += res;
617 }
618 }
619 }
620
621 /* Write data with the assertion that it all has to be written, or
622 * else abort the process. Based on atomicio() from openssh. */
623 static void
624 must_write(int fd, void *buf, size_t n)
625 {
626 char *s = buf;
627 ssize_t res, pos = 0;
628
629 while (n > pos) {
630 res = write(fd, s + pos, n - pos);
631 switch (res) {
632 case -1:
633 if (errno == EINTR || errno == EAGAIN)
634 continue;
635 case 0:
636 _exit(0);
637 default:
638 pos += res;
639 }
640 }
641 }
0 /*
1 * Copyright 2001 Niels Provos <provos@citi.umich.edu>
2 * All rights reserved.
3 *
4 * Copyright (c) 2002 Matthieu Herrb
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "lldpd.h"
33
34 #include <sys/param.h>
35 #include <sys/uio.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/stat.h>
39 #include <err.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <signal.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 void
49 send_fd(int sock, int fd)
50 {
51 struct msghdr msg;
52 union {
53 struct cmsghdr hdr;
54 char buf[CMSG_SPACE(sizeof(int))];
55 } cmsgbuf;
56 struct cmsghdr *cmsg;
57 struct iovec vec;
58 int result = 0;
59 ssize_t n;
60
61 memset(&msg, 0, sizeof(msg));
62
63 if (fd >= 0) {
64 msg.msg_control = (caddr_t)&cmsgbuf.buf;
65 msg.msg_controllen = sizeof(cmsgbuf.buf);
66 cmsg = CMSG_FIRSTHDR(&msg);
67 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
68 cmsg->cmsg_level = SOL_SOCKET;
69 cmsg->cmsg_type = SCM_RIGHTS;
70 *(int *)CMSG_DATA(cmsg) = fd;
71 } else {
72 result = errno;
73 }
74
75 vec.iov_base = &result;
76 vec.iov_len = sizeof(int);
77 msg.msg_iov = &vec;
78 msg.msg_iovlen = 1;
79
80 if ((n = sendmsg(sock, &msg, 0)) == -1)
81 LLOG_WARN("sendmsg(%d)", sock);
82 if (n != sizeof(int))
83 LLOG_WARNX("sendmsg: expected sent 1 got %ld",
84 (long)n);
85 }
86
87 int
88 receive_fd(int sock)
89 {
90 struct msghdr msg;
91 union {
92 struct cmsghdr hdr;
93 char buf[CMSG_SPACE(sizeof(int))];
94 } cmsgbuf;
95 struct cmsghdr *cmsg;
96 struct iovec vec;
97 ssize_t n;
98 int result;
99 int fd;
100
101 memset(&msg, 0, sizeof(msg));
102 vec.iov_base = &result;
103 vec.iov_len = sizeof(int);
104 msg.msg_iov = &vec;
105 msg.msg_iovlen = 1;
106 msg.msg_control = &cmsgbuf.buf;
107 msg.msg_controllen = sizeof(cmsgbuf.buf);
108
109 if ((n = recvmsg(sock, &msg, 0)) == -1)
110 LLOG_WARN("recvmsg");
111 if (n != sizeof(int))
112 LLOG_WARNX("recvmsg: expected received 1 got %ld",
113 (long)n);
114 if (result == 0) {
115 cmsg = CMSG_FIRSTHDR(&msg);
116 if (cmsg == NULL) {
117 LLOG_WARNX("no message header");
118 return -1;
119 }
120 if (cmsg->cmsg_type != SCM_RIGHTS)
121 LLOG_WARNX("expected type %d got %d",
122 SCM_RIGHTS, cmsg->cmsg_type);
123 fd = (*(int *)CMSG_DATA(cmsg));
124 return fd;
125 } else {
126 errno = result;
127 return -1;
128 }
129 }