#include "kpi_interface.h"
#include <sys/queue.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/kern_event.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/kpi_mbuf.h>
#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/dlil.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <net/if_arp.h>
#include <libkern/libkern.h>
#include <kern/locks.h>
#if IF_LASTCHANGEUPTIME
#define TOUCHLASTCHANGE(__if_lastchange) microuptime(__if_lastchange)
#else
#define TOUCHLASTCHANGE(__if_lastchange) microtime(__if_lastchange)
#endif
extern lck_spin_t *dlil_input_lock;
static void
ifnet_kpi_free(
ifnet_t ifp)
{
ifnet_detached_func detach_func = ifp->if_kpi_storage;
if (detach_func)
detach_func(ifp);
if (ifp->if_broadcast.length > sizeof(ifp->if_broadcast.u.buffer)) {
FREE(ifp->if_broadcast.u.ptr, M_IFADDR);
ifp->if_broadcast.u.ptr = NULL;
}
dlil_if_release(ifp);
}
errno_t
ifnet_allocate(
const struct ifnet_init_params *init,
ifnet_t *interface)
{
int error;
struct ifnet *ifp = NULL;
if (init->family == 0)
return EINVAL;
if (init->name == NULL ||
init->output == NULL)
return EINVAL;
if (strlen(init->name) >= IFNAMSIZ)
return EINVAL;
if ((init->type & 0xFFFFFF00) != 0 || init->type == 0)
return EINVAL;
error = dlil_if_acquire(init->family, init->uniqueid, init->uniqueid_len, &ifp);
if (error == 0)
{
strncpy(ifp->if_name, init->name, IFNAMSIZ);
ifp->if_type = init->type;
ifp->if_family = init->family;
ifp->if_unit = init->unit;
ifp->if_output = init->output;
ifp->if_demux = init->demux;
ifp->if_add_proto_u.kpi = init->add_proto;
ifp->if_del_proto = init->del_proto;
ifp->if_check_multi = init->check_multi;
ifp->if_framer = init->framer;
ifp->if_softc = init->softc;
ifp->if_ioctl = init->ioctl;
ifp->if_set_bpf_tap = init->set_bpf_tap;
ifp->if_free = ifnet_kpi_free;
ifp->if_event = init->event;
ifp->if_kpi_storage = init->detach;
ifp->if_eflags |= IFEF_USEKPI;
if (init->broadcast_len && init->broadcast_addr) {
if (init->broadcast_len > sizeof(ifp->if_broadcast.u.buffer)) {
MALLOC(ifp->if_broadcast.u.ptr, u_char*, init->broadcast_len, M_IFADDR, M_NOWAIT);
if (ifp->if_broadcast.u.ptr == NULL) {
error = ENOMEM;
}
else {
bcopy(init->broadcast_addr, ifp->if_broadcast.u.ptr, init->broadcast_len);
}
}
else {
bcopy(init->broadcast_addr, ifp->if_broadcast.u.buffer, init->broadcast_len);
}
ifp->if_broadcast.length = init->broadcast_len;
}
else {
bzero(&ifp->if_broadcast, sizeof(ifp->if_broadcast));
}
if (error == 0) {
*interface = ifp;
ifnet_reference(ifp); }
else {
dlil_if_release(ifp);
*interface = 0;
}
}
return error;
}
errno_t
ifnet_reference(
ifnet_t interface)
{
if (interface == NULL) return EINVAL;
ifp_reference(interface);
return 0;
}
errno_t
ifnet_release(
ifnet_t interface)
{
if (interface == NULL) return EINVAL;
ifp_release(interface);
return 0;
}
errno_t
ifnet_attach(
ifnet_t interface,
const struct sockaddr_dl *ll_addr)
{
if (interface == NULL) return EINVAL;
if (ll_addr && interface->if_addrlen == 0) {
interface->if_addrlen = ll_addr->sdl_alen;
}
else if (ll_addr && ll_addr->sdl_alen != interface->if_addrlen) {
return EINVAL;
}
return dlil_if_attach_with_address(interface, ll_addr);
}
errno_t
ifnet_detach(
ifnet_t interface)
{
errno_t error;
if (interface == NULL) return EINVAL;
error = dlil_if_detach(interface);
if (error == DLIL_WAIT_FOR_FREE) error = 0;
return error;
}
void*
ifnet_softc(
ifnet_t interface)
{
return interface == NULL ? NULL : interface->if_softc;
}
const char*
ifnet_name(
ifnet_t interface)
{
return interface == NULL ? NULL : interface->if_name;
}
ifnet_family_t
ifnet_family(
ifnet_t interface)
{
return interface == NULL ? 0 : interface->if_family;
}
u_int32_t
ifnet_unit(
ifnet_t interface)
{
return interface == NULL ? (u_int32_t)0xffffffff : (u_int32_t)interface->if_unit;
}
u_int32_t
ifnet_index(
ifnet_t interface)
{
return interface == NULL ? (u_int32_t)0xffffffff : interface->if_index;
}
errno_t
ifnet_set_flags(
ifnet_t interface,
u_int16_t new_flags,
u_int16_t mask)
{
int lock;
if (interface == NULL) return EINVAL;
lock = (interface->if_lock != 0);
if (lock) ifnet_lock_exclusive(interface);
if (lock && (mask & IFF_UP) != 0) {
if_updown(interface, (new_flags & IFF_UP) == IFF_UP);
}
interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask);
if (lock) ifnet_lock_done(interface);
return 0;
}
u_int16_t
ifnet_flags(
ifnet_t interface)
{
return interface == NULL ? 0 : interface->if_flags;
}
errno_t
ifnet_set_eflags(
ifnet_t interface,
u_int32_t new_flags,
u_int32_t mask)
{
int lock;
if (interface == NULL) return EINVAL;
lock = (interface->if_lock != 0);
if (lock) ifnet_lock_exclusive(interface);
interface->if_eflags = (new_flags & mask) | (interface->if_eflags & ~mask);
if (lock) ifnet_lock_done(interface);
return 0;
}
u_int32_t
ifnet_eflags(
ifnet_t interface)
{
return interface == NULL ? 0 : interface->if_eflags;
}
static const ifnet_offload_t offload_mask = IFNET_CSUM_IP | IFNET_CSUM_TCP |
IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT |
IFNET_CSUM_SUM16 | IFNET_VLAN_TAGGING | IFNET_VLAN_MTU;
errno_t
ifnet_set_offload(
ifnet_t interface,
ifnet_offload_t offload)
{
int lock;
if (interface == NULL) return EINVAL;
lock = (interface->if_lock != 0);
if (lock) ifnet_lock_exclusive(interface);
interface->if_hwassist = (offload & offload_mask);
if (lock) ifnet_lock_done(interface);
return 0;
}
ifnet_offload_t
ifnet_offload(
ifnet_t interface)
{
return interface == NULL ? 0 : (interface->if_hwassist & offload_mask);
}
errno_t
ifnet_set_link_mib_data(
ifnet_t interface,
void* mibData,
u_int32_t mibLen)
{
int lock;
if (interface == NULL) return EINVAL;
lock = (interface->if_lock != 0);
if (lock) ifnet_lock_exclusive(interface);
interface->if_linkmib = (void*)mibData;
interface->if_linkmiblen = mibLen;
if (lock) ifnet_lock_done(interface);
return 0;
}
errno_t
ifnet_get_link_mib_data(
ifnet_t interface,
void *mibData,
u_int32_t *mibLen)
{
errno_t result = 0;
int lock;
if (interface == NULL) return EINVAL;
lock = (interface->if_lock != NULL);
if (lock) ifnet_lock_shared(interface);
if (*mibLen < interface->if_linkmiblen)
result = EMSGSIZE;
if (result == 0 && interface->if_linkmib == NULL)
result = ENOTSUP;
if (result == 0) {
*mibLen = interface->if_linkmiblen;
bcopy(interface->if_linkmib, mibData, *mibLen);
}
if (lock) ifnet_lock_done(interface);
return result;
}
u_int32_t
ifnet_get_link_mib_data_length(
ifnet_t interface)
{
return interface == NULL ? 0 : interface->if_linkmiblen;
}
errno_t
ifnet_attach_protocol(
ifnet_t interface,
protocol_family_t protocol,
const struct ifnet_attach_proto_param *proto_details)
{
if (interface == NULL || protocol == 0 || proto_details == NULL)
return EINVAL;
return dlil_attach_protocol_kpi(interface, protocol, proto_details);
}
errno_t
ifnet_detach_protocol(
ifnet_t interface,
protocol_family_t protocol)
{
if (interface == NULL || protocol == 0) return EINVAL;
return dlil_detach_protocol(interface, protocol);
}
errno_t
ifnet_output(
ifnet_t interface,
protocol_family_t protocol_family,
mbuf_t m,
void *route,
const struct sockaddr *dest)
{
if (interface == NULL || protocol_family == 0 || m == NULL) {
if (m)
mbuf_freem_list(m);
return EINVAL;
}
return dlil_output(interface, protocol_family, m, route, dest, 0);
}
errno_t
ifnet_output_raw(
ifnet_t interface,
protocol_family_t protocol_family,
mbuf_t m)
{
if (interface == NULL || protocol_family == 0 || m == NULL) {
if (m)
mbuf_freem_list(m);
return EINVAL;
}
return dlil_output(interface, protocol_family, m, NULL, NULL, 1);
}
errno_t
ifnet_input(
ifnet_t interface,
mbuf_t first_packet,
const struct ifnet_stat_increment_param *stats)
{
mbuf_t last_packet = first_packet;
if (interface == NULL || first_packet == NULL) {
if (first_packet)
mbuf_freem_list(first_packet);
return EINVAL;
}
while (mbuf_nextpkt(last_packet) != NULL)
last_packet = mbuf_nextpkt(last_packet);
return dlil_input_with_stats(interface, first_packet, last_packet, stats);
}
errno_t
ifnet_ioctl(
ifnet_t interface,
protocol_family_t protocol_family,
u_int32_t ioctl_code,
void *ioctl_arg)
{
if (interface == NULL || protocol_family == 0 || ioctl_code == 0)
return EINVAL;
return dlil_ioctl(protocol_family, interface,
ioctl_code, ioctl_arg);
}
errno_t
ifnet_event(
ifnet_t interface,
struct kern_event_msg* event_ptr)
{
if (interface == NULL || event_ptr == NULL) return EINVAL;
return dlil_event(interface, event_ptr);
}
errno_t
ifnet_set_mtu(
ifnet_t interface,
u_int32_t mtu)
{
if (interface == NULL) return EINVAL;
interface->if_data.ifi_mtu = mtu;
return 0;
}
u_int32_t
ifnet_mtu(
ifnet_t interface)
{
u_int32_t retval;
retval = interface == NULL ? 0 : interface->if_data.ifi_mtu;
return retval;
}
u_char
ifnet_type(
ifnet_t interface)
{
u_char retval;
retval = interface == NULL ? 0 : interface->if_data.ifi_type;
return retval;
}
#if 0
errno_t
ifnet_set_typelen(
ifnet_t interface,
u_char typelen)
{
int lock = (interface->if_lock != 0);
if (lock) ifnet_lock_exclusive(interface);
interface->if_data.ifi_typelen = typelen;
if (lock) ifnet_lock_done(interface);
return 0;
}
u_char
ifnet_typelen(
ifnet_t interface)
{
u_char retval;
retval = interface == NULL ? 0 : interface->if_data.ifi_typelen;
return retval;
}
#endif
errno_t
ifnet_set_addrlen(
ifnet_t interface,
u_char addrlen)
{
if (interface == NULL) return EINVAL;
interface->if_data.ifi_addrlen = addrlen;
return 0;
}
u_char
ifnet_addrlen(
ifnet_t interface)
{
u_char retval;
retval = interface == NULL ? 0 : interface->if_data.ifi_addrlen;
return retval;
}
errno_t
ifnet_set_hdrlen(
ifnet_t interface,
u_char hdrlen)
{
if (interface == NULL) return EINVAL;
interface->if_data.ifi_hdrlen = hdrlen;
return 0;
}
u_char
ifnet_hdrlen(
ifnet_t interface)
{
u_char retval;
retval = interface == NULL ? 0 : interface->if_data.ifi_hdrlen;
return retval;
}
errno_t
ifnet_set_metric(
ifnet_t interface,
u_int32_t metric)
{
if (interface == NULL) return EINVAL;
interface->if_data.ifi_metric = metric;
return 0;
}
u_int32_t
ifnet_metric(
ifnet_t interface)
{
u_int32_t retval;
retval = interface == NULL ? 0 : interface->if_data.ifi_metric;
return retval;
}
errno_t
ifnet_set_baudrate(
ifnet_t interface,
u_int64_t baudrate)
{
if (interface == NULL) return EINVAL;
interface->if_data.ifi_baudrate = baudrate > 0xFFFFFFFF ? 0xFFFFFFFF : baudrate;
return 0;
}
u_int64_t
ifnet_baudrate(
ifnet_t interface)
{
u_int64_t retval;
retval = interface == NULL ? 0 : interface->if_data.ifi_baudrate;
return retval;
}
errno_t
ifnet_stat_increment(
ifnet_t interface,
const struct ifnet_stat_increment_param *counts)
{
if (interface == NULL) return EINVAL;
lck_spin_lock(dlil_input_lock);
interface->if_data.ifi_ipackets += counts->packets_in;
interface->if_data.ifi_ibytes += counts->bytes_in;
interface->if_data.ifi_ierrors += counts->errors_in;
interface->if_data.ifi_opackets += counts->packets_out;
interface->if_data.ifi_obytes += counts->bytes_out;
interface->if_data.ifi_oerrors += counts->errors_out;
interface->if_data.ifi_collisions += counts->collisions;
interface->if_data.ifi_iqdrops += counts->dropped;
TOUCHLASTCHANGE(&interface->if_lastchange);
lck_spin_unlock(dlil_input_lock);
return 0;
}
errno_t
ifnet_stat_increment_in(
ifnet_t interface,
u_int32_t packets_in,
u_int32_t bytes_in,
u_int32_t errors_in)
{
if (interface == NULL) return EINVAL;
lck_spin_lock(dlil_input_lock);
interface->if_data.ifi_ipackets += packets_in;
interface->if_data.ifi_ibytes += bytes_in;
interface->if_data.ifi_ierrors += errors_in;
TOUCHLASTCHANGE(&interface->if_lastchange);
lck_spin_unlock(dlil_input_lock);
return 0;
}
errno_t
ifnet_stat_increment_out(
ifnet_t interface,
u_int32_t packets_out,
u_int32_t bytes_out,
u_int32_t errors_out)
{
if (interface == NULL) return EINVAL;
lck_spin_lock(dlil_input_lock);
interface->if_data.ifi_opackets += packets_out;
interface->if_data.ifi_obytes += bytes_out;
interface->if_data.ifi_oerrors += errors_out;
TOUCHLASTCHANGE(&interface->if_lastchange);
lck_spin_unlock(dlil_input_lock);
return 0;
}
errno_t
ifnet_set_stat(
ifnet_t interface,
const struct ifnet_stats_param *stats)
{
if (interface == NULL) return EINVAL;
lck_spin_lock(dlil_input_lock);
interface->if_data.ifi_ipackets = stats->packets_in;
interface->if_data.ifi_ibytes = stats->bytes_in;
interface->if_data.ifi_imcasts = stats->multicasts_in;
interface->if_data.ifi_ierrors = stats->errors_in;
interface->if_data.ifi_opackets = stats->packets_out;
interface->if_data.ifi_obytes = stats->bytes_out;
interface->if_data.ifi_omcasts = stats->multicasts_out;
interface->if_data.ifi_oerrors = stats->errors_out;
interface->if_data.ifi_collisions = stats->collisions;
interface->if_data.ifi_iqdrops = stats->dropped;
interface->if_data.ifi_noproto = stats->no_protocol;
TOUCHLASTCHANGE(&interface->if_lastchange);
lck_spin_unlock(dlil_input_lock);
return 0;
}
errno_t
ifnet_stat(
ifnet_t interface,
struct ifnet_stats_param *stats)
{
if (interface == NULL) return EINVAL;
lck_spin_lock(dlil_input_lock);
stats->packets_in = interface->if_data.ifi_ipackets;
stats->bytes_in = interface->if_data.ifi_ibytes;
stats->multicasts_in = interface->if_data.ifi_imcasts;
stats->errors_in = interface->if_data.ifi_ierrors;
stats->packets_out = interface->if_data.ifi_opackets;
stats->bytes_out = interface->if_data.ifi_obytes;
stats->multicasts_out = interface->if_data.ifi_omcasts;
stats->errors_out = interface->if_data.ifi_oerrors;
stats->collisions = interface->if_data.ifi_collisions;
stats->dropped = interface->if_data.ifi_iqdrops;
stats->no_protocol = interface->if_data.ifi_noproto;
lck_spin_unlock(dlil_input_lock);
return 0;
}
errno_t
ifnet_touch_lastchange(
ifnet_t interface)
{
if (interface == NULL) return EINVAL;
lck_spin_lock(dlil_input_lock);
TOUCHLASTCHANGE(&interface->if_lastchange);
lck_spin_unlock(dlil_input_lock);
return 0;
}
errno_t
ifnet_lastchange(
ifnet_t interface,
struct timeval *last_change)
{
if (interface == NULL) return EINVAL;
lck_spin_lock(dlil_input_lock);
*last_change = interface->if_data.ifi_lastchange;
lck_spin_unlock(dlil_input_lock);
#if IF_LASTCHANGEUPTIME
last_change->tv_sec += boottime_sec();
#endif
return 0;
}
errno_t
ifnet_get_address_list(
ifnet_t interface,
ifaddr_t **addresses)
{
if (interface == NULL || addresses == NULL) return EINVAL;
return ifnet_get_address_list_family(interface, addresses, 0);
}
errno_t
ifnet_get_address_list_family(
ifnet_t interface,
ifaddr_t **addresses,
sa_family_t family)
{
struct ifnet *ifp;
int count = 0;
int cmax = 0;
if (interface == NULL || addresses == NULL) return EINVAL;
*addresses = NULL;
ifnet_head_lock_shared();
TAILQ_FOREACH(ifp, &ifnet, if_link)
{
if (interface && ifp != interface) continue;
ifnet_lock_shared(ifp);
if ((ifp->if_eflags & IFEF_DETACHING) == 0) {
if (interface == NULL || interface == ifp)
{
struct ifaddr *addr;
TAILQ_FOREACH(addr, &ifp->if_addrhead, ifa_link)
{
if (family == 0 || addr->ifa_addr->sa_family == family)
cmax++;
}
}
}
else if (interface != NULL) {
ifnet_lock_done(ifp);
ifnet_head_done();
return ENXIO;
}
ifnet_lock_done(ifp);
}
MALLOC(*addresses, ifaddr_t*, sizeof(ifaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT);
if (*addresses == NULL) {
ifnet_head_done();
return ENOMEM;
}
TAILQ_FOREACH(ifp, &ifnet, if_link)
{
if (interface && ifp != interface) continue;
ifnet_lock_shared(ifp);
if ((ifp->if_eflags & IFEF_DETACHING) == 0) {
if (interface == NULL || (struct ifnet*)interface == ifp)
{
struct ifaddr *addr;
TAILQ_FOREACH(addr, &ifp->if_addrhead, ifa_link)
{
if (count + 1 > cmax) break;
if (family == 0 || addr->ifa_addr->sa_family == family) {
(*addresses)[count] = (ifaddr_t)addr;
ifaddr_reference((*addresses)[count]);
count++;
}
}
}
}
ifnet_lock_done(ifp);
if (interface || count == cmax)
break;
}
ifnet_head_done();
(*addresses)[cmax] = 0;
return 0;
}
void
ifnet_free_address_list(
ifaddr_t *addresses)
{
int i;
if (addresses == NULL) return;
for (i = 0; addresses[i] != NULL; i++)
{
ifaddr_release(addresses[i]);
}
FREE(addresses, M_TEMP);
}
void*
ifnet_lladdr(
ifnet_t interface)
{
if (interface == NULL) return NULL;
return LLADDR(SDL(interface->if_addrhead.tqh_first->ifa_addr));
}
errno_t
ifnet_llbroadcast_copy_bytes(
ifnet_t interface,
void *addr,
size_t buffer_len,
size_t *out_len)
{
if (interface == NULL || addr == NULL || out_len == NULL) return EINVAL;
*out_len = interface->if_broadcast.length;
if (buffer_len < interface->if_broadcast.length) {
return EMSGSIZE;
}
if (interface->if_broadcast.length == 0)
return ENXIO;
if (interface->if_broadcast.length <= sizeof(interface->if_broadcast.u.buffer)) {
bcopy(interface->if_broadcast.u.buffer, addr, interface->if_broadcast.length);
}
else {
bcopy(interface->if_broadcast.u.ptr, addr, interface->if_broadcast.length);
}
return 0;
}
errno_t
ifnet_lladdr_copy_bytes(
ifnet_t interface,
void* lladdr,
size_t lladdr_len)
{
struct sockaddr_dl *sdl;
if (interface == NULL || lladdr == NULL) return EINVAL;
sdl = SDL(interface->if_addrhead.tqh_first->ifa_addr);
while (1) {
if (lladdr_len != sdl->sdl_alen) {
bzero(lladdr, lladdr_len);
return EMSGSIZE;
}
bcopy(LLADDR(sdl), lladdr, lladdr_len);
if (bcmp(lladdr, LLADDR(sdl), lladdr_len) == 0 &&
lladdr_len == sdl->sdl_alen)
break;
}
return 0;
}
static errno_t
ifnet_set_lladdr_internal(
ifnet_t interface,
const void *lladdr,
size_t lladdr_len,
u_char new_type,
int apply_type)
{
struct ifaddr *ifa;
struct sockaddr_dl *sdl;
errno_t error = 0;
if (interface == NULL) return EINVAL;
if (lladdr_len != 0 && (lladdr_len != interface->if_addrlen || lladdr == 0))
return EINVAL;
ifnet_head_lock_shared();
ifa = ifnet_addrs[interface->if_index - 1];
if (ifa != NULL) {
sdl = (struct sockaddr_dl*)ifa->ifa_addr;
if (lladdr_len != 0) {
bcopy(lladdr, LLADDR(sdl), lladdr_len);
}
else {
bzero(LLADDR(sdl), interface->if_addrlen);
}
sdl->sdl_alen = lladdr_len;
if (apply_type) {
sdl->sdl_type = new_type;
}
}
else {
error = ENXIO;
}
ifnet_head_done();
if (error == 0) {
dlil_post_msg(interface, KEV_DL_SUBCLASS,
KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0);
}
return error;
}
errno_t
ifnet_set_lladdr(
ifnet_t interface,
const void* lladdr,
size_t lladdr_len)
{
return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, 0, 0);
}
errno_t
ifnet_set_lladdr_and_type(
ifnet_t interface,
const void* lladdr,
size_t lladdr_len,
u_char type)
{
return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, type, 1);
}
errno_t
ifnet_add_multicast(
ifnet_t interface,
const struct sockaddr *maddr,
ifmultiaddr_t *address)
{
if (interface == NULL || maddr == NULL) return EINVAL;
return if_addmulti(interface, maddr, address);
}
errno_t
ifnet_remove_multicast(
ifmultiaddr_t address)
{
if (address == NULL) return EINVAL;
return if_delmultiaddr(address, 0);
}
errno_t ifnet_get_multicast_list(ifnet_t interface, ifmultiaddr_t **addresses)
{
int count = 0;
int cmax = 0;
struct ifmultiaddr *addr;
int lock;
if (interface == NULL || addresses == NULL)
return EINVAL;
lock = (interface->if_lock != 0);
if (lock) ifnet_lock_shared(interface);
if ((interface->if_eflags & IFEF_DETACHING) == 0) {
LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link)
{
cmax++;
}
}
else {
if (lock) ifnet_lock_done(interface);
return ENXIO;
}
MALLOC(*addresses, ifmultiaddr_t*, sizeof(ifmultiaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT);
if (*addresses == NULL) return ENOMEM;
LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link)
{
if (count + 1 > cmax)
break;
(*addresses)[count] = (ifmultiaddr_t)addr;
ifmaddr_reference((*addresses)[count]);
count++;
}
(*addresses)[cmax] = 0;
if (lock) ifnet_lock_done(interface);
return 0;
}
void
ifnet_free_multicast_list(
ifmultiaddr_t *addresses)
{
int i;
if (addresses == NULL) return;
for (i = 0; addresses[i] != NULL; i++)
{
ifmaddr_release(addresses[i]);
}
FREE(addresses, M_TEMP);
}
errno_t
ifnet_find_by_name(
const char *ifname,
ifnet_t *interface)
{
struct ifnet *ifp;
int namelen;
if (ifname == NULL) return EINVAL;
namelen = strlen(ifname);
*interface = NULL;
ifnet_head_lock_shared();
TAILQ_FOREACH(ifp, &ifnet, if_link)
{
struct ifaddr *ifa = ifnet_addrs[ifp->if_index - 1];
struct sockaddr_dl *ll_addr;
if (!ifa || !ifa->ifa_addr)
continue;
ll_addr = (struct sockaddr_dl *)ifa->ifa_addr;
if ((ifp->if_eflags & IFEF_DETACHING) == 0 &&
namelen == ll_addr->sdl_nlen &&
(strncmp(ll_addr->sdl_data, ifname, ll_addr->sdl_nlen) == 0))
{
break;
}
}
if (ifp) {
*interface = ifp;
ifnet_reference(*interface);
}
ifnet_head_done();
return (ifp == NULL) ? ENXIO : 0;
}
errno_t
ifnet_list_get(
ifnet_family_t family,
ifnet_t **list,
u_int32_t *count)
{
struct ifnet *ifp;
u_int32_t cmax = 0;
*count = 0;
errno_t result = 0;
if (list == NULL || count == NULL) return EINVAL;
ifnet_head_lock_shared();
TAILQ_FOREACH(ifp, &ifnet, if_link)
{
if (ifp->if_eflags & IFEF_DETACHING) continue;
if (family == 0 || ifp->if_family == family)
cmax++;
}
if (cmax == 0)
result = ENXIO;
if (result == 0) {
MALLOC(*list, ifnet_t*, sizeof(ifnet_t) * (cmax + 1), M_TEMP, M_NOWAIT);
if (*list == NULL)
result = ENOMEM;
}
if (result == 0) {
TAILQ_FOREACH(ifp, &ifnet, if_link)
{
if (ifp->if_eflags & IFEF_DETACHING) continue;
if (*count + 1 > cmax) break;
if (family == 0 || ((ifnet_family_t)ifp->if_family) == family)
{
(*list)[*count] = (ifnet_t)ifp;
ifnet_reference((*list)[*count]);
(*count)++;
}
}
(*list)[*count] = NULL;
}
ifnet_head_done();
return 0;
}
void
ifnet_list_free(
ifnet_t *interfaces)
{
int i;
if (interfaces == NULL) return;
for (i = 0; interfaces[i]; i++)
{
ifnet_release(interfaces[i]);
}
FREE(interfaces, M_TEMP);
}
errno_t
ifaddr_reference(
ifaddr_t ifa)
{
if (ifa == NULL) return EINVAL;
ifaref(ifa);
return 0;
}
errno_t
ifaddr_release(
ifaddr_t ifa)
{
if (ifa == NULL) return EINVAL;
ifafree(ifa);
return 0;
}
sa_family_t
ifaddr_address_family(
ifaddr_t ifa)
{
if (ifa && ifa->ifa_addr)
return ifa->ifa_addr->sa_family;
return 0;
}
errno_t
ifaddr_address(
ifaddr_t ifa,
struct sockaddr *out_addr,
u_int32_t addr_size)
{
u_int32_t copylen;
if (ifa == NULL || out_addr == NULL) return EINVAL;
if (ifa->ifa_addr == NULL) return ENOTSUP;
copylen = (addr_size >= ifa->ifa_addr->sa_len) ? ifa->ifa_addr->sa_len : addr_size;
bcopy(ifa->ifa_addr, out_addr, copylen);
if (ifa->ifa_addr->sa_len > addr_size) return EMSGSIZE;
return 0;
}
errno_t
ifaddr_dstaddress(
ifaddr_t ifa,
struct sockaddr *out_addr,
u_int32_t addr_size)
{
u_int32_t copylen;
if (ifa == NULL || out_addr == NULL) return EINVAL;
if (ifa->ifa_dstaddr == NULL) return ENOTSUP;
copylen = (addr_size >= ifa->ifa_dstaddr->sa_len) ? ifa->ifa_dstaddr->sa_len : addr_size;
bcopy(ifa->ifa_dstaddr, out_addr, copylen);
if (ifa->ifa_dstaddr->sa_len > addr_size) return EMSGSIZE;
return 0;
}
errno_t
ifaddr_netmask(
ifaddr_t ifa,
struct sockaddr *out_addr,
u_int32_t addr_size)
{
u_int32_t copylen;
if (ifa == NULL || out_addr == NULL) return EINVAL;
if (ifa->ifa_netmask == NULL) return ENOTSUP;
copylen = addr_size >= ifa->ifa_netmask->sa_len ? ifa->ifa_netmask->sa_len : addr_size;
bcopy(ifa->ifa_netmask, out_addr, copylen);
if (ifa->ifa_netmask->sa_len > addr_size) return EMSGSIZE;
return 0;
}
ifnet_t
ifaddr_ifnet(
ifaddr_t ifa)
{
struct ifnet *ifp;
if (ifa == NULL) return NULL;
ifp = ifa->ifa_ifp;
return (ifnet_t)ifp;
}
ifaddr_t
ifaddr_withaddr(
const struct sockaddr* address)
{
if (address == NULL) return NULL;
return ifa_ifwithaddr(address);
}
ifaddr_t
ifaddr_withdstaddr(
const struct sockaddr* address)
{
if (address == NULL) return NULL;
return ifa_ifwithdstaddr(address);
}
ifaddr_t
ifaddr_withnet(
const struct sockaddr* net)
{
if (net == NULL) return NULL;
return ifa_ifwithnet(net);
}
ifaddr_t
ifaddr_withroute(
int flags,
const struct sockaddr* destination,
const struct sockaddr* gateway)
{
if (destination == NULL || gateway == NULL) return NULL;
return ifa_ifwithroute(flags, destination, gateway);
}
ifaddr_t
ifaddr_findbestforaddr(
const struct sockaddr *addr,
ifnet_t interface)
{
if (addr == NULL || interface == NULL) return NULL;
return ifaof_ifpforaddr(addr, interface);
}
errno_t
ifmaddr_reference(
ifmultiaddr_t ifmaddr)
{
if (ifmaddr == NULL) return EINVAL;
ifma_reference(ifmaddr);
return 0;
}
errno_t
ifmaddr_release(
ifmultiaddr_t ifmaddr)
{
if (ifmaddr == NULL) return EINVAL;
ifma_release(ifmaddr);
return 0;
}
errno_t
ifmaddr_address(
ifmultiaddr_t ifmaddr,
struct sockaddr *out_addr,
u_int32_t addr_size)
{
u_int32_t copylen;
if (ifmaddr == NULL || out_addr == NULL) return EINVAL;
if (ifmaddr->ifma_addr == NULL) return ENOTSUP;
copylen = addr_size >= ifmaddr->ifma_addr->sa_len ? ifmaddr->ifma_addr->sa_len : addr_size;
bcopy(ifmaddr->ifma_addr, out_addr, copylen);
if (ifmaddr->ifma_addr->sa_len > addr_size) return EMSGSIZE;
return 0;
}
errno_t
ifmaddr_lladdress(
ifmultiaddr_t ifmaddr,
struct sockaddr *out_addr,
u_int32_t addr_size)
{
if (ifmaddr == NULL || out_addr == NULL) return EINVAL;
if (ifmaddr->ifma_ll == NULL) return ENOTSUP;
return ifmaddr_address(ifmaddr->ifma_ll, out_addr, addr_size);
}
ifnet_t
ifmaddr_ifnet(
ifmultiaddr_t ifmaddr)
{
if (ifmaddr == NULL || ifmaddr->ifma_ifp == NULL) return NULL;
return ifmaddr->ifma_ifp;
}