Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F143774401
D52027.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D52027.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D52027: libifconfig: Add netlink based link and address helper functions
Attached
Detach File
Event Timeline
Log In to Comment