diff --git a/lib/libifconfig/Makefile b/lib/libifconfig/Makefile --- a/lib/libifconfig/Makefile +++ b/lib/libifconfig/Makefile @@ -7,7 +7,7 @@ LIBADD= m SHLIBDIR?= /lib -SHLIB_MAJOR= 1 +SHLIB_MAJOR= 2 VERSION_DEF= ${LIBCSRCDIR}/Versions.def SYMBOL_MAPS= ${.CURDIR}/Symbol.map diff --git a/lib/libifconfig/Symbol.map b/lib/libifconfig/Symbol.map --- a/lib/libifconfig/Symbol.map +++ b/lib/libifconfig/Symbol.map @@ -26,12 +26,17 @@ 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; diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h --- a/lib/libifconfig/libifconfig.h +++ b/lib/libifconfig/libifconfig.h @@ -202,10 +202,73 @@ */ 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 diff --git a/lib/libifconfig/libifconfig_media.c b/lib/libifconfig/libifconfig_media.c --- a/lib/libifconfig/libifconfig_media.c +++ b/lib/libifconfig/libifconfig_media.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -53,11 +54,9 @@ #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 | \ @@ -65,74 +64,100 @@ 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[] = { { { @@ -192,83 +217,214 @@ }, }; -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); } /*************************************************************************** @@ -295,7 +451,6 @@ h->error.errcode = ENOMEM; return (-1); } - (void)memset(ms, 0, sizeof(*ms)); (void)strlcpy(ms->ifmr.ifm_name, name, sizeof(ms->ifmr.ifm_name)); /* @@ -363,36 +518,6 @@ } } -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) diff --git a/share/examples/libifconfig/status.c b/share/examples/libifconfig/status.c --- a/share/examples/libifconfig/status.c +++ b/share/examples/libifconfig/status.c @@ -406,7 +406,6 @@ * 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) { @@ -419,14 +418,19 @@ 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"); } @@ -438,15 +442,20 @@ 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); }