diff --git a/lib/libifconfig/Makefile b/lib/libifconfig/Makefile index 73dad36c1dc5..c6f006018427 100644 --- a/lib/libifconfig/Makefile +++ b/lib/libifconfig/Makefile @@ -1,48 +1,48 @@ # $FreeBSD$ PACKAGE= lib${LIB} LIB= ifconfig INTERNALLIB= true LIBADD= m SHLIBDIR?= /lib -SHLIB_MAJOR= 1 +SHLIB_MAJOR= 2 VERSION_DEF= ${LIBCSRCDIR}/Versions.def SYMBOL_MAPS= ${.CURDIR}/Symbol.map SRCS= libifconfig.c \ libifconfig_bridge.c \ libifconfig_carp.c \ libifconfig_inet.c \ libifconfig_inet6.c \ libifconfig_internal.c \ libifconfig_lagg.c \ libifconfig_media.c \ libifconfig_sfp.c GEN= libifconfig_sfp_tables.h \ libifconfig_sfp_tables.c \ libifconfig_sfp_tables_internal.h SRCS+= ${GEN} .include .SUFFIXES: .tpl.c .tpl.h .tpl.c.c .tpl.h.h: sfp.lua ${LUA} ${.CURDIR}/sfp.lua ${.IMPSRC} >${.TARGET} CLEANFILES+= ${GEN} # If libifconfig become public uncomment those two lines #INCSDIR= ${INCLUDEDIR} #INCS= libifconfig.h libifconfig_sfp.h libifconfig_sfp_tables.h #MAN= libifconfig.3 CFLAGS+= -I${.CURDIR} -I${.OBJDIR} NO_WCAST_ALIGN= yes .include diff --git a/lib/libifconfig/Symbol.map b/lib/libifconfig/Symbol.map index 782f78ec5e34..b40f304915b3 100644 --- a/lib/libifconfig/Symbol.map +++ b/lib/libifconfig/Symbol.map @@ -1,75 +1,80 @@ FBSD_1.6 { ifconfig_bridge_get_bridge_status; ifconfig_bridge_free_bridge_status; ifconfig_carp_get_info; ifconfig_close; ifconfig_create_interface; ifconfig_create_interface_vlan; ifconfig_destroy_interface; ifconfig_err_errno; ifconfig_err_errtype; ifconfig_err_ioctlreq; ifconfig_foreach_ifaddr; ifconfig_foreach_iface; ifconfig_get_capability; ifconfig_get_description; ifconfig_get_fib; ifconfig_get_groups; ifconfig_get_ifstatus; ifconfig_get_metric; ifconfig_get_mtu; ifconfig_get_nd6; ifconfig_get_orig_name; ifconfig_inet_get_addrinfo; ifconfig_inet6_get_addrinfo; ifconfig_lagg_free_lagg_status; ifconfig_lagg_get_lagg_status; ifconfig_lagg_get_laggport_status; ifconfig_list_cloners; + ifconfig_media_get_downreason; ifconfig_media_get_mediareq; - ifconfig_media_get_options_string; + ifconfig_media_get_mode; + ifconfig_media_get_options; ifconfig_media_get_status; ifconfig_media_get_subtype; ifconfig_media_get_type; - ifconfig_media_get_downreason; + ifconfig_media_lookup_mode; + ifconfig_media_lookup_options; + ifconfig_media_lookup_subtype; + ifconfig_media_lookup_type; ifconfig_open; ifconfig_set_capability; ifconfig_set_description; ifconfig_set_fib; ifconfig_set_metric; ifconfig_set_mtu; ifconfig_set_name; ifconfig_set_vlantag; ifconfig_sfp_channel_count; ifconfig_sfp_dump_region_count; ifconfig_sfp_free_sfp_status; ifconfig_sfp_get_sfp_dump; ifconfig_sfp_get_sfp_info; ifconfig_sfp_get_sfp_info_strings; ifconfig_sfp_get_sfp_status; ifconfig_sfp_get_sfp_vendor_info; ifconfig_sfp_physical_spec; ifconfig_unset_description; bias_mA; power_dBm; power_mW; /* Auto-generated. */ ifconfig_sfp_cab_tech_description; ifconfig_sfp_cab_tech_symbol; ifconfig_sfp_conn_description; ifconfig_sfp_conn_symbol; ifconfig_sfp_eth_10g_description; ifconfig_sfp_eth_10g_symbol; ifconfig_sfp_eth_1040g_description; ifconfig_sfp_eth_1040g_symbol; ifconfig_sfp_eth_description; ifconfig_sfp_eth_symbol; ifconfig_sfp_eth_ext_description; ifconfig_sfp_eth_ext_symbol; ifconfig_sfp_fc_speed_description; ifconfig_sfp_fc_speed_symbol; ifconfig_sfp_rev_description; ifconfig_sfp_rev_symbol; }; diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h index d8245ea13b23..e1cd6d1821a5 100644 --- a/lib/libifconfig/libifconfig.h +++ b/lib/libifconfig/libifconfig.h @@ -1,300 +1,363 @@ /* * Copyright (c) 2016-2017, Marie Helene Kvello-Aune * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * thislist of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #pragma once #include #include #include #include #define ND6_IFF_DEFAULTIF 0x8000 typedef enum { OK = 0, OTHER, IOCTL, SOCKET } ifconfig_errtype; /* * Opaque definition so calling application can just pass a * pointer to it for library use. */ struct ifconfig_handle; typedef struct ifconfig_handle ifconfig_handle_t; struct carpreq; struct ifaddrs; struct ifbropreq; struct ifbreq; struct in6_ndireq; struct lagg_reqall; struct lagg_reqflags; struct lagg_reqopts; struct lagg_reqport; /** Stores extra info associated with a bridge(4) interface */ struct ifconfig_bridge_status { struct ifbropreq *params; /**< current operational parameters */ struct ifbreq *members; /**< list of bridge members */ size_t members_count; /**< how many member interfaces */ uint32_t cache_size; /**< size of address cache */ uint32_t cache_lifetime; /**< address cache entry lifetime */ }; struct ifconfig_capabilities { /** Current capabilities (ifconfig prints this as 'options')*/ int curcap; /** Requested capabilities (ifconfig prints this as 'capabilities')*/ int reqcap; }; /** Stores extra info associated with an inet address */ struct ifconfig_inet_addr { const struct sockaddr_in *sin; const struct sockaddr_in *netmask; const struct sockaddr_in *dst; const struct sockaddr_in *broadcast; int prefixlen; uint8_t vhid; }; /** Stores extra info associated with an inet6 address */ struct ifconfig_inet6_addr { struct sockaddr_in6 *sin6; struct sockaddr_in6 *dstin6; struct in6_addrlifetime lifetime; int prefixlen; uint32_t flags; uint8_t vhid; }; /** Stores extra info associated with a lagg(4) interface */ struct ifconfig_lagg_status { struct lagg_reqall *ra; struct lagg_reqopts *ro; struct lagg_reqflags *rf; }; /** Retrieves a new state object for use in other API calls. * Example usage: *{@code * // Create state object * ifconfig_handle_t *lifh; * lifh = ifconfig_open(); * if (lifh == NULL) { * // Handle error * } * * // Do stuff with the handle * * // Dispose of the state object * ifconfig_close(lifh); * lifh = NULL; *} */ ifconfig_handle_t *ifconfig_open(void); /** Frees resources held in the provided state object. * @param h The state object to close. * @see #ifconfig_open(void) */ void ifconfig_close(ifconfig_handle_t *h); /** Identifies what kind of error occured. */ ifconfig_errtype ifconfig_err_errtype(ifconfig_handle_t *h); /** Retrieves the errno associated with the error, if any. */ int ifconfig_err_errno(ifconfig_handle_t *h); typedef void (*ifconfig_foreach_func_t)(ifconfig_handle_t *h, struct ifaddrs *ifa, void *udata); /** Iterate over every network interface * @param h An open ifconfig state object * @param cb A callback function to call with a pointer to each interface * @param udata An opaque value that will be passed to the callback. * @return 0 on success, nonzero if the list could not be iterated */ int ifconfig_foreach_iface(ifconfig_handle_t *h, ifconfig_foreach_func_t cb, void *udata); /** Iterate over every address on a single network interface * @param h An open ifconfig state object * @param ifa A pointer that was supplied by a previous call to * ifconfig_foreach_iface * @param udata An opaque value that will be passed to the callback. * @param cb A callback function to call with a pointer to each ifaddr */ void ifconfig_foreach_ifaddr(ifconfig_handle_t *h, struct ifaddrs *ifa, ifconfig_foreach_func_t cb, void *udata); /** If error type was IOCTL, this identifies which request failed. */ unsigned long ifconfig_err_ioctlreq(ifconfig_handle_t *h); int ifconfig_get_description(ifconfig_handle_t *h, const char *name, char **description); int ifconfig_set_description(ifconfig_handle_t *h, const char *name, const char *newdescription); int ifconfig_unset_description(ifconfig_handle_t *h, const char *name); int ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname); int ifconfig_get_orig_name(ifconfig_handle_t *h, const char *ifname, char **orig_name); int ifconfig_set_fib(ifconfig_handle_t *h, const char *name, int fib); int ifconfig_get_fib(ifconfig_handle_t *h, const char *name, int *fib); int ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu); int ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu); int ifconfig_get_nd6(ifconfig_handle_t *h, const char *name, struct in6_ndireq *nd); int ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int metric); int ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric); int ifconfig_set_capability(ifconfig_handle_t *h, const char *name, const int capability); int ifconfig_get_capability(ifconfig_handle_t *h, const char *name, struct ifconfig_capabilities *capability); /** Retrieve the list of groups to which this interface belongs * @param h An open ifconfig state object * @param name The interface name * @param ifgr return argument. The caller is responsible for freeing * ifgr->ifgr_groups * @return 0 on success, nonzero on failure */ int ifconfig_get_groups(ifconfig_handle_t *h, const char *name, struct ifgroupreq *ifgr); int ifconfig_get_ifstatus(ifconfig_handle_t *h, const char *name, struct ifstat *stat); /** Retrieve the interface media information * @param h An open ifconfig state object * @param name The interface name * @param ifmr Return argument. The caller is responsible for freeing it * @return 0 on success, nonzero on failure */ int ifconfig_media_get_mediareq(ifconfig_handle_t *h, const char *name, struct ifmediareq **ifmr); -const char *ifconfig_media_get_type(int ifmw); -const char *ifconfig_media_get_subtype(int ifmw); + const char *ifconfig_media_get_status(const struct ifmediareq *ifmr); -void ifconfig_media_get_options_string(int ifmw, char *buf, size_t buflen); + +typedef int ifmedia_t; + +#define INVALID_IFMEDIA ((ifmedia_t)-1) + +/** Retrieve the name of a media type + * @param media The media to be named + * @return A pointer to the media type name, or NULL on failure + */ +const char *ifconfig_media_get_type(ifmedia_t media); + +/** Retrieve a media type by its name + * @param name The name of a media type + * @return The media type value, or INVALID_IFMEDIA on failure + */ +ifmedia_t ifconfig_media_lookup_type(const char *name); + +/** Retrieve the name of a media subtype + * @param media The media subtype to be named + * @return A pointer to the media subtype name, or NULL on failure + */ +const char *ifconfig_media_get_subtype(ifmedia_t media); + +/** Retrieve a media subtype by its name + * @param media The top level media type whose subtype we want + * @param name The name of a media subtype + * @return The media subtype value, or INVALID_IFMEDIA on failure + */ +ifmedia_t ifconfig_media_lookup_subtype(ifmedia_t media, const char *name); + +/** Retrieve the name of a media mode + * @param media The media mode to be named + * @return A pointer to the media mode name, or NULL on failure + */ +const char *ifconfig_media_get_mode(ifmedia_t media); + +/** Retrieve a media mode by its name + * @param media The top level media type whose mode we want + * @param name The name of a media mode + * @return The media mode value, or INVALID_IFMEDIA on failure + */ +ifmedia_t ifconfig_media_lookup_mode(ifmedia_t media, const char *name); + +/** Retrieve an array of media options + * @param media The media for which to obtain the options + * @return Pointer to an array of pointers to option names, + * terminated by a NULL pointer, or simply NULL on failure. + * The caller is responsible for freeing the array but not its + * contents. + */ +const char **ifconfig_media_get_options(ifmedia_t media); + +/** Retrieve an array of media options by names + * @param media The top level media type whose options we want + * @param opts Pointer to an array of string pointers naming options + * @param nopts Number of elements in the opts array + * @return Pointer to an array of media options, one for each option named + * in opts. NULL is returned instead with errno set to ENOMEM if + * allocating the return array fails or EINVAL if media is not + * valid. A media option in the array will be INVALID_IFMEDIA + * when lookup failed for the option named in that position in + * opts. The caller is responsible for freeing the array. + */ +ifmedia_t *ifconfig_media_lookup_options(ifmedia_t media, const char **opts, + size_t nopts); /** Retrieve the reason the interface is down * @param h An open ifconfig state object * @param name The interface name * @param ifdr Return argument. * @return 0 on success, nonzero on failure */ int ifconfig_media_get_downreason(ifconfig_handle_t *h, const char *name, struct ifdownreason *ifdr); int ifconfig_carp_get_info(ifconfig_handle_t *h, const char *name, struct carpreq *carpr, int ncarpr); /** Retrieve additional information about an inet address * @param h An open ifconfig state object * @param name The interface name * @param ifa Pointer to the the address structure of interest * @param addr Return argument. It will be filled with additional information * about the address. * @return 0 on success, nonzero on failure. */ int ifconfig_inet_get_addrinfo(ifconfig_handle_t *h, const char *name, struct ifaddrs *ifa, struct ifconfig_inet_addr *addr); /** Retrieve additional information about an inet6 address * @param h An open ifconfig state object * @param name The interface name * @param ifa Pointer to the the address structure of interest * @param addr Return argument. It will be filled with additional information * about the address. * @return 0 on success, nonzero on failure. */ int ifconfig_inet6_get_addrinfo(ifconfig_handle_t *h, const char *name, struct ifaddrs *ifa, struct ifconfig_inet6_addr *addr); /** Retrieve additional information about a bridge(4) interface */ int ifconfig_bridge_get_bridge_status(ifconfig_handle_t *h, const char *name, struct ifconfig_bridge_status **bridge); /** Frees the structure returned by ifconfig_bridge_get_bridge_status. Does * nothing if the argument is NULL * @param bridge Pointer to the structure to free */ void ifconfig_bridge_free_bridge_status(struct ifconfig_bridge_status *bridge); /** Retrieve additional information about a lagg(4) interface */ int ifconfig_lagg_get_lagg_status(ifconfig_handle_t *h, const char *name, struct ifconfig_lagg_status **lagg_status); /** Retrieve additional information about a member of a lagg(4) interface */ int ifconfig_lagg_get_laggport_status(ifconfig_handle_t *h, const char *name, struct lagg_reqport *rp); /** Frees the structure returned by ifconfig_lagg_get_lagg_status. Does * nothing if the argument is NULL * @param laggstat Pointer to the structure to free */ void ifconfig_lagg_free_lagg_status(struct ifconfig_lagg_status *laggstat); /** Destroy a virtual interface * @param name Interface to destroy */ int ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name); /** Creates a (virtual) interface * @param name Name of interface to create. Example: bridge or bridge42 * @param name ifname Is set to actual name of created interface */ int ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname); /** Creates a (virtual) interface * @param name Name of interface to create. Example: vlan0 or ix0.50 * @param name ifname Is set to actual name of created interface * @param vlandev Name of interface to attach to * @param vlanid VLAN ID/Tag. Must not be 0. */ int ifconfig_create_interface_vlan(ifconfig_handle_t *h, const char *name, char **ifname, const char *vlandev, const unsigned short vlantag); int ifconfig_set_vlantag(ifconfig_handle_t *h, const char *name, const char *vlandev, const unsigned short vlantag); /** Gets the names of all interface cloners available on the system * @param bufp Set to the address of the names buffer on success or NULL * if an error occurs. This buffer must be freed when done. * @param lenp Set to the number of names in the returned buffer or 0 * if an error occurs. Each name is contained within an * IFNAMSIZ length slice of the buffer, for a total buffer * length of *lenp * IFNAMSIZ bytes. */ int ifconfig_list_cloners(ifconfig_handle_t *h, char **bufp, size_t *lenp); diff --git a/lib/libifconfig/libifconfig_media.c b/lib/libifconfig/libifconfig_media.c index d7ef507604be..e27f5900e3d3 100644 --- a/lib/libifconfig/libifconfig_media.c +++ b/lib/libifconfig/libifconfig_media.c @@ -1,404 +1,529 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include "libifconfig.h" #include "libifconfig_internal.h" - -static struct ifmedia_description *get_toptype_desc(int); -static struct ifmedia_type_to_subtype *get_toptype_ttos(int); -static struct ifmedia_description *get_subtype_desc(int, - struct ifmedia_type_to_subtype *ttos); +static const struct ifmedia_description *lookup_media_desc( + const struct ifmedia_description *, const char *); +static const struct ifmedia_type_to_subtype *get_toptype_ttos(ifmedia_t); #define IFM_OPMODE(x) \ ((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \ IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \ IFM_IEEE80211_MBSS)) #define IFM_IEEE80211_STA 0 -static struct ifmedia_description ifm_type_descriptions[] = +static const struct ifmedia_description + ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS; -static struct ifmedia_description ifm_subtype_ethernet_descriptions[] = +static const struct ifmedia_description + ifm_subtype_ethernet_descriptions[] = IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; -static struct ifmedia_description ifm_subtype_ethernet_aliases[] = +static const struct ifmedia_description + ifm_subtype_ethernet_aliases[] = IFM_SUBTYPE_ETHERNET_ALIASES; -static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = +static const struct ifmedia_description + ifm_subtype_ethernet_option_descriptions[] = IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; -static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = +static const struct ifmedia_description + ifm_subtype_ieee80211_descriptions[] = IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; -static struct ifmedia_description ifm_subtype_ieee80211_aliases[] = +static const struct ifmedia_description + ifm_subtype_ieee80211_aliases[] = IFM_SUBTYPE_IEEE80211_ALIASES; -static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = +static const struct ifmedia_description + ifm_subtype_ieee80211_option_descriptions[] = IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; -static struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] = +static const struct ifmedia_description + ifm_subtype_ieee80211_mode_descriptions[] = IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS; -static struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] = +static const struct ifmedia_description + ifm_subtype_ieee80211_mode_aliases[] = IFM_SUBTYPE_IEEE80211_MODE_ALIASES; -static struct ifmedia_description ifm_subtype_atm_descriptions[] = +static const struct ifmedia_description + ifm_subtype_atm_descriptions[] = IFM_SUBTYPE_ATM_DESCRIPTIONS; -static struct ifmedia_description ifm_subtype_atm_aliases[] = +static const struct ifmedia_description + ifm_subtype_atm_aliases[] = IFM_SUBTYPE_ATM_ALIASES; -static struct ifmedia_description ifm_subtype_atm_option_descriptions[] = +static const struct ifmedia_description + ifm_subtype_atm_option_descriptions[] = IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS; -static struct ifmedia_description ifm_subtype_shared_descriptions[] = +static const struct ifmedia_description + ifm_subtype_shared_descriptions[] = IFM_SUBTYPE_SHARED_DESCRIPTIONS; -static struct ifmedia_description ifm_subtype_shared_aliases[] = +static const struct ifmedia_description + ifm_subtype_shared_aliases[] = IFM_SUBTYPE_SHARED_ALIASES; -static struct ifmedia_description ifm_shared_option_descriptions[] = +static const struct ifmedia_description + ifm_shared_option_descriptions[] = IFM_SHARED_OPTION_DESCRIPTIONS; -static struct ifmedia_description ifm_shared_option_aliases[] = +static const struct ifmedia_description + ifm_shared_option_aliases[] = IFM_SHARED_OPTION_ALIASES; +static const struct ifmedia_description * +lookup_media_desc(const struct ifmedia_description *desc, const char *name) +{ + + for (; desc->ifmt_string != NULL; ++desc) + if (strcasecmp(desc->ifmt_string, name) == 0) + return (desc); + return (NULL); +} + struct ifmedia_type_to_subtype { struct { - struct ifmedia_description *desc; - int alias; + const struct ifmedia_description *desc; + bool alias; } subtypes[5]; struct { - struct ifmedia_description *desc; - int alias; + const struct ifmedia_description *desc; + bool alias; } options[4]; struct { - struct ifmedia_description *desc; - int alias; + const struct ifmedia_description *desc; + bool alias; } modes[3]; }; /* must be in the same order as IFM_TYPE_DESCRIPTIONS */ -static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = +static const struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { { { { &ifm_subtype_shared_descriptions[0], 0 }, { &ifm_subtype_shared_aliases[0], 1 }, { &ifm_subtype_ethernet_descriptions[0], 0 }, { &ifm_subtype_ethernet_aliases[0], 1 }, { NULL, 0 }, }, { { &ifm_shared_option_descriptions[0], 0 }, { &ifm_shared_option_aliases[0], 1 }, { &ifm_subtype_ethernet_option_descriptions[0], 0 }, { NULL, 0 }, }, { { NULL, 0 }, }, }, { { { &ifm_subtype_shared_descriptions[0], 0 }, { &ifm_subtype_shared_aliases[0], 1 }, { &ifm_subtype_ieee80211_descriptions[0], 0 }, { &ifm_subtype_ieee80211_aliases[0], 1 }, { NULL, 0 }, }, { { &ifm_shared_option_descriptions[0], 0 }, { &ifm_shared_option_aliases[0], 1 }, { &ifm_subtype_ieee80211_option_descriptions[0], 0 }, { NULL, 0 }, }, { { &ifm_subtype_ieee80211_mode_descriptions[0], 0 }, { &ifm_subtype_ieee80211_mode_aliases[0], 0 }, { NULL, 0 }, }, }, { { { &ifm_subtype_shared_descriptions[0], 0 }, { &ifm_subtype_shared_aliases[0], 1 }, { &ifm_subtype_atm_descriptions[0], 0 }, { &ifm_subtype_atm_aliases[0], 1 }, { NULL, 0 }, }, { { &ifm_shared_option_descriptions[0], 0 }, { &ifm_shared_option_aliases[0], 1 }, { &ifm_subtype_atm_option_descriptions[0], 0 }, { NULL, 0 }, }, { { NULL, 0 }, }, }, }; -static struct ifmedia_description * -get_toptype_desc(int ifmw) +static const struct ifmedia_type_to_subtype * +get_toptype_ttos(ifmedia_t media) { - struct ifmedia_description *desc; + const struct ifmedia_description *desc; + const struct ifmedia_type_to_subtype *ttos; - for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) { - if (IFM_TYPE(ifmw) == desc->ifmt_word) { - break; - } + for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; + desc->ifmt_string != NULL; desc++, ttos++) { + if (IFM_TYPE(media) == desc->ifmt_word) + return (ttos); } - - return (desc); + errno = ENOENT; + return (NULL); } -static struct ifmedia_type_to_subtype * -get_toptype_ttos(int ifmw) +const char * +ifconfig_media_get_type(ifmedia_t media) { - struct ifmedia_description *desc; - struct ifmedia_type_to_subtype *ttos; + const struct ifmedia_description *desc; - for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; - desc->ifmt_string != NULL; desc++, ttos++) { - if (IFM_TYPE(ifmw) == desc->ifmt_word) { - break; - } + for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; ++desc) { + if (IFM_TYPE(media) == desc->ifmt_word) + return (desc->ifmt_string); } + errno = ENOENT; + return (NULL); +} + +ifmedia_t +ifconfig_media_lookup_type(const char *name) +{ + const struct ifmedia_description *desc; - return (ttos); + desc = lookup_media_desc(ifm_type_descriptions, name); + return (desc == NULL ? INVALID_IFMEDIA : desc->ifmt_word); } -static struct ifmedia_description * -get_subtype_desc(int ifmw, - struct ifmedia_type_to_subtype *ttos) +const char * +ifconfig_media_get_subtype(ifmedia_t media) { - int i; - struct ifmedia_description *desc; + const struct ifmedia_description *desc; + const struct ifmedia_type_to_subtype *ttos; + + ttos = get_toptype_ttos(media); + if (ttos == NULL) { + errno = EINVAL; + return (NULL); + } - for (i = 0; ttos->subtypes[i].desc != NULL; i++) { - if (ttos->subtypes[i].alias) { + for (size_t i = 0; ttos->subtypes[i].desc != NULL; ++i) { + if (ttos->subtypes[i].alias) continue; - } for (desc = ttos->subtypes[i].desc; - desc->ifmt_string != NULL; desc++) { - if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) { - return (desc); - } + desc->ifmt_string != NULL; ++desc) { + if (IFM_SUBTYPE(media) == desc->ifmt_word) + return (desc->ifmt_string); } } - + errno = ENOENT; return (NULL); } -const char * -ifconfig_media_get_type(int ifmw) +ifmedia_t +ifconfig_media_lookup_subtype(ifmedia_t media, const char *name) { - struct ifmedia_description *desc; + const struct ifmedia_description *desc; + const struct ifmedia_type_to_subtype *ttos; - /*int seen_option = 0, i;*/ + ttos = get_toptype_ttos(media); + if (ttos == NULL) { + errno = EINVAL; + return (INVALID_IFMEDIA); + } - /* Find the top-level interface type. */ - desc = get_toptype_desc(ifmw); - if (desc->ifmt_string == NULL) { - return (""); - } else { - return (desc->ifmt_string); + for (size_t i = 0; ttos->subtypes[i].desc != NULL; ++i) { + desc = lookup_media_desc(ttos->subtypes[i].desc, name); + if (desc != NULL) + return (desc->ifmt_word); } + errno = ENOENT; + return (INVALID_IFMEDIA); } const char * -ifconfig_media_get_subtype(int ifmw) +ifconfig_media_get_mode(ifmedia_t media) { - struct ifmedia_description *desc; - struct ifmedia_type_to_subtype *ttos; + const struct ifmedia_description *desc; + const struct ifmedia_type_to_subtype *ttos; + + ttos = get_toptype_ttos(media); + if (ttos == NULL) { + errno = EINVAL; + return (NULL); + } - ttos = get_toptype_ttos(ifmw); - desc = get_subtype_desc(ifmw, ttos); - return (desc->ifmt_string); + for (size_t i = 0; ttos->modes[i].desc != NULL; ++i) { + if (ttos->modes[i].alias) + continue; + for (desc = ttos->modes[i].desc; + desc->ifmt_string != NULL; ++desc) { + if (IFM_MODE(media) == desc->ifmt_word) + return (desc->ifmt_string); + } + } + errno = ENOENT; + return (NULL); +} + +ifmedia_t +ifconfig_media_lookup_mode(ifmedia_t media, const char *name) +{ + const struct ifmedia_description *desc; + const struct ifmedia_type_to_subtype *ttos; + + ttos = get_toptype_ttos(media); + if (ttos == NULL) { + errno = EINVAL; + return (INVALID_IFMEDIA); + } + + for (size_t i = 0; ttos->modes[i].desc != NULL; ++i) { + desc = lookup_media_desc(ttos->modes[i].desc, name); + if (desc != NULL) + return (desc->ifmt_word); + } + errno = ENOENT; + return (INVALID_IFMEDIA); +} + +const char ** +ifconfig_media_get_options(ifmedia_t media) +{ + const char **options; + const struct ifmedia_description *desc; + const struct ifmedia_type_to_subtype *ttos; + size_t n; + + ttos = get_toptype_ttos(media); + if (ttos == NULL) { + errno = EINVAL; + return (NULL); + } + + n = 0; + for (size_t i = 0; ttos->options[i].desc != NULL; ++i) { + if (ttos->options[i].alias) + continue; + for (desc = ttos->options[i].desc; + desc->ifmt_string != NULL; ++desc) { + if ((media & desc->ifmt_word) != 0) + ++n; + } + } + if (n == 0) { + errno = ENOENT; + return (NULL); + } + + options = calloc(n + 1, sizeof(*options)); + if (options == NULL) + return (NULL); + + options[n] = NULL; + n = 0; + for (size_t i = 0; ttos->options[i].desc != NULL; ++i) { + if (ttos->options[i].alias) + continue; + for (desc = ttos->options[i].desc; + desc->ifmt_string != NULL; ++desc) { + if ((media & desc->ifmt_word) != 0) { + options[n] = desc->ifmt_string; + ++n; + } + } + } + return (options); +} + +ifmedia_t * +ifconfig_media_lookup_options(ifmedia_t media, const char **opts, size_t nopts) +{ + ifmedia_t *options; + const struct ifmedia_description *desc, *opt; + const struct ifmedia_type_to_subtype *ttos; + + assert(opts != NULL); + assert(nopts > 0); + + ttos = get_toptype_ttos(media); + if (ttos == NULL) { + errno = EINVAL; + return (NULL); + } + + options = calloc(nopts, sizeof(*options)); + if (options == NULL) + return (NULL); + (void)memset(options, INVALID_IFMEDIA, nopts * sizeof(ifmedia_t)); + + for (size_t i = 0; ttos->options[i].desc != NULL; ++i) { + desc = ttos->options[i].desc; + for (size_t j = 0; j < nopts; ++j) { + opt = lookup_media_desc(desc, opts[j]); + if (opt != NULL) + options[j] = opt->ifmt_word; + } + } + return (options); } /*************************************************************************** * Above this point, this file is mostly copied from sbin/ifconfig/ifmedia.c ***************************************************************************/ /* Internal structure used for allocations and frees */ struct _ifconfig_media_status { struct ifmediareq ifmr; int medialist[0]; }; int ifconfig_media_get_mediareq(ifconfig_handle_t *h, const char *name, struct ifmediareq **ifmr) { struct _ifconfig_media_status *ms, *ms2; unsigned long cmd = SIOCGIFXMEDIA; *ifmr = NULL; ms = calloc(1, sizeof(*ms)); if (ms == NULL) { h->error.errtype = OTHER; h->error.errcode = ENOMEM; return (-1); } - (void)memset(ms, 0, sizeof(*ms)); (void)strlcpy(ms->ifmr.ifm_name, name, sizeof(ms->ifmr.ifm_name)); /* * Check if interface supports extended media types. */ if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms->ifmr) < 0) { cmd = SIOCGIFMEDIA; if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms->ifmr) < 0) { /* Interface doesn't support SIOC{G,S}IFMEDIA. */ h->error.errtype = OK; free(ms); return (-1); } } if (ms->ifmr.ifm_count == 0) { *ifmr = &ms->ifmr; return (0); /* Interface has no media types ?*/ } ms2 = realloc(ms, sizeof(*ms) + sizeof(int) * ms->ifmr.ifm_count); if (ms2 == NULL) { h->error.errtype = OTHER; h->error.errcode = ENOMEM; free(ms); return (-1); } ms2->ifmr.ifm_ulist = &ms2->medialist[0]; if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms2->ifmr) < 0) { free(ms2); return (-1); } *ifmr = &ms2->ifmr; return (0); } const char * ifconfig_media_get_status(const struct ifmediareq *ifmr) { switch (IFM_TYPE(ifmr->ifm_active)) { case IFM_ETHER: case IFM_ATM: if (ifmr->ifm_status & IFM_ACTIVE) { return ("active"); } else { return ("no carrier"); } break; case IFM_IEEE80211: if (ifmr->ifm_status & IFM_ACTIVE) { /* NB: only sta mode associates */ if (IFM_OPMODE(ifmr->ifm_active) == IFM_IEEE80211_STA) { return ("associated"); } else { return ("running"); } } else { return ("no carrier"); } break; default: return (""); } } -void -ifconfig_media_get_options_string(int ifmw, char *buf, size_t buflen) -{ - struct ifmedia_type_to_subtype *ttos; - struct ifmedia_description *desc; - int i, seen_option = 0; - size_t len; - - assert(buflen > 0); - buf[0] = '\0'; - ttos = get_toptype_ttos(ifmw); - for (i = 0; ttos->options[i].desc != NULL; i++) { - if (ttos->options[i].alias) { - continue; - } - for (desc = ttos->options[i].desc; - desc->ifmt_string != NULL; desc++) { - if (ifmw & desc->ifmt_word) { - if (seen_option++) { - strlcat(buf, ",", buflen); - } - len = strlcat(buf, desc->ifmt_string, buflen); - assert(len < buflen); - buf += len; - buflen -= len; - } - } - } -} - int ifconfig_media_get_downreason(ifconfig_handle_t *h, const char *name, struct ifdownreason *ifdr) { (void)memset(ifdr, 0, sizeof(*ifdr)); (void)strlcpy(ifdr->ifdr_name, name, sizeof(ifdr->ifdr_name)); return (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDOWNREASON, ifdr)); } diff --git a/share/examples/libifconfig/status.c b/share/examples/libifconfig/status.c index 62fd3f35c8de..114cf7e87a68 100644 --- a/share/examples/libifconfig/status.c +++ b/share/examples/libifconfig/status.c @@ -1,530 +1,539 @@ /* * Copyright (c) 2017, Spectra Logic Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * thislist of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const char *carp_states[] = { CARP_STATES }; static void print_carp(ifconfig_handle_t *lifh, struct ifaddrs *ifa) { struct carpreq carpr[CARP_MAXVHID]; int i; if (ifconfig_carp_get_info(lifh, ifa->ifa_name, carpr, CARP_MAXVHID)) { return; /* Probably not configured on this interface */ } for (i = 0; i < carpr[0].carpr_count; i++) { printf("\tcarp: %s vhid %d advbase %d advskew %d", carp_states[carpr[i].carpr_state], carpr[i].carpr_vhid, carpr[i].carpr_advbase, carpr[i].carpr_advskew); printf("\n"); } } static void print_inet4_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa) { struct ifconfig_inet_addr addr; char addr_buf[NI_MAXHOST]; if (ifconfig_inet_get_addrinfo(lifh, ifa->ifa_name, ifa, &addr) != 0) { return; } inet_ntop(AF_INET, &addr.sin->sin_addr, addr_buf, sizeof(addr_buf)); printf("\tinet %s", addr_buf); if (addr.dst) { printf(" --> %s", inet_ntoa(addr.dst->sin_addr)); } printf(" netmask 0x%x ", ntohl(addr.netmask->sin_addr.s_addr)); if ((addr.broadcast != NULL) && (addr.broadcast->sin_addr.s_addr != 0)) { printf("broadcast %s ", inet_ntoa(addr.broadcast->sin_addr)); } if (addr.vhid != 0) { printf("vhid %d ", addr.vhid); } printf("\n"); } static void print_inet6_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa) { struct ifconfig_inet6_addr addr; char addr_buf[NI_MAXHOST]; struct timespec now; /* Print the address */ if (ifconfig_inet6_get_addrinfo(lifh, ifa->ifa_name, ifa, &addr) != 0) { err(1, "ifconfig_inet6_get_addrinfo"); } if (0 != getnameinfo((struct sockaddr *)addr.sin6, addr.sin6->sin6_len, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST)) { inet_ntop(AF_INET6, &addr.sin6->sin6_addr, addr_buf, sizeof(addr_buf)); } printf("\tinet6 %s", addr_buf); if (addr.dstin6) { inet_ntop(AF_INET6, addr.dstin6, addr_buf, sizeof(addr_buf)); printf(" --> %s", addr_buf); } /* Print the netmask */ printf(" prefixlen %d ", addr.prefixlen); /* Print the scopeid*/ if (addr.sin6->sin6_scope_id) { printf("scopeid 0x%x ", addr.sin6->sin6_scope_id); } /* Print the flags */ if ((addr.flags & IN6_IFF_ANYCAST) != 0) { printf("anycast "); } if ((addr.flags & IN6_IFF_TENTATIVE) != 0) { printf("tentative "); } if ((addr.flags & IN6_IFF_DUPLICATED) != 0) { printf("duplicated "); } if ((addr.flags & IN6_IFF_DETACHED) != 0) { printf("detached "); } if ((addr.flags & IN6_IFF_DEPRECATED) != 0) { printf("deprecated "); } if ((addr.flags & IN6_IFF_AUTOCONF) != 0) { printf("autoconf "); } if ((addr.flags & IN6_IFF_TEMPORARY) != 0) { printf("temporary "); } if ((addr.flags & IN6_IFF_PREFER_SOURCE) != 0) { printf("prefer_source "); } /* Print the lifetimes */ clock_gettime(CLOCK_MONOTONIC_FAST, &now); if (addr.lifetime.ia6t_preferred || addr.lifetime.ia6t_expire) { printf("pltime "); if (addr.lifetime.ia6t_preferred) { printf("%ld ", MAX(0l, addr.lifetime.ia6t_preferred - now.tv_sec)); } else { printf("infty "); } printf("vltime "); if (addr.lifetime.ia6t_expire) { printf("%ld ", MAX(0l, addr.lifetime.ia6t_expire - now.tv_sec)); } else { printf("infty "); } } /* Print the vhid */ if (addr.vhid != 0) { printf("vhid %d ", addr.vhid); } printf("\n"); } static void print_link_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa) { char addr_buf[NI_MAXHOST]; struct sockaddr_dl *sdl; int n; sdl = (struct sockaddr_dl *)ifa->ifa_addr; if ((sdl != NULL) && (sdl->sdl_alen > 0)) { if (((sdl->sdl_type == IFT_ETHER) || (sdl->sdl_type == IFT_L2VLAN) || (sdl->sdl_type == IFT_BRIDGE)) && (sdl->sdl_alen == ETHER_ADDR_LEN)) { ether_ntoa_r((struct ether_addr *)LLADDR(sdl), addr_buf); printf("\tether %s\n", addr_buf); } else { n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; printf("\tlladdr %s\n", link_ntoa(sdl) + n); } } } static void print_ifaddr(ifconfig_handle_t *lifh, struct ifaddrs *ifa, void *udata __unused) { switch (ifa->ifa_addr->sa_family) { case AF_INET: print_inet4_addr(lifh, ifa); break; case AF_INET6: /* * printing AF_INET6 status requires calling SIOCGIFAFLAG_IN6 * and SIOCGIFALIFETIME_IN6. TODO: figure out the best way to * do that from within libifconfig */ print_inet6_addr(lifh, ifa); break; case AF_LINK: print_link_addr(lifh, ifa); break; case AF_LOCAL: case AF_UNSPEC: default: /* TODO */ break; } } static void print_nd6(ifconfig_handle_t *lifh, struct ifaddrs *ifa) { struct in6_ndireq nd; if (ifconfig_get_nd6(lifh, ifa->ifa_name, &nd) == 0) { printf("\tnd6 options=%x\n", nd.ndi.flags); } else { err(1, "Failed to get nd6 options"); } } static void print_fib(ifconfig_handle_t *lifh, struct ifaddrs *ifa) { int fib; if (ifconfig_get_fib(lifh, ifa->ifa_name, &fib) == 0) { printf("\tfib: %d\n", fib); } else { err(1, "Failed to get interface FIB"); } } static void print_lagg(ifconfig_handle_t *lifh, struct ifaddrs *ifa) { struct lagg_protos lpr[] = LAGG_PROTOS; struct ifconfig_lagg_status *ls; struct lacp_opreq *lp; const char *proto = ""; int i; if (ifconfig_lagg_get_lagg_status(lifh, ifa->ifa_name, &ls) < 0) { if (ifconfig_err_errno(lifh) == EINVAL) { return; } err(1, "Failed to get interface lagg status"); } /* First print the proto */ for (i = 0; i < nitems(lpr); i++) { if (ls->ra->ra_proto == lpr[i].lpr_proto) { proto = lpr[i].lpr_name; break; } } printf("\tlaggproto %s", proto); /* Now print the lagg hash */ if (ls->rf->rf_flags & LAGG_F_HASHMASK) { const char *sep = ""; printf(" lagghash "); if (ls->rf->rf_flags & LAGG_F_HASHL2) { printf("%sl2", sep); sep = ","; } if (ls->rf->rf_flags & LAGG_F_HASHL3) { printf("%sl3", sep); sep = ","; } if (ls->rf->rf_flags & LAGG_F_HASHL4) { printf("%sl4", sep); sep = ","; } } putchar('\n'); printf("\tlagg options:\n"); printf("\t\tflags=%x", ls->ro->ro_opts); putchar('\n'); printf("\t\tflowid_shift: %d\n", ls->ro->ro_flowid_shift); if (ls->ra->ra_proto == LAGG_PROTO_ROUNDROBIN) { printf("\t\trr_limit: %d\n", ls->ro->ro_bkt); } printf("\tlagg statistics:\n"); printf("\t\tactive ports: %d\n", ls->ro->ro_active); printf("\t\tflapping: %u\n", ls->ro->ro_flapping); for (i = 0; i < ls->ra->ra_ports; i++) { lp = (struct lacp_opreq *)&ls->ra->ra_port[i].rp_lacpreq; printf("\tlaggport: %s ", ls->ra->ra_port[i].rp_portname); printf("flags=%x", ls->ra->ra_port[i].rp_flags); if (ls->ra->ra_proto == LAGG_PROTO_LACP) { printf(" state=%x", lp->actor_state); } putchar('\n'); } printf("\n"); ifconfig_lagg_free_lagg_status(ls); } static void print_laggport(ifconfig_handle_t *lifh, struct ifaddrs *ifa) { struct lagg_reqport rp; if (ifconfig_lagg_get_laggport_status(lifh, ifa->ifa_name, &rp) < 0) { if ((ifconfig_err_errno(lifh) == EINVAL) || (ifconfig_err_errno(lifh) == ENOENT)) { return; } else { err(1, "Failed to get lagg port status"); } } printf("\tlaggdev: %s\n", rp.rp_ifname); } static void print_groups(ifconfig_handle_t *lifh, struct ifaddrs *ifa) { struct ifgroupreq ifgr; struct ifg_req *ifg; int len; int cnt = 0; if (ifconfig_get_groups(lifh, ifa->ifa_name, &ifgr) != 0) { err(1, "Failed to get groups"); } ifg = ifgr.ifgr_groups; len = ifgr.ifgr_len; for (; ifg && len >= sizeof(struct ifg_req); ifg++) { len -= sizeof(struct ifg_req); if (strcmp(ifg->ifgrq_group, "all")) { if (cnt == 0) { printf("\tgroups: "); } cnt++; printf("%s ", ifg->ifgrq_group); } } if (cnt) { printf("\n"); } free(ifgr.ifgr_groups); } static void print_media(ifconfig_handle_t *lifh, struct ifaddrs *ifa) { int i; /* Outline: * 1) Determine whether the iface supports SIOGIFMEDIA or SIOGIFXMEDIA * 2) Get the full media list * 3) Print the current media word * 4) Print the active media word, if different * 5) Print the status * 6) Print the supported media list * * How to print the media word: * 1) Get the top-level interface type and description * 2) Print the subtype * 3) For current word only, print the top type, if it exists * 4) Print options list * 5) Print the instance, if there is one * * How to get the top-level interface type * 1) Shift ifmw right by 0x20 and index into IFM_TYPE_DESCRIPTIONS * * How to get the top-level interface subtype * 1) Shift ifmw right by 0x20, index into ifmedia_types_to_subtypes * 2) Iterate through the resulting table's subtypes table, ignoring * aliases. Iterate through the resulting ifmedia_description * tables, finding an entry with the right media subtype */ struct ifmediareq *ifmr; - char opts[80]; if (ifconfig_media_get_mediareq(lifh, ifa->ifa_name, &ifmr) != 0) { if (ifconfig_err_errtype(lifh) != OK) { err(1, "Failed to get media info"); } else { return; /* Interface doesn't support media info */ } } printf("\tmedia: %s %s", ifconfig_media_get_type(ifmr->ifm_current), ifconfig_media_get_subtype(ifmr->ifm_current)); if (ifmr->ifm_active != ifmr->ifm_current) { + const char **options; + printf(" (%s", ifconfig_media_get_subtype(ifmr->ifm_active)); - ifconfig_media_get_options_string(ifmr->ifm_active, opts, - sizeof(opts)); - if (opts[0] != '\0') { - printf(" <%s>)\n", opts); + options = ifconfig_media_get_options(ifmr->ifm_active); + if (options != NULL && options[0] != NULL) { + printf(" <%s", options[0]); + for (size_t i = 1; options[i] != NULL; ++i) + printf(",%s", options[i]); + printf(">)\n"); } else { printf(")\n"); } + free(options); } else { printf("\n"); } if (ifmr->ifm_status & IFM_AVALID) { printf("\tstatus: %s\n", ifconfig_media_get_status(ifmr)); } printf("\tsupported media:\n"); for (i = 0; i < ifmr->ifm_count; i++) { + const char **options; + printf("\t\tmedia %s", ifconfig_media_get_subtype(ifmr->ifm_ulist[i])); - ifconfig_media_get_options_string(ifmr->ifm_ulist[i], opts, - sizeof(opts)); - if (opts[0] != '\0') { - printf(" mediaopt %s\n", opts); + options = ifconfig_media_get_options(ifmr->ifm_ulist[i]); + if (options != NULL && options[0] != NULL) { + printf(" mediaopt %s", options[0]); + for (size_t i = 1; options[i] != NULL; ++i) + printf(",%s", options[i]); + printf("\n"); } else { printf("\n"); } + free(options); } free(ifmr); } static void print_iface(ifconfig_handle_t *lifh, struct ifaddrs *ifa, void *udata __unused) { int metric, mtu; char *description = NULL; struct ifconfig_capabilities caps; struct ifstat ifs; printf("%s: flags=%x ", ifa->ifa_name, ifa->ifa_flags); if (ifconfig_get_metric(lifh, ifa->ifa_name, &metric) == 0) { printf("metric %d ", metric); } else { err(1, "Failed to get interface metric"); } if (ifconfig_get_mtu(lifh, ifa->ifa_name, &mtu) == 0) { printf("mtu %d\n", mtu); } else { err(1, "Failed to get interface MTU"); } if (ifconfig_get_description(lifh, ifa->ifa_name, &description) == 0) { printf("\tdescription: %s\n", description); } if (ifconfig_get_capability(lifh, ifa->ifa_name, &caps) == 0) { if (caps.curcap != 0) { printf("\toptions=%x\n", caps.curcap); } if (caps.reqcap != 0) { printf("\tcapabilities=%x\n", caps.reqcap); } } else { err(1, "Failed to get interface capabilities"); } ifconfig_foreach_ifaddr(lifh, ifa, print_ifaddr, NULL); /* This paragraph is equivalent to ifconfig's af_other_status funcs */ print_nd6(lifh, ifa); print_media(lifh, ifa); print_groups(lifh, ifa); print_fib(lifh, ifa); print_carp(lifh, ifa); print_lagg(lifh, ifa); print_laggport(lifh, ifa); if (ifconfig_get_ifstatus(lifh, ifa->ifa_name, &ifs) == 0) { printf("%s", ifs.ascii); } free(description); } int main(int argc, char *argv[]) { ifconfig_handle_t *lifh; if (argc != 1) { errx(1, "Usage: example_status"); } lifh = ifconfig_open(); if (lifh == NULL) { errx(1, "Failed to open libifconfig handle."); } if (ifconfig_foreach_iface(lifh, print_iface, NULL) != 0) { err(1, "Failed to get interfaces"); } ifconfig_close(lifh); lifh = NULL; return (-1); }