Page MenuHomeFreeBSD

D52027.diff
No OneTemporary

D52027.diff

diff --git a/lib/libifconfig/Makefile b/lib/libifconfig/Makefile
--- a/lib/libifconfig/Makefile
+++ b/lib/libifconfig/Makefile
@@ -18,6 +18,7 @@
libifconfig_internal.c \
libifconfig_lagg.c \
libifconfig_media.c \
+ libifconfig_nl.c \
libifconfig_sfp.c
GEN= libifconfig_sfp_tables.h \
diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -382,3 +382,82 @@
* length of *lenp * IFNAMSIZ bytes.
*/
int ifconfig_list_cloners(ifconfig_handle_t *h, char **bufp, size_t *lenp);
+
+/** Brings the interface up
+ * @param h An open ifconfig state object
+ * @param ifname The interface name
+ * @return 0 on success, nonzero on failure.
+ * On failure, the error info on the handle is set.
+ */
+int ifconfig_if_up(ifconfig_handle_t *h, const char *ifname);
+
+/** Brings the interface down
+ * @param h An open ifconfig state object
+ * @param ifname The interface name
+ * @return 0 on success, nonzero on failure.
+ * On failure, the error info on the handle is set.
+ */
+int ifconfig_if_down(ifconfig_handle_t *h, const char *ifname);
+
+/** Adds an IPv4 address to an interface
+ * @param h An open ifconfig state object
+ * @param ifname The interface name
+ * @param addr The IPv4 address to be added
+ * @return 0 on success, nonzero on failure.
+ * On failure, the error info on the handle is set.
+ */
+int ifconfig_add_inet(ifconfig_handle_t *h, const char *ifname,
+ const struct ifconfig_inet_addr *addr);
+
+/** Delete an IPv4 address on an interface
+ * @param h An open ifconfig state object
+ * @param ifname The interface name
+ * @param addr The IPv4 address to be deleted
+ * @return 0 on success, nonzero on failure.
+ * On failure, the error info on the handle is set.
+ */
+int ifconfig_del_inet(ifconfig_handle_t *h, const char *ifname,
+ const struct ifconfig_inet_addr *addr);
+
+/** Adds an IPv6 address to an interface
+ * @param h An open ifconfig state object
+ * @param ifname The interface name
+ * @param addr The IPv6 address to be added.
+ * For non-P2P addresses,
+ * either only the dst field is set
+ * or both sin6 and dst fields are set to the same address.
+ * @return 0 on success, nonzero on failure.
+ * On failure, the error info on the handle is set.
+ */
+int ifconfig_add_inet6(ifconfig_handle_t *h, const char *ifname,
+ const struct ifconfig_inet6_addr *addr);
+
+/** Delete an IPv6 address on an interface
+ * @param h An open ifconfig state object
+ * @param ifname The interface name
+ * @param addr The IPv6 address to be deleted
+ * @return 0 on success, nonzero on failure.
+ * On failure, the error info on the handle is set.
+ */
+int ifconfig_del_inet6(ifconfig_handle_t *h, const char *ifname,
+ const struct ifconfig_inet6_addr *addr);
+
+/** Get MAC address of an interface
+ * @param h An open ifconfig state object
+ * @param ifname The interface name
+ * @param addr Return argument. It will be filled with the MAC address
+ * @return 0 on success, nonzero on failure.
+ * On failure, the error info on the handle is set.
+ */
+int ifconfig_get_mac(ifconfig_handle_t *h, const char *ifname,
+ struct ether_addr *addr);
+
+/** Set MAC address on an interface
+ * @param h An open ifconfig state object
+ * @param ifname The interface name
+ * @param addr The MAC address
+ * @return 0 on success, nonzero on failure.
+ * On failure, the error info on the handle is set.
+ */
+int ifconfig_set_mac(ifconfig_handle_t *h, const char *ifname,
+ const struct ether_addr *addr);
diff --git a/lib/libifconfig/libifconfig_inet.c b/lib/libifconfig/libifconfig_inet.c
--- a/lib/libifconfig/libifconfig_inet.c
+++ b/lib/libifconfig/libifconfig_inet.c
@@ -31,6 +31,10 @@
#include <net/if.h>
#include <netinet/in.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_route.h>
+#include <netlink/route/common.h>
+#include <netlink/route/ifaddrs.h>
#include <errno.h>
#include <ifaddrs.h>
@@ -42,6 +46,9 @@
static const struct sockaddr_in NULL_SIN;
+static int ifconfig_inet_exec_nl(ifconfig_handle_t *h, int action,
+ const char *ifname, const struct ifconfig_inet_addr *addr);
+
static int
inet_prefixlen(const struct in_addr *addr)
{
@@ -94,3 +101,85 @@
return (0);
}
+
+static int
+ifconfig_inet_exec_nl(ifconfig_handle_t *h, int action, const char *ifname,
+ const struct ifconfig_inet_addr *addr)
+{
+ int ret = 0, nested_offset = 0;
+ struct snl_state ss;
+ struct snl_writer nw = { 0 };
+ struct nlmsghdr *hdr;
+ struct ifaddrmsg *ifahdr;
+ struct snl_errmsg_data e = { 0 };
+
+ assert(addr != NULL);
+
+ if (!snl_init(&ss, NETLINK_ROUTE)) {
+ ifconfig_error(h, NETLINK, ENOTSUP);
+ return (-1);
+ }
+
+ snl_init_writer(&ss, &nw);
+ hdr = snl_create_msg_request(&nw, action);
+ ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
+
+ ifahdr->ifa_family = AF_INET;
+ ifahdr->ifa_prefixlen = addr->prefixlen;
+
+ ifahdr->ifa_index = if_nametoindex(ifname);
+ if (ifahdr->ifa_index == 0) {
+ ifconfig_error(h, OTHER, EADDRNOTAVAIL);
+ ret = -1;
+ goto out;
+ }
+
+ if (addr->sin != NULL)
+ snl_add_msg_attr_ip4(&nw, IFA_LOCAL, &addr->sin->sin_addr);
+ if (addr->dst != NULL)
+ snl_add_msg_attr_ip4(&nw, IFA_ADDRESS, &addr->dst->sin_addr);
+ if (addr->broadcast != NULL)
+ snl_add_msg_attr_ip4(&nw, IFA_BROADCAST,
+ &addr->broadcast->sin_addr);
+
+ nested_offset = snl_add_msg_attr_nested(&nw, IFA_FREEBSD);
+ if (addr->vhid != 0)
+ snl_add_msg_attr_u32(&nw, IFAF_VHID, addr->vhid);
+ snl_end_attr_nested(&nw, nested_offset);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL) {
+ ifconfig_error(h, NETLINK, ENOMEM);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_send_message(&ss, hdr)) {
+ ifconfig_error(h, NETLINK, EIO);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_read_reply_code(&ss, hdr->nlmsg_seq, &e)) {
+ ifconfig_error(h, NETLINK, e.error);
+ ret = -1;
+ goto out;
+ }
+
+out:
+ snl_free(&ss);
+ return (ret);
+}
+
+int
+ifconfig_add_inet(ifconfig_handle_t *h, const char *ifname,
+ const struct ifconfig_inet_addr *addr)
+{
+ return (ifconfig_inet_exec_nl(h, NL_RTM_NEWADDR, ifname, addr));
+}
+
+int
+ifconfig_del_inet(ifconfig_handle_t *h, const char *ifname,
+ const struct ifconfig_inet_addr *addr)
+{
+ return (ifconfig_inet_exec_nl(h, NL_RTM_DELADDR, ifname, addr));
+}
diff --git a/lib/libifconfig/libifconfig_inet6.c b/lib/libifconfig/libifconfig_inet6.c
--- a/lib/libifconfig/libifconfig_inet6.c
+++ b/lib/libifconfig/libifconfig_inet6.c
@@ -31,6 +31,10 @@
#include <net/if.h>
#include <netinet/in.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_route.h>
+#include <netlink/route/common.h>
+#include <netlink/route/ifaddrs.h>
#include <errno.h>
#include <ifaddrs.h>
@@ -40,6 +44,8 @@
#include "libifconfig.h"
#include "libifconfig_internal.h"
+static int ifconfig_inet6_exec_nl(ifconfig_handle_t *h, int action,
+ const char *ifname, const struct ifconfig_inet6_addr *addr);
static int
inet6_prefixlen(struct in6_addr *addr)
@@ -101,3 +107,89 @@
return (0);
}
+
+static int
+ifconfig_inet6_exec_nl(ifconfig_handle_t *h, int action, const char *ifname,
+ const struct ifconfig_inet6_addr *addr)
+{
+ int ret = 0, nested_offset = 0;
+ struct snl_state ss;
+ struct snl_writer nw = { 0 };
+ struct nlmsghdr *hdr;
+ struct ifaddrmsg *ifahdr;
+ struct ifa_cacheinfo ci = { 0 };
+ struct snl_errmsg_data e = { 0 };
+
+ assert(addr != NULL);
+
+ if (!snl_init(&ss, NETLINK_ROUTE)) {
+ ifconfig_error(h, NETLINK, ENOTSUP);
+ return (-1);
+ }
+
+ snl_init_writer(&ss, &nw);
+ hdr = snl_create_msg_request(&nw, action);
+ ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
+
+ ifahdr->ifa_family = AF_INET6;
+ ifahdr->ifa_prefixlen = addr->prefixlen;
+
+ ifahdr->ifa_index = if_nametoindex(ifname);
+ if (ifahdr->ifa_index == 0) {
+ ifconfig_error(h, OTHER, EADDRNOTAVAIL);
+ ret = -1;
+ goto out;
+ }
+
+ if (addr->sin6 != NULL)
+ snl_add_msg_attr_ip6(&nw, IFA_LOCAL, &addr->sin6->sin6_addr);
+ if (addr->dstin6 != NULL)
+ snl_add_msg_attr_ip6(&nw, IFA_ADDRESS,
+ &addr->dstin6->sin6_addr);
+
+ ci.ifa_prefered = addr->lifetime.ia6t_pltime;
+ ci.ifa_valid = addr->lifetime.ia6t_vltime;
+ snl_add_msg_attr(&nw, IFA_CACHEINFO, sizeof(ci), &ci);
+
+ nested_offset = snl_add_msg_attr_nested(&nw, IFA_FREEBSD);
+ snl_add_msg_attr_u32(&nw, IFAF_FLAGS, addr->flags);
+ if (addr->vhid != 0)
+ snl_add_msg_attr_u32(&nw, IFAF_VHID, addr->vhid);
+ snl_end_attr_nested(&nw, nested_offset);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL) {
+ ifconfig_error(h, NETLINK, ENOMEM);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_send_message(&ss, hdr)) {
+ ifconfig_error(h, NETLINK, EIO);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_read_reply_code(&ss, hdr->nlmsg_seq, &e)) {
+ ifconfig_error(h, NETLINK, e.error);
+ ret = -1;
+ goto out;
+ }
+
+out:
+ snl_free(&ss);
+ return (ret);
+}
+
+int
+ifconfig_add_inet6(ifconfig_handle_t *h, const char *ifname,
+ const struct ifconfig_inet6_addr *addr)
+{
+ return (ifconfig_inet6_exec_nl(h, NL_RTM_NEWADDR, ifname, addr));
+}
+
+int
+ifconfig_del_inet6(ifconfig_handle_t *h, const char *ifname,
+ const struct ifconfig_inet6_addr *addr)
+{
+ return (ifconfig_inet6_exec_nl(h, NL_RTM_DELADDR, ifname, addr));
+}
diff --git a/lib/libifconfig/libifconfig_nl.c b/lib/libifconfig/libifconfig_nl.c
new file mode 100644
--- /dev/null
+++ b/lib/libifconfig/libifconfig_nl.c
@@ -0,0 +1,218 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025, Muhammad Saheed <saheed@FreeBSD.org>
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netlink/netlink.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_route_parsers.h>
+#include <netlink/route/common.h>
+#include <netlink/route/interface.h>
+
+#include <errno.h>
+
+#include "libifconfig.h"
+#include "libifconfig_internal.h"
+
+static int ifconfig_modify_flags(ifconfig_handle_t *h, const char *ifname,
+ int ifi_flags, int ifi_change);
+
+static int
+ifconfig_modify_flags(ifconfig_handle_t *h, const char *ifname, int ifi_flags,
+ int ifi_change)
+{
+ int ret = 0;
+ struct snl_state ss;
+ struct snl_writer nw;
+ struct nlmsghdr *hdr;
+ struct ifinfomsg *ifi;
+ struct snl_errmsg_data e = { 0 };
+
+ if (!snl_init(&ss, NETLINK_ROUTE)) {
+ ifconfig_error(h, NETLINK, ENOTSUP);
+ return (-1);
+ }
+
+ snl_init_writer(&ss, &nw);
+ hdr = snl_create_msg_request(&nw, NL_RTM_NEWLINK);
+ ifi = snl_reserve_msg_object(&nw, struct ifinfomsg);
+ snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifname);
+
+ ifi->ifi_flags = ifi_flags;
+ ifi->ifi_change = ifi_change;
+
+ hdr = snl_finalize_msg(&nw);
+ if (hdr == NULL) {
+ ifconfig_error(h, NETLINK, ENOMEM);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_send_message(&ss, hdr)) {
+ ifconfig_error(h, NETLINK, EIO);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_read_reply_code(&ss, hdr->nlmsg_seq, &e)) {
+ ifconfig_error(h, NETLINK, e.error);
+ ret = -1;
+ goto out;
+ }
+
+out:
+ snl_free(&ss);
+ return (ret);
+}
+
+int
+ifconfig_if_up(ifconfig_handle_t *h, const char *ifname)
+{
+ return (ifconfig_modify_flags(h, ifname, IFF_UP, IFF_UP));
+}
+
+int
+ifconfig_if_down(ifconfig_handle_t *h, const char *ifname)
+{
+ return (ifconfig_modify_flags(h, ifname, ~IFF_UP, IFF_UP));
+}
+
+int
+ifconfig_get_mac(ifconfig_handle_t *h, const char *ifname,
+ struct ether_addr *addr)
+{
+ int ret = 0;
+ uint32_t nlmsg_seq = 0;
+ struct snl_state ss;
+ struct snl_writer nw = { 0 };
+ struct nlmsghdr *hdr;
+ struct snl_parsed_link link = { 0 };
+ struct snl_errmsg_data e = { 0 };
+
+ assert(addr != NULL);
+
+ if (!snl_init(&ss, NETLINK_ROUTE)) {
+ ifconfig_error(h, NETLINK, ENOTSUP);
+ return (-1);
+ }
+
+ snl_init_writer(&ss, &nw);
+ hdr = snl_create_msg_request(&nw, RTM_GETLINK);
+ (void)snl_reserve_msg_object(&nw, struct ifinfomsg);
+
+ snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifname);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL) {
+ ifconfig_error(h, NETLINK, ENOMEM);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_send_message(&ss, hdr)) {
+ ifconfig_error(h, NETLINK, EIO);
+ ret = -1;
+ goto out;
+ }
+
+ nlmsg_seq = hdr->nlmsg_seq;
+ while ((hdr = snl_read_reply_multi(&ss, nlmsg_seq, &e)) != NULL) {
+ if (!snl_parse_nlmsg(&ss, hdr, &snl_rtm_link_parser, &link))
+ continue;
+
+ if (link.ifla_address != NULL &&
+ NLA_DATA_LEN(link.ifla_address) == ETHER_ADDR_LEN) {
+ memcpy(addr, NLA_DATA(link.ifla_address),
+ ETHER_ADDR_LEN);
+ goto out;
+ }
+ }
+ ifconfig_error(h, NETLINK, ENOENT);
+ ret = -1;
+
+out:
+ snl_free(&ss);
+ return (ret);
+}
+
+int
+ifconfig_set_mac(ifconfig_handle_t *h, const char *ifname,
+ const struct ether_addr *addr)
+{
+ int ret = 0;
+ struct snl_state ss;
+ struct snl_writer nw = { 0 };
+ struct nlmsghdr *hdr;
+ struct ifinfomsg *ifi;
+ struct snl_errmsg_data e = { 0 };
+
+ assert(addr != NULL);
+
+ if (!snl_init(&ss, NETLINK_ROUTE)) {
+ ifconfig_error(h, NETLINK, ENOTSUP);
+ return (-1);
+ }
+
+ snl_init_writer(&ss, &nw);
+ hdr = snl_create_msg_request(&nw, RTM_NEWLINK);
+ ifi = snl_reserve_msg_object(&nw, struct ifinfomsg);
+
+ ifi->ifi_type = ARPHRD_ETHER;
+ ifi->ifi_family = AF_UNSPEC;
+
+ ifi->ifi_index = if_nametoindex(ifname);
+ if (ifi->ifi_index == 0) {
+ ifconfig_error(h, OTHER, EADDRNOTAVAIL);
+ ret = -1;
+ goto out;
+ }
+
+ snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifname);
+ snl_add_msg_attr(&nw, IFLA_ADDRESS, ETHER_ADDR_LEN, addr);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL) {
+ ifconfig_error(h, NETLINK, ENOMEM);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_send_message(&ss, hdr)) {
+ ifconfig_error(h, NETLINK, EIO);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_read_reply_code(&ss, hdr->nlmsg_seq, &e)) {
+ ifconfig_error(h, NETLINK, e.error);
+ ret = -1;
+ goto out;
+ }
+
+out:
+ snl_free(&ss);
+ return (ret);
+}

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 1, 12:30 PM (52 m, 21 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28366335
Default Alt Text
D52027.diff (14 KB)

Event Timeline