Changeset View
Changeset View
Standalone View
Standalone View
lib/libifconfig/src/libifconfig.c
Property | Old Value | New Value |
---|---|---|
svn:eol-style | null | native \ No newline at end of property |
svn:keywords | null | FreeBSD=%H \ No newline at end of property |
svn:mime-type | null | text/plain \ No newline at end of property |
/* | |||||
* Copyright (c) 2016, 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. | |||||
* | |||||
* 3. Neither the name of the copyright holder 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 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. | |||||
*/ | |||||
/* | |||||
* 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. | |||||
* 4. 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. | |||||
*/ | |||||
#include <sys/ioctl.h> | |||||
#include <net/if.h> | |||||
#include <err.h> | |||||
#include <errno.h> | |||||
#include <fcntl.h> | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <unistd.h> | |||||
#include "libifconfig.h" | |||||
#include "libifconfig_internal.h" | |||||
libifc_handle_t * | |||||
libifc_open() | |||||
{ | |||||
struct libifc_handle *h; | |||||
h = calloc(1, sizeof(struct libifc_handle)); | |||||
return (h); | |||||
} | |||||
void | |||||
libifc_close(libifc_handle_t *h) | |||||
{ | |||||
if (h->sockets.sdkeys != NULL) { | |||||
free(h->sockets.sdkeys); | |||||
h->sockets.sdkeys = NULL; | |||||
} | |||||
if (h->sockets.sdvals != NULL) { | |||||
for (int i = 0; i < h->sockets.sdindex; i++) { | |||||
(void)close(h->sockets.sdvals[i]); | |||||
} | |||||
free(h->sockets.sdvals); | |||||
h->sockets.sdvals = NULL; | |||||
} | |||||
h->sockets.sdindex = 0; | |||||
free(h); | |||||
} | |||||
libifc_errtype | |||||
libifc_err_errtype(libifc_handle_t *h) | |||||
{ | |||||
return (h->error.errtype); | |||||
} | |||||
int | |||||
libifc_err_errno(libifc_handle_t *h) | |||||
{ | |||||
return (h->error.errcode); | |||||
} | |||||
unsigned long | |||||
libifc_err_ioctlreq(libifc_handle_t *h) | |||||
{ | |||||
return (h->error.ioctl_request); | |||||
} | |||||
int | |||||
libifc_get_description(libifc_handle_t *h, const char *name, char **description) | |||||
{ | |||||
struct ifreq ifr; | |||||
char *descr = NULL; | |||||
size_t descrlen = 64; | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
for (;;) { | |||||
if ((descr = reallocf(descr, descrlen)) != NULL) { | |||||
kp: This will likely be easier to read if the conditions are inverted, i.e. check for error, not… | |||||
marieheleneka_gmail.comAuthorUnsubmitted Done Inline ActionsChop all the x-mas trees. :) marieheleneka_gmail.com: Chop all the x-mas trees. :) | |||||
ifr.ifr_buffer.buffer = descr; | |||||
ifr.ifr_buffer.length = descrlen; | |||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR, | |||||
&ifr) == 0) { | |||||
if (ifr.ifr_buffer.buffer == descr) { | |||||
if (strlen(descr) > 0) { | |||||
*description = strdup(descr); | |||||
free(descr); | |||||
return (0); | |||||
} | |||||
} else if (ifr.ifr_buffer.length > descrlen) { | |||||
descrlen = ifr.ifr_buffer.length; | |||||
continue; | |||||
} | |||||
} else { | |||||
return (-1); | |||||
} | |||||
} else { | |||||
free(descr); | |||||
h->error.errtype = OTHER; | |||||
h->error.errcode = ENOMEM; | |||||
return (-1); | |||||
} | |||||
break; | |||||
} | |||||
free(descr); | |||||
h->error.errtype = OTHER; | |||||
h->error.errcode = 0; | |||||
return (-1); | |||||
} | |||||
int | |||||
libifc_set_description(libifc_handle_t *h, const char *name, | |||||
const char *newdescription) | |||||
{ | |||||
struct ifreq ifr; | |||||
int desclen; | |||||
desclen = strlen(newdescription); | |||||
/* | |||||
* Unset description if the new description is 0 characters long. | |||||
* TODO: Decide whether this should be an error condition instead. | |||||
*/ | |||||
if (desclen == 0) { | |||||
return (libifc_unset_description(h, name)); | |||||
} | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
ifr.ifr_buffer.length = desclen + 1; | |||||
ifr.ifr_buffer.buffer = strdup(newdescription); | |||||
if (ifr.ifr_buffer.buffer == NULL) { | |||||
h->error.errtype = OTHER; | |||||
h->error.errcode = ENOMEM; | |||||
return (-1); | |||||
} | |||||
/* | |||||
* TODO: Check whether this ioctl() call truncates or fails when new | |||||
kpUnsubmitted Done Inline ActionsThe maximum length is configured through the net.ifdescr_maxlen sysctl. I don't think you need to check for this before the ioctl() call. Just handle the error. kp: The maximum length is configured through the net.ifdescr_maxlen sysctl.
If the name is longer… | |||||
* description is too long. If truncates, this function should probably | |||||
* have an error condition for this further up. | |||||
*/ | |||||
if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFDESCR, &ifr) != 0) { | |||||
if (ifr.ifr_buffer.buffer != NULL) { | |||||
free(ifr.ifr_buffer.buffer); | |||||
} | |||||
return (-1); | |||||
} | |||||
if (ifr.ifr_buffer.buffer != NULL) { | |||||
kpUnsubmitted Done Inline ActionsIt's safe to call free(NULL). You don't need this check. kp: It's safe to call free(NULL). You don't need this check.
Also, I don't think it can be NULL at… | |||||
free(ifr.ifr_buffer.buffer); | |||||
} | |||||
return (0); | |||||
} | |||||
int libifc_unset_description(libifc_handle_t *h, const char *name) | |||||
{ | |||||
struct ifreq ifr; | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
ifr.ifr_buffer.length = 0; | |||||
ifr.ifr_buffer.buffer = NULL; | |||||
if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFDESCR, &ifr) < 0) { | |||||
return (-1); | |||||
} | |||||
return (0); | |||||
} | |||||
int libifc_set_name(libifc_handle_t *h, const char *name, const char *newname) | |||||
{ | |||||
struct ifreq ifr; | |||||
char *tmpname; | |||||
tmpname = strdup(newname); | |||||
if (tmpname == NULL) { | |||||
h->error.errtype = OTHER; | |||||
h->error.errcode = ENOMEM; | |||||
return (-1); | |||||
} | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
ifr.ifr_data = tmpname; | |||||
/* | |||||
* TODO: Check whether this ioctl() call truncates or fails when new | |||||
kpUnsubmitted Done Inline ActionsThe kernel doesn't truncate, and if the name is longer than it likes you'll get an error. kp: The kernel doesn't truncate, and if the name is longer than it likes you'll get an error. | |||||
* name is too long. If truncates, this function should have an error | |||||
* condition for this further up. | |||||
*/ | |||||
if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFNAME, &ifr) != 0) { | |||||
free(tmpname); | |||||
return (-1); | |||||
} | |||||
free(tmpname); | |||||
return (0); | |||||
} | |||||
int libifc_set_mtu(libifc_handle_t *h, const char *name, const int mtu) | |||||
{ | |||||
struct ifreq ifr; | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
ifr.ifr_mtu = mtu; | |||||
if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFMTU, &ifr) < 0) { | |||||
return (-1); | |||||
} | |||||
return (0); | |||||
} | |||||
int libifc_get_mtu(libifc_handle_t *h, const char *name, int *mtu) | |||||
{ | |||||
struct ifreq ifr; | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, &ifr) == -1) { | |||||
return (-1); | |||||
} | |||||
*mtu = ifr.ifr_mtu; | |||||
return (0); | |||||
} | |||||
int libifc_set_metric(libifc_handle_t *h, const char *name, const int mtu) | |||||
{ | |||||
struct ifreq ifr; | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
ifr.ifr_mtu = mtu; | |||||
if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFMETRIC, &ifr) < 0) { | |||||
return (-1); | |||||
} | |||||
return (0); | |||||
} | |||||
int libifc_get_metric(libifc_handle_t *h, const char *name, int *metric) | |||||
{ | |||||
struct ifreq ifr; | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, &ifr) == -1) { | |||||
return (-1); | |||||
} | |||||
*metric = ifr.ifr_metric; | |||||
return (0); | |||||
} | |||||
int libifc_set_capability(libifc_handle_t *h, const char *name, | |||||
const int capability) | |||||
{ | |||||
struct ifreq ifr; | |||||
struct libifc_capabilities ifcap; | |||||
int flags; | |||||
int value; | |||||
if (libifc_get_capability(h, name, &ifcap) != 0) { | |||||
return (-1); | |||||
} | |||||
value = capability; | |||||
flags = ifcap.curcap; | |||||
if (value < 0) { | |||||
value = -value; | |||||
flags &= ~value; | |||||
} else { | |||||
flags |= value; | |||||
} | |||||
flags &= ifcap.reqcap; | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
/* | |||||
* TODO: Verify that it's safe to not have ifr.ifr_curcap | |||||
* set for this request. | |||||
*/ | |||||
ifr.ifr_reqcap = flags; | |||||
if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFCAP, &ifr) < 0) { | |||||
return (-1); | |||||
} | |||||
return (0); | |||||
} | |||||
int libifc_get_capability(libifc_handle_t *h, const char *name, | |||||
struct libifc_capabilities *capability) | |||||
{ | |||||
struct ifreq ifr; | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCGIFCAP, &ifr) < 0) { | |||||
return (-1); | |||||
} | |||||
capability->curcap = ifr.ifr_curcap; | |||||
capability->reqcap = ifr.ifr_reqcap; | |||||
return (0); | |||||
} | |||||
int libifc_destroy_interface(libifc_handle_t *h, const char *name) | |||||
{ | |||||
struct ifreq ifr; | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, &ifr) < 0) { | |||||
return (-1); | |||||
} | |||||
return (0); | |||||
} | |||||
int libifc_create_interface(libifc_handle_t *h, const char *name, char **ifname) | |||||
{ | |||||
struct ifreq ifr; | |||||
(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); | |||||
/* | |||||
* TODO: | |||||
* Insert special snowflake handling here. See GitHub issue #12 for details. | |||||
* In the meantime, hard-nosupport interfaces that need special handling. | |||||
*/ | |||||
if ((strncmp(name, "wlan", strlen("wlan")) == 0) || | |||||
(strncmp(name, "vlan", strlen("vlan")) == 0) || | |||||
(strncmp(name, "vxlan", strlen("vxlan")) == 0)) { | |||||
h->error.errtype = OTHER; | |||||
h->error.errcode = ENOSYS; | |||||
return (-1); | |||||
} | |||||
/* No special handling for this interface type. */ | |||||
if (libifc_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) { | |||||
return (-1); | |||||
} | |||||
*ifname = strdup(ifr.ifr_name); | |||||
return (0); | |||||
} |
This will likely be easier to read if the conditions are inverted, i.e. check for error, not success.
Something like: