Changeset View
Changeset View
Standalone View
Standalone View
sys/netlink/route/iface.c
Show First 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
struct if_state { | struct if_state { | ||||
uint8_t ifla_operstate; | uint8_t ifla_operstate; | ||||
uint8_t ifla_carrier; | uint8_t ifla_carrier; | ||||
}; | }; | ||||
static void | static void | ||||
get_operstate_ether(struct ifnet *ifp, struct if_state *pstate) | get_operstate_ether(if_t ifp, struct if_state *pstate) | ||||
{ | { | ||||
struct ifmediareq ifmr = {}; | struct ifmediareq ifmr = {}; | ||||
int error; | int error; | ||||
error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (void *)&ifmr); | error = if_ioctl(ifp, SIOCGIFMEDIA, (void *)&ifmr); | ||||
if (error != 0) { | if (error != 0) { | ||||
NL_LOG(LOG_DEBUG, "error calling SIOCGIFMEDIA on %s: %d", | NL_LOG(LOG_DEBUG, "error calling SIOCGIFMEDIA on %s: %d", | ||||
if_name(ifp), error); | if_name(ifp), error); | ||||
return; | return; | ||||
} | } | ||||
switch (IFM_TYPE(ifmr.ifm_active)) { | switch (IFM_TYPE(ifmr.ifm_active)) { | ||||
case IFM_ETHER: | case IFM_ETHER: | ||||
if (ifmr.ifm_status & IFM_ACTIVE) { | if (ifmr.ifm_status & IFM_ACTIVE) { | ||||
pstate->ifla_carrier = 1; | pstate->ifla_carrier = 1; | ||||
if (ifp->if_flags & IFF_MONITOR) | if (if_getflags(ifp) & IFF_MONITOR) | ||||
pstate->ifla_operstate = IF_OPER_DORMANT; | pstate->ifla_operstate = IF_OPER_DORMANT; | ||||
else | else | ||||
pstate->ifla_operstate = IF_OPER_UP; | pstate->ifla_operstate = IF_OPER_UP; | ||||
} else | } else | ||||
pstate->ifla_operstate = IF_OPER_DOWN; | pstate->ifla_operstate = IF_OPER_DOWN; | ||||
} | } | ||||
} | } | ||||
static bool | static bool | ||||
get_stats(struct nl_writer *nw, struct ifnet *ifp) | get_stats(struct nl_writer *nw, if_t ifp) | ||||
{ | { | ||||
struct rtnl_link_stats64 *stats; | struct rtnl_link_stats64 *stats; | ||||
int nla_len = sizeof(struct nlattr) + sizeof(*stats); | int nla_len = sizeof(struct nlattr) + sizeof(*stats); | ||||
struct nlattr *nla = nlmsg_reserve_data(nw, nla_len, struct nlattr); | struct nlattr *nla = nlmsg_reserve_data(nw, nla_len, struct nlattr); | ||||
if (nla == NULL) | if (nla == NULL) | ||||
return (false); | return (false); | ||||
nla->nla_type = IFLA_STATS64; | nla->nla_type = IFLA_STATS64; | ||||
nla->nla_len = nla_len; | nla->nla_len = nla_len; | ||||
stats = (struct rtnl_link_stats64 *)(nla + 1); | stats = (struct rtnl_link_stats64 *)(nla + 1); | ||||
stats->rx_packets = ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS); | stats->rx_packets = if_getcounter(ifp, IFCOUNTER_IPACKETS); | ||||
stats->tx_packets = ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS); | stats->tx_packets = if_getcounter(ifp, IFCOUNTER_OPACKETS); | ||||
stats->rx_bytes = ifp->if_get_counter(ifp, IFCOUNTER_IBYTES); | stats->rx_bytes = if_getcounter(ifp, IFCOUNTER_IBYTES); | ||||
stats->tx_bytes = ifp->if_get_counter(ifp, IFCOUNTER_OBYTES); | stats->tx_bytes = if_getcounter(ifp, IFCOUNTER_OBYTES); | ||||
stats->rx_errors = ifp->if_get_counter(ifp, IFCOUNTER_IERRORS); | stats->rx_errors = if_getcounter(ifp, IFCOUNTER_IERRORS); | ||||
stats->tx_errors = ifp->if_get_counter(ifp, IFCOUNTER_OERRORS); | stats->tx_errors = if_getcounter(ifp, IFCOUNTER_OERRORS); | ||||
stats->rx_dropped = ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS); | stats->rx_dropped = if_getcounter(ifp, IFCOUNTER_IQDROPS); | ||||
stats->tx_dropped = ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS); | stats->tx_dropped = if_getcounter(ifp, IFCOUNTER_OQDROPS); | ||||
stats->multicast = ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS); | stats->multicast = if_getcounter(ifp, IFCOUNTER_IMCASTS); | ||||
stats->rx_nohandler = ifp->if_get_counter(ifp, IFCOUNTER_NOPROTO); | stats->rx_nohandler = if_getcounter(ifp, IFCOUNTER_NOPROTO); | ||||
return (true); | return (true); | ||||
} | } | ||||
static void | static void | ||||
get_operstate(struct ifnet *ifp, struct if_state *pstate) | get_operstate(if_t ifp, struct if_state *pstate) | ||||
{ | { | ||||
pstate->ifla_operstate = IF_OPER_UNKNOWN; | pstate->ifla_operstate = IF_OPER_UNKNOWN; | ||||
pstate->ifla_carrier = 0; /* no carrier */ | pstate->ifla_carrier = 0; /* no carrier */ | ||||
switch (ifp->if_type) { | switch (if_gettype(ifp)) { | ||||
case IFT_ETHER: | case IFT_ETHER: | ||||
case IFT_L2VLAN: | case IFT_L2VLAN: | ||||
get_operstate_ether(ifp, pstate); | get_operstate_ether(ifp, pstate); | ||||
break; | break; | ||||
default: | default: | ||||
/* Map admin state to the operstate */ | /* Map admin state to the operstate */ | ||||
if (ifp->if_flags & IFF_UP) { | if (if_getflags(ifp) & IFF_UP) { | ||||
pstate->ifla_operstate = IF_OPER_UP; | pstate->ifla_operstate = IF_OPER_UP; | ||||
pstate->ifla_carrier = 1; | pstate->ifla_carrier = 1; | ||||
} else | } else | ||||
pstate->ifla_operstate = IF_OPER_DOWN; | pstate->ifla_operstate = IF_OPER_DOWN; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
get_hwaddr(struct nl_writer *nw, struct ifnet *ifp) | get_hwaddr(struct nl_writer *nw, if_t ifp) | ||||
{ | { | ||||
struct ifreq ifr = {}; | struct ifreq ifr = {}; | ||||
if (if_gethwaddr(ifp, &ifr) == 0) { | if (if_gethwaddr(ifp, &ifr) == 0) { | ||||
nlattr_add(nw, IFLAF_ORIG_HWADDR, if_getaddrlen(ifp), | nlattr_add(nw, IFLAF_ORIG_HWADDR, if_getaddrlen(ifp), | ||||
ifr.ifr_addr.sa_data); | ifr.ifr_addr.sa_data); | ||||
} | } | ||||
} | } | ||||
static unsigned | static unsigned | ||||
ifp_flags_to_netlink(const struct ifnet *ifp) | ifp_flags_to_netlink(const if_t ifp) | ||||
{ | { | ||||
return (ifp->if_flags | ifp->if_drv_flags); | return (if_getflags(ifp) | if_getdrvflags(ifp)); | ||||
} | } | ||||
#define LLADDR_CONST(s) ((const void *)((s)->sdl_data + (s)->sdl_nlen)) | #define LLADDR_CONST(s) ((const void *)((s)->sdl_data + (s)->sdl_nlen)) | ||||
static bool | static bool | ||||
dump_sa(struct nl_writer *nw, int attr, const struct sockaddr *sa) | dump_sa(struct nl_writer *nw, int attr, const struct sockaddr *sa) | ||||
{ | { | ||||
uint32_t addr_len = 0; | uint32_t addr_len = 0; | ||||
const void *addr_data = NULL; | const void *addr_data = NULL; | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
* @nw: message writer | * @nw: message writer | ||||
* @ifp: target interface | * @ifp: target interface | ||||
* @hdr: template header | * @hdr: template header | ||||
* @if_flags_mask: changed if_[drv]_flags bitmask | * @if_flags_mask: changed if_[drv]_flags bitmask | ||||
* | * | ||||
* This function is called without epoch and MAY sleep. | * This function is called without epoch and MAY sleep. | ||||
*/ | */ | ||||
static bool | static bool | ||||
dump_iface(struct nl_writer *nw, struct ifnet *ifp, const struct nlmsghdr *hdr, | dump_iface(struct nl_writer *nw, if_t ifp, const struct nlmsghdr *hdr, | ||||
int if_flags_mask) | int if_flags_mask) | ||||
{ | { | ||||
struct ifinfomsg *ifinfo; | struct ifinfomsg *ifinfo; | ||||
NL_LOG(LOG_DEBUG3, "dumping interface %s data", if_name(ifp)); | NL_LOG(LOG_DEBUG3, "dumping interface %s data", if_name(ifp)); | ||||
if (!nlmsg_reply(nw, hdr, sizeof(struct ifinfomsg))) | if (!nlmsg_reply(nw, hdr, sizeof(struct ifinfomsg))) | ||||
goto enomem; | goto enomem; | ||||
ifinfo = nlmsg_reserve_object(nw, struct ifinfomsg); | ifinfo = nlmsg_reserve_object(nw, struct ifinfomsg); | ||||
ifinfo->ifi_family = AF_UNSPEC; | ifinfo->ifi_family = AF_UNSPEC; | ||||
ifinfo->__ifi_pad = 0; | ifinfo->__ifi_pad = 0; | ||||
ifinfo->ifi_type = ifp->if_type; | ifinfo->ifi_type = if_gettype(ifp); | ||||
ifinfo->ifi_index = ifp->if_index; | ifinfo->ifi_index = if_getindex(ifp); | ||||
ifinfo->ifi_flags = ifp_flags_to_netlink(ifp); | ifinfo->ifi_flags = ifp_flags_to_netlink(ifp); | ||||
ifinfo->ifi_change = if_flags_mask; | ifinfo->ifi_change = if_flags_mask; | ||||
struct if_state ifs = {}; | struct if_state ifs = {}; | ||||
get_operstate(ifp, &ifs); | get_operstate(ifp, &ifs); | ||||
if (ifs.ifla_operstate == IF_OPER_UP) | if (ifs.ifla_operstate == IF_OPER_UP) | ||||
ifinfo->ifi_flags |= IFF_LOWER_UP; | ifinfo->ifi_flags |= IFF_LOWER_UP; | ||||
nlattr_add_string(nw, IFLA_IFNAME, if_name(ifp)); | nlattr_add_string(nw, IFLA_IFNAME, if_name(ifp)); | ||||
nlattr_add_u8(nw, IFLA_OPERSTATE, ifs.ifla_operstate); | nlattr_add_u8(nw, IFLA_OPERSTATE, ifs.ifla_operstate); | ||||
nlattr_add_u8(nw, IFLA_CARRIER, ifs.ifla_carrier); | nlattr_add_u8(nw, IFLA_CARRIER, ifs.ifla_carrier); | ||||
/* | /* | ||||
nlattr_add_u8(nw, IFLA_PROTO_DOWN, val); | nlattr_add_u8(nw, IFLA_PROTO_DOWN, val); | ||||
nlattr_add_u8(nw, IFLA_LINKMODE, val); | nlattr_add_u8(nw, IFLA_LINKMODE, val); | ||||
*/ | */ | ||||
if (if_getaddrlen(ifp) != 0) { | if (if_getaddrlen(ifp) != 0) { | ||||
struct ifaddr *ifa = if_getifaddr(ifp); | struct ifaddr *ifa = if_getifaddr(ifp); | ||||
dump_sa(nw, IFLA_ADDRESS, ifa->ifa_addr); | dump_sa(nw, IFLA_ADDRESS, ifa->ifa_addr); | ||||
} | } | ||||
if ((ifp->if_broadcastaddr != NULL)) { | if ((if_getbroadcastaddr(ifp) != NULL)) { | ||||
nlattr_add(nw, IFLA_BROADCAST, ifp->if_addrlen, | nlattr_add(nw, IFLA_BROADCAST, if_getaddrlen(ifp), | ||||
ifp->if_broadcastaddr); | if_getbroadcastaddr(ifp)); | ||||
} | } | ||||
nlattr_add_u32(nw, IFLA_MTU, ifp->if_mtu); | nlattr_add_u32(nw, IFLA_MTU, if_getmtu(ifp)); | ||||
/* | /* | ||||
nlattr_add_u32(nw, IFLA_MIN_MTU, 60); | nlattr_add_u32(nw, IFLA_MIN_MTU, 60); | ||||
nlattr_add_u32(nw, IFLA_MAX_MTU, 9000); | nlattr_add_u32(nw, IFLA_MAX_MTU, 9000); | ||||
nlattr_add_u32(nw, IFLA_GROUP, 0); | nlattr_add_u32(nw, IFLA_GROUP, 0); | ||||
*/ | */ | ||||
if (ifp->if_description != NULL) | if (if_getdescr(ifp) != NULL) | ||||
nlattr_add_string(nw, IFLA_IFALIAS, ifp->if_description); | nlattr_add_string(nw, IFLA_IFALIAS, if_getdescr(ifp)); | ||||
/* Store FreeBSD-specific attributes */ | /* Store FreeBSD-specific attributes */ | ||||
int off = nlattr_add_nested(nw, IFLA_FREEBSD); | int off = nlattr_add_nested(nw, IFLA_FREEBSD); | ||||
if (off != 0) { | if (off != 0) { | ||||
get_hwaddr(nw, ifp); | get_hwaddr(nw, ifp); | ||||
dump_iface_caps(nw, ifp); | dump_iface_caps(nw, ifp); | ||||
nlattr_set_len(nw, off); | nlattr_set_len(nw, off); | ||||
} | } | ||||
get_stats(nw, ifp); | get_stats(nw, ifp); | ||||
uint32_t val = (ifp->if_flags & IFF_PROMISC) != 0; | uint32_t val = (if_getflags(ifp) & IFF_PROMISC) != 0; | ||||
nlattr_add_u32(nw, IFLA_PROMISCUITY, val); | nlattr_add_u32(nw, IFLA_PROMISCUITY, val); | ||||
ifc_dump_ifp_nl(ifp, nw); | ifc_dump_ifp_nl(ifp, nw); | ||||
if (nlmsg_end(nw)) | if (nlmsg_end(nw)) | ||||
return (true); | return (true); | ||||
enomem: | enomem: | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | static const struct nlattr_parser nla_p_if[] = { | ||||
{ .type = IFLA_GROUP, .off = _OUT(ifla_group), .cb = nlattr_get_string }, | { .type = IFLA_GROUP, .off = _OUT(ifla_group), .cb = nlattr_get_string }, | ||||
{ .type = IFLA_ALT_IFNAME, .off = _OUT(ifla_ifname), .cb = nlattr_get_string }, | { .type = IFLA_ALT_IFNAME, .off = _OUT(ifla_ifname), .cb = nlattr_get_string }, | ||||
}; | }; | ||||
#undef _IN | #undef _IN | ||||
#undef _OUT | #undef _OUT | ||||
NL_DECLARE_STRICT_PARSER(ifmsg_parser, struct ifinfomsg, check_ifmsg, nlf_p_if, nla_p_if); | NL_DECLARE_STRICT_PARSER(ifmsg_parser, struct ifinfomsg, check_ifmsg, nlf_p_if, nla_p_if); | ||||
static bool | static bool | ||||
match_iface(struct ifnet *ifp, void *_arg) | match_iface(if_t ifp, void *_arg) | ||||
{ | { | ||||
struct nl_parsed_link *attrs = (struct nl_parsed_link *)_arg; | struct nl_parsed_link *attrs = (struct nl_parsed_link *)_arg; | ||||
if (attrs->ifi_index != 0 && attrs->ifi_index != ifp->if_index) | if (attrs->ifi_index != 0 && attrs->ifi_index != if_getindex(ifp)) | ||||
return (false); | return (false); | ||||
if (attrs->ifi_type != 0 && attrs->ifi_index != ifp->if_type) | if (attrs->ifi_type != 0 && attrs->ifi_index != if_gettype(ifp)) | ||||
return (false); | return (false); | ||||
if (attrs->ifla_ifname != NULL && strcmp(attrs->ifla_ifname, if_name(ifp))) | if (attrs->ifla_ifname != NULL && strcmp(attrs->ifla_ifname, if_name(ifp))) | ||||
return (false); | return (false); | ||||
/* TODO: add group match */ | /* TODO: add group match */ | ||||
return (true); | return (true); | ||||
} | } | ||||
static int | static int | ||||
dump_cb(struct ifnet *ifp, void *_arg) | dump_cb(if_t ifp, void *_arg) | ||||
{ | { | ||||
struct netlink_walkargs *wa = (struct netlink_walkargs *)_arg; | struct netlink_walkargs *wa = (struct netlink_walkargs *)_arg; | ||||
if (!dump_iface(wa->nw, ifp, &wa->hdr, 0)) | if (!dump_iface(wa->nw, ifp, &wa->hdr, 0)) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* {nlmsg_len=52, nlmsg_type=RTM_GETLINK, nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=1662842818, nlmsg_pid=0}, | * {nlmsg_len=52, nlmsg_type=RTM_GETLINK, nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=1662842818, nlmsg_pid=0}, | ||||
* {ifi_family=AF_PACKET, ifi_type=ARPHRD_NETROM, ifi_index=0, ifi_flags=0, ifi_change=0}, | * {ifi_family=AF_PACKET, ifi_type=ARPHRD_NETROM, ifi_index=0, ifi_flags=0, ifi_change=0}, | ||||
* [ | * [ | ||||
* [{nla_len=10, nla_type=IFLA_IFNAME}, "vnet9"], | * [{nla_len=10, nla_type=IFLA_IFNAME}, "vnet9"], | ||||
* [{nla_len=8, nla_type=IFLA_EXT_MASK}, RTEXT_FILTER_VF] | * [{nla_len=8, nla_type=IFLA_EXT_MASK}, RTEXT_FILTER_VF] | ||||
* ] | * ] | ||||
*/ | */ | ||||
static int | static int | ||||
rtnl_handle_getlink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) | rtnl_handle_getlink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
int error = 0; | int error = 0; | ||||
struct nl_parsed_link attrs = {}; | struct nl_parsed_link attrs = {}; | ||||
error = nl_parse_nlmsg(hdr, &ifmsg_parser, npt, &attrs); | error = nl_parse_nlmsg(hdr, &ifmsg_parser, npt, &attrs); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
struct netlink_walkargs wa = { | struct netlink_walkargs wa = { | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | |||||
* ] | * ] | ||||
* ] | * ] | ||||
*/ | */ | ||||
static int | static int | ||||
rtnl_handle_dellink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) | rtnl_handle_dellink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct ifnet *ifp; | if_t ifp; | ||||
int error; | int error; | ||||
struct nl_parsed_link attrs = {}; | struct nl_parsed_link attrs = {}; | ||||
error = nl_parse_nlmsg(hdr, &ifmsg_parser, npt, &attrs); | error = nl_parse_nlmsg(hdr, &ifmsg_parser, npt, &attrs); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | create_link(struct nlmsghdr *hdr, struct nl_parsed_link *lattrs, | ||||
return (ifd.error); | return (ifd.error); | ||||
} | } | ||||
static int | static int | ||||
modify_link(struct nlmsghdr *hdr, struct nl_parsed_link *lattrs, | modify_link(struct nlmsghdr *hdr, struct nl_parsed_link *lattrs, | ||||
struct nlattr_bmask *bm, struct nlpcb *nlp, struct nl_pstate *npt) | struct nlattr_bmask *bm, struct nlpcb *nlp, struct nl_pstate *npt) | ||||
{ | { | ||||
struct ifnet *ifp = NULL; | if_t ifp = NULL; | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
if (lattrs->ifi_index == 0 && lattrs->ifla_ifname == NULL) { | if (lattrs->ifi_index == 0 && lattrs->ifla_ifname == NULL) { | ||||
/* | /* | ||||
* Applications like ip(8) verify RTM_NEWLINK command | * Applications like ip(8) verify RTM_NEWLINK command | ||||
* existence by calling it with empty arguments. Always | * existence by calling it with empty arguments. Always | ||||
* return "innocent" error in that case. | * return "innocent" error in that case. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 322 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* {'attrs': [('IFA_ADDRESS', '12.0.0.1'), | * {'attrs': [('IFA_ADDRESS', '12.0.0.1'), | ||||
('IFA_LOCAL', '12.0.0.1'), | ('IFA_LOCAL', '12.0.0.1'), | ||||
('IFA_LABEL', 'eth10'), | ('IFA_LABEL', 'eth10'), | ||||
('IFA_FLAGS', 128), | ('IFA_FLAGS', 128), | ||||
('IFA_CACHEINFO', {'ifa_preferred': 4294967295, 'ifa_valid': 4294967295, 'cstamp': 63745746, 'tstamp': 63745746})], | ('IFA_CACHEINFO', {'ifa_preferred': 4294967295, 'ifa_valid': 4294967295, 'cstamp': 63745746, 'tstamp': 63745746})], | ||||
*/ | */ | ||||
static bool | static bool | ||||
dump_iface_addr(struct nl_writer *nw, struct ifnet *ifp, struct ifaddr *ifa, | dump_iface_addr(struct nl_writer *nw, if_t ifp, struct ifaddr *ifa, | ||||
const struct nlmsghdr *hdr) | const struct nlmsghdr *hdr) | ||||
{ | { | ||||
struct ifaddrmsg *ifamsg; | struct ifaddrmsg *ifamsg; | ||||
struct sockaddr *sa = ifa->ifa_addr; | struct sockaddr *sa = ifa->ifa_addr; | ||||
struct sockaddr *sa_dst = ifa->ifa_dstaddr; | struct sockaddr *sa_dst = ifa->ifa_dstaddr; | ||||
NL_LOG(LOG_DEBUG3, "dumping ifa %p type %s(%d) for interface %s", | NL_LOG(LOG_DEBUG3, "dumping ifa %p type %s(%d) for interface %s", | ||||
ifa, rib_print_family(sa->sa_family), sa->sa_family, if_name(ifp)); | ifa, rib_print_family(sa->sa_family), sa->sa_family, if_name(ifp)); | ||||
if (!nlmsg_reply(nw, hdr, sizeof(struct ifaddrmsg))) | if (!nlmsg_reply(nw, hdr, sizeof(struct ifaddrmsg))) | ||||
goto enomem; | goto enomem; | ||||
ifamsg = nlmsg_reserve_object(nw, struct ifaddrmsg); | ifamsg = nlmsg_reserve_object(nw, struct ifaddrmsg); | ||||
ifamsg->ifa_family = sa->sa_family; | ifamsg->ifa_family = sa->sa_family; | ||||
ifamsg->ifa_prefixlen = get_sa_plen(ifa->ifa_netmask); | ifamsg->ifa_prefixlen = get_sa_plen(ifa->ifa_netmask); | ||||
ifamsg->ifa_flags = 0; // ifa_flags is useless | ifamsg->ifa_flags = 0; // ifa_flags is useless | ||||
ifamsg->ifa_scope = ifa_get_scope(ifa); | ifamsg->ifa_scope = ifa_get_scope(ifa); | ||||
ifamsg->ifa_index = ifp->if_index; | ifamsg->ifa_index = if_getindex(ifp); | ||||
if ((ifp->if_flags & IFF_POINTOPOINT) && sa_dst != NULL && sa_dst->sa_family != 0) { | if ((if_getflags(ifp) & IFF_POINTOPOINT) && sa_dst != NULL && sa_dst->sa_family != 0) { | ||||
/* P2P interface may have IPv6 LL with no dst address */ | /* P2P interface may have IPv6 LL with no dst address */ | ||||
dump_sa(nw, IFA_ADDRESS, sa_dst); | dump_sa(nw, IFA_ADDRESS, sa_dst); | ||||
dump_sa(nw, IFA_LOCAL, sa); | dump_sa(nw, IFA_LOCAL, sa); | ||||
} else { | } else { | ||||
dump_sa(nw, IFA_ADDRESS, sa); | dump_sa(nw, IFA_ADDRESS, sa); | ||||
#ifdef INET | #ifdef INET | ||||
/* | /* | ||||
* In most cases, IFA_ADDRESS == IFA_LOCAL | * In most cases, IFA_ADDRESS == IFA_LOCAL | ||||
* Skip IFA_LOCAL for anything except INET | * Skip IFA_LOCAL for anything except INET | ||||
*/ | */ | ||||
if (sa->sa_family == AF_INET) | if (sa->sa_family == AF_INET) | ||||
dump_sa(nw, IFA_LOCAL, sa); | dump_sa(nw, IFA_LOCAL, sa); | ||||
#endif | #endif | ||||
} | } | ||||
if (ifp->if_flags & IFF_BROADCAST) | if (if_getflags(ifp) & IFF_BROADCAST) | ||||
dump_sa(nw, IFA_BROADCAST, ifa->ifa_broadaddr); | dump_sa(nw, IFA_BROADCAST, ifa->ifa_broadaddr); | ||||
nlattr_add_string(nw, IFA_LABEL, if_name(ifp)); | nlattr_add_string(nw, IFA_LABEL, if_name(ifp)); | ||||
uint32_t nl_ifa_flags = 0; | uint32_t nl_ifa_flags = 0; | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (sa->sa_family == AF_INET6) { | if (sa->sa_family == AF_INET6) { | ||||
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; | struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa; | ||||
Show All 27 Lines | |||||
enomem: | enomem: | ||||
NL_LOG(LOG_DEBUG, "Failed to dump ifa type %s(%d) for interface %s", | NL_LOG(LOG_DEBUG, "Failed to dump ifa type %s(%d) for interface %s", | ||||
rib_print_family(sa->sa_family), sa->sa_family, if_name(ifp)); | rib_print_family(sa->sa_family), sa->sa_family, if_name(ifp)); | ||||
nlmsg_abort(nw); | nlmsg_abort(nw); | ||||
return (false); | return (false); | ||||
} | } | ||||
static int | static int | ||||
dump_iface_addrs(struct netlink_walkargs *wa, struct ifnet *ifp) | dump_iface_addrs(struct netlink_walkargs *wa, if_t ifp) | ||||
{ | { | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct ifa_iter it; | |||||
int error = 0; | |||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | for (ifa = ifa_iter_start(ifp, &it); ifa != NULL; ifa = ifa_iter_next(&it)) { | ||||
if (wa->family != 0 && wa->family != ifa->ifa_addr->sa_family) | if (wa->family != 0 && wa->family != ifa->ifa_addr->sa_family) | ||||
continue; | continue; | ||||
if (ifa->ifa_addr->sa_family == AF_LINK) | if (ifa->ifa_addr->sa_family == AF_LINK) | ||||
continue; | continue; | ||||
if (prison_if(wa->cred, ifa->ifa_addr) != 0) | if (prison_if(wa->cred, ifa->ifa_addr) != 0) | ||||
continue; | continue; | ||||
wa->count++; | wa->count++; | ||||
if (!dump_iface_addr(wa->nw, ifp, ifa, &wa->hdr)) | if (!dump_iface_addr(wa->nw, ifp, ifa, &wa->hdr)) { | ||||
return (ENOMEM); | error = ENOMEM; | ||||
break; | |||||
} | |||||
wa->dumped++; | wa->dumped++; | ||||
} | } | ||||
ifa_iter_finish(&it); | |||||
return (0); | return (error); | ||||
} | } | ||||
static int | static int | ||||
rtnl_handle_getaddr(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) | rtnl_handle_getaddr(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) | ||||
{ | { | ||||
struct ifnet *ifp; | if_t ifp; | ||||
int error = 0; | int error = 0; | ||||
struct nl_parsed_ifa attrs = {}; | struct nl_parsed_ifa attrs = {}; | ||||
error = nl_parse_nlmsg(hdr, &ifa_parser, npt, &attrs); | error = nl_parse_nlmsg(hdr, &ifa_parser, npt, &attrs); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
struct netlink_walkargs wa = { | struct netlink_walkargs wa = { | ||||
Show All 11 Lines | rtnl_handle_getaddr(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) | ||||
if (attrs.ifa_index != 0) { | if (attrs.ifa_index != 0) { | ||||
ifp = ifnet_byindex(attrs.ifa_index); | ifp = ifnet_byindex(attrs.ifa_index); | ||||
if (ifp == NULL) | if (ifp == NULL) | ||||
error = ENOENT; | error = ENOENT; | ||||
else | else | ||||
error = dump_iface_addrs(&wa, ifp); | error = dump_iface_addrs(&wa, ifp); | ||||
} else { | } else { | ||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { | struct if_iter it; | ||||
for (ifp = if_iter_start(&it); ifp != NULL; ifp = if_iter_next(&it)) { | |||||
error = dump_iface_addrs(&wa, ifp); | error = dump_iface_addrs(&wa, ifp); | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
} | } | ||||
if_iter_finish(&it); | |||||
} | } | ||||
NL_LOG(LOG_DEBUG2, "End dump, iterated %d dumped %d", wa.count, wa.dumped); | NL_LOG(LOG_DEBUG2, "End dump, iterated %d dumped %d", wa.count, wa.dumped); | ||||
if (!nlmsg_end_dump(wa.nw, error, &wa.hdr)) { | if (!nlmsg_end_dump(wa.nw, error, &wa.hdr)) { | ||||
NL_LOG(LOG_DEBUG, "Unable to finalize the dump"); | NL_LOG(LOG_DEBUG, "Unable to finalize the dump"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
#ifdef INET | #ifdef INET | ||||
static int | static int | ||||
handle_newaddr_inet(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs, | handle_newaddr_inet(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs, | ||||
struct ifnet *ifp, struct nlpcb *nlp, struct nl_pstate *npt) | if_t ifp, struct nlpcb *nlp, struct nl_pstate *npt) | ||||
{ | { | ||||
int plen = attrs->ifa_prefixlen; | int plen = attrs->ifa_prefixlen; | ||||
int if_flags = if_getflags(ifp); | int if_flags = if_getflags(ifp); | ||||
struct sockaddr_in *addr, *dst; | struct sockaddr_in *addr, *dst; | ||||
if (plen > 32) { | if (plen > 32) { | ||||
nlmsg_report_err_msg(npt, "invalid ifa_prefixlen"); | nlmsg_report_err_msg(npt, "invalid ifa_prefixlen"); | ||||
return (EINVAL); | return (EINVAL); | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | handle_newaddr_inet(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs, | ||||
if (dst != NULL) | if (dst != NULL) | ||||
req.ifra_dstaddr = *dst; | req.ifra_dstaddr = *dst; | ||||
return (in_control(NULL, SIOCAIFADDR, &req, ifp, curthread)); | return (in_control(NULL, SIOCAIFADDR, &req, ifp, curthread)); | ||||
} | } | ||||
static int | static int | ||||
handle_deladdr_inet(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs, | handle_deladdr_inet(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs, | ||||
struct ifnet *ifp, struct nlpcb *nlp, struct nl_pstate *npt) | if_t ifp, struct nlpcb *nlp, struct nl_pstate *npt) | ||||
{ | { | ||||
struct sockaddr_in *addr = (struct sockaddr_in *)attrs->ifa_local; | struct sockaddr_in *addr = (struct sockaddr_in *)attrs->ifa_local; | ||||
if (addr == NULL) | if (addr == NULL) | ||||
addr = (struct sockaddr_in *)attrs->ifa_address; | addr = (struct sockaddr_in *)attrs->ifa_address; | ||||
if (addr == NULL) { | if (addr == NULL) { | ||||
nlmsg_report_err_msg(npt, "empty IFA_ADDRESS/IFA_LOCAL"); | nlmsg_report_err_msg(npt, "empty IFA_ADDRESS/IFA_LOCAL"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
struct in_aliasreq req = { .ifra_addr = *addr }; | struct in_aliasreq req = { .ifra_addr = *addr }; | ||||
return (in_control(NULL, SIOCDIFADDR, &req, ifp, curthread)); | return (in_control(NULL, SIOCDIFADDR, &req, ifp, curthread)); | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
static int | static int | ||||
handle_newaddr_inet6(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs, | handle_newaddr_inet6(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs, | ||||
struct ifnet *ifp, struct nlpcb *nlp, struct nl_pstate *npt) | if_t ifp, struct nlpcb *nlp, struct nl_pstate *npt) | ||||
{ | { | ||||
struct sockaddr_in6 *addr, *dst; | struct sockaddr_in6 *addr, *dst; | ||||
if (attrs->ifa_prefixlen > 128) { | if (attrs->ifa_prefixlen > 128) { | ||||
nlmsg_report_err_msg(npt, "invalid ifa_prefixlen"); | nlmsg_report_err_msg(npt, "invalid ifa_prefixlen"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | handle_newaddr_inet6(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs, | ||||
if (dst != NULL) | if (dst != NULL) | ||||
req.ifra_dstaddr = *dst; | req.ifra_dstaddr = *dst; | ||||
return (in6_control(NULL, SIOCAIFADDR_IN6, &req, ifp, curthread)); | return (in6_control(NULL, SIOCAIFADDR_IN6, &req, ifp, curthread)); | ||||
} | } | ||||
static int | static int | ||||
handle_deladdr_inet6(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs, | handle_deladdr_inet6(struct nlmsghdr *hdr, struct nl_parsed_ifa *attrs, | ||||
struct ifnet *ifp, struct nlpcb *nlp, struct nl_pstate *npt) | if_t ifp, struct nlpcb *nlp, struct nl_pstate *npt) | ||||
{ | { | ||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)attrs->ifa_local; | struct sockaddr_in6 *addr = (struct sockaddr_in6 *)attrs->ifa_local; | ||||
if (addr == NULL) | if (addr == NULL) | ||||
addr = (struct sockaddr_in6 *)(attrs->ifa_address); | addr = (struct sockaddr_in6 *)(attrs->ifa_address); | ||||
if (addr == NULL) { | if (addr == NULL) { | ||||
nlmsg_report_err_msg(npt, "Empty IFA_LOCAL/IFA_ADDRESS"); | nlmsg_report_err_msg(npt, "Empty IFA_LOCAL/IFA_ADDRESS"); | ||||
Show All 14 Lines | rtnl_handle_addr(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt) | ||||
int error; | int error; | ||||
struct nl_parsed_ifa attrs = {}; | struct nl_parsed_ifa attrs = {}; | ||||
error = nl_parse_nlmsg(hdr, &ifa_parser, npt, &attrs); | error = nl_parse_nlmsg(hdr, &ifa_parser, npt, &attrs); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
struct ifnet *ifp = ifnet_byindex_ref(attrs.ifa_index); | if_t ifp = ifnet_byindex_ref(attrs.ifa_index); | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
if (ifp == NULL) { | if (ifp == NULL) { | ||||
nlmsg_report_err_msg(npt, "Unable to find interface with index %u", | nlmsg_report_err_msg(npt, "Unable to find interface with index %u", | ||||
attrs.ifa_index); | attrs.ifa_index); | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
int if_flags = if_getflags(ifp); | int if_flags = if_getflags(ifp); | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | #endif | ||||
hdr.nlmsg_type = (cmd == RTM_DELETE) ? NL_RTM_DELADDR : NL_RTM_NEWADDR; | hdr.nlmsg_type = (cmd == RTM_DELETE) ? NL_RTM_DELADDR : NL_RTM_NEWADDR; | ||||
dump_iface_addr(&nw, ifa->ifa_ifp, ifa, &hdr); | dump_iface_addr(&nw, ifa->ifa_ifp, ifa, &hdr); | ||||
nlmsg_flush(&nw); | nlmsg_flush(&nw); | ||||
} | } | ||||
static void | static void | ||||
rtnl_handle_ifevent(struct ifnet *ifp, int nlmsg_type, int if_flags_mask) | rtnl_handle_ifevent(if_t ifp, int nlmsg_type, int if_flags_mask) | ||||
{ | { | ||||
struct nlmsghdr hdr = { .nlmsg_type = nlmsg_type }; | struct nlmsghdr hdr = { .nlmsg_type = nlmsg_type }; | ||||
struct nl_writer nw = {}; | struct nl_writer nw = {}; | ||||
if (!nl_has_listeners(NETLINK_ROUTE, RTNLGRP_LINK)) | if (!nl_has_listeners(NETLINK_ROUTE, RTNLGRP_LINK)) | ||||
return; | return; | ||||
if (!nlmsg_get_group_writer(&nw, NLMSG_LARGE, NETLINK_ROUTE, RTNLGRP_LINK)) { | if (!nlmsg_get_group_writer(&nw, NLMSG_LARGE, NETLINK_ROUTE, RTNLGRP_LINK)) { | ||||
NL_LOG(LOG_DEBUG, "error allocating mbuf"); | NL_LOG(LOG_DEBUG, "error allocating mbuf"); | ||||
return; | return; | ||||
} | } | ||||
dump_iface(&nw, ifp, &hdr, if_flags_mask); | dump_iface(&nw, ifp, &hdr, if_flags_mask); | ||||
nlmsg_flush(&nw); | nlmsg_flush(&nw); | ||||
} | } | ||||
static void | static void | ||||
rtnl_handle_ifattach(void *arg, struct ifnet *ifp) | rtnl_handle_ifattach(void *arg, if_t ifp) | ||||
{ | { | ||||
NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp)); | NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp)); | ||||
rtnl_handle_ifevent(ifp, NL_RTM_NEWLINK, 0); | rtnl_handle_ifevent(ifp, NL_RTM_NEWLINK, 0); | ||||
} | } | ||||
static void | static void | ||||
rtnl_handle_ifdetach(void *arg, struct ifnet *ifp) | rtnl_handle_ifdetach(void *arg, if_t ifp) | ||||
{ | { | ||||
NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp)); | NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp)); | ||||
rtnl_handle_ifevent(ifp, NL_RTM_DELLINK, 0); | rtnl_handle_ifevent(ifp, NL_RTM_DELLINK, 0); | ||||
} | } | ||||
static void | static void | ||||
rtnl_handle_iflink(void *arg, struct ifnet *ifp) | rtnl_handle_iflink(void *arg, if_t ifp) | ||||
{ | { | ||||
NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp)); | NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp)); | ||||
rtnl_handle_ifevent(ifp, NL_RTM_NEWLINK, 0); | rtnl_handle_ifevent(ifp, NL_RTM_NEWLINK, 0); | ||||
} | } | ||||
void | void | ||||
rtnl_handle_ifnet_event(struct ifnet *ifp, int if_flags_mask) | rtnl_handle_ifnet_event(if_t ifp, int if_flags_mask) | ||||
{ | { | ||||
NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp)); | NL_LOG(LOG_DEBUG2, "ifnet %s", if_name(ifp)); | ||||
rtnl_handle_ifevent(ifp, NL_RTM_NEWLINK, if_flags_mask); | rtnl_handle_ifevent(ifp, NL_RTM_NEWLINK, if_flags_mask); | ||||
} | } | ||||
static const struct rtnl_cmd_handler cmd_handlers[] = { | static const struct rtnl_cmd_handler cmd_handlers[] = { | ||||
{ | { | ||||
.cmd = NL_RTM_GETLINK, | .cmd = NL_RTM_GETLINK, | ||||
▲ Show 20 Lines • Show All 87 Lines • Show Last 20 Lines |