* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010 Bjoern A. Zeeb <bz@FreeBSD.org>
* Copyright (c) 1980, 1986, 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.
* 3. 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/epoch.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/ethernet.h>
#include <net/if_vlan_var.h>
uint64_t
if_setbaudrate(struct ifnet *ifp, uint64_t baudrate)
{
uint64_t oldbrate;
oldbrate = ifp->if_baudrate;
ifp->if_baudrate = baudrate;
return (oldbrate);
}
uint64_t
if_getbaudrate(const if_t ifp)
{
return (ifp->if_baudrate);
}
int
if_setcapabilities(if_t ifp, int capabilities)
{
ifp->if_capabilities = capabilities;
return (0);
}
int
if_setcapabilitiesbit(if_t ifp, int setbit, int clearbit)
{
ifp->if_capabilities &= ~clearbit;
ifp->if_capabilities |= setbit;
return (0);
}
int
if_getcapabilities(const if_t ifp)
{
return (ifp->if_capabilities);
}
int
if_setcapenable(if_t ifp, int capabilities)
{
ifp->if_capenable = capabilities;
return (0);
}
int
if_setcapenablebit(if_t ifp, int setcap, int clearcap)
{
ifp->if_capenable &= ~clearcap;
ifp->if_capenable |= setcap;
return (0);
}
#if 0
int
if_setcapabilities2(if_t ifp, int capabilities)
{
ifp->if_capabilities2 = capabilities;
return (0);
}
int
if_setcapabilities2bit(if_t ifp, int setbit, int clearbit)
{
ifp->if_capabilities2 &= ~clearbit;
ifp->if_capabilities2 |= setbit;
return (0);
}
int
if_getcapabilities2(const if_t ifp)
{
return (ifp->if_capabilities2);
}
int
if_setcapenable2(if_t ifp, int capabilities2)
{
ifp->if_capenable2 = capabilities2;
return (0);
}
int
if_setcapenable2bit(if_t ifp, int setcap, int clearcap)
{
ifp->if_capenable2 &= ~clearcap;
ifp->if_capenable2 |= setcap;
return (0);
}
#endif
const char *
if_getdname(const if_t ifp)
{
return (ifp->if_dname);
}
void
if_setdname(if_t ifp, const char *dname)
{
ifp->if_dname = dname;
}
const char *
if_name(if_t ifp)
{
return (ifp->if_xname);
}
int
if_setname(if_t ifp, const char *name)
{
if (strlen(name) > sizeof(ifp->if_xname) - 1)
return (ENAMETOOLONG);
strcpy(ifp->if_xname, name);
return (0);
}
int
if_togglecapenable(if_t ifp, int togglecap)
{
ifp->if_capenable ^= togglecap;
return (0);
}
int
if_getcapenable(const if_t ifp)
{
return (ifp->if_capenable);
}
#if 0
int
if_togglecapenable2(if_t ifp, int togglecap)
{
ifp->if_capenable2 ^= togglecap;
return (0);
}
int
if_getcapenable2(const if_t ifp)
{
return (ifp->if_capenable2);
}
#endif
int
if_getdunit(const if_t ifp)
{
return (ifp->if_dunit);
}
int
if_getindex(const if_t ifp)
{
return (ifp->if_index);
}
#if 0
int
if_getidxgen(const if_t ifp)
{
return (ifp->if_idxgen);
}
const char *
if_getdescr(if_t ifp)
{
return (ifp->if_description);
}
void
if_setdescr(if_t ifp, char *descrbuf)
{
sx_xlock(&ifdescr_sx);
char *odescrbuf = ifp->if_description;
ifp->if_description = descrbuf;
sx_xunlock(&ifdescr_sx);
if_freedescr(odescrbuf);
}
char *
if_allocdescr(size_t sz, int malloc_flag)
{
malloc_flag &= (M_WAITOK | M_NOWAIT);
return (malloc(sz, M_IFDESCR, M_ZERO | malloc_flag));
}
void
if_freedescr(char *descrbuf)
{
free(descrbuf, M_IFDESCR);
}
int
if_getalloctype(const if_t ifp)
{
return (ifp->if_alloctype);
}
void
if_setlastchange(if_t ifp)
{
getmicrotime(&ifp->if_lastchange);
}
#endif
* This is largely undesirable because it ties ifnet to a device, but does
* provide flexiblity for an embedded product vendor. Should be used with
* the understanding that it violates the interface boundaries, and should be
* a last resort only.
*/
int
if_setdev(if_t ifp, void *dev)
{
return (0);
}
int
if_setdrvflagbits(if_t ifp, int set_flags, int clear_flags)
{
ifp->if_drv_flags &= ~clear_flags;
ifp->if_drv_flags |= set_flags;
return (0);
}
int
if_getdrvflags(const if_t ifp)
{
return (ifp->if_drv_flags);
}
int
if_setdrvflags(if_t ifp, int flags)
{
ifp->if_drv_flags = flags;
return (0);
}
int
if_setflags(if_t ifp, int flags)
{
ifp->if_flags = flags;
return (0);
}
int
if_setflagbits(if_t ifp, int set, int clear)
{
ifp->if_flags &= ~clear;
ifp->if_flags |= set;
return (0);
}
int
if_getflags(const if_t ifp)
{
return (ifp->if_flags);
}
int
if_clearhwassist(if_t ifp)
{
ifp->if_hwassist = 0;
return (0);
}
int
if_sethwassistbits(if_t ifp, int toset, int toclear)
{
ifp->if_hwassist &= ~toclear;
ifp->if_hwassist |= toset;
return (0);
}
int
if_sethwassist(if_t ifp, int hwassist_bit)
{
ifp->if_hwassist = hwassist_bit;
return (0);
}
int
if_gethwassist(const if_t ifp)
{
return (ifp->if_hwassist);
}
int
if_togglehwassist(if_t ifp, int toggle_bits)
{
ifp->if_hwassist ^= toggle_bits;
return (0);
}
int
if_setmtu(if_t ifp, int mtu)
{
ifp->if_mtu = mtu;
return (0);
}
#if 0
void
if_notifymtu(if_t ifp)
{
#ifdef INET6
nd6_setmtu(ifp);
#endif
rt_updatemtu(ifp);
}
#endif
int
if_getmtu(const if_t ifp)
{
return (ifp->if_mtu);
}
#if 0
int
if_getmtu_family(const if_t ifp, int family)
{
struct domain *dp;
SLIST_FOREACH(dp, &domains, dom_next) {
if (dp->dom_family == family && dp->dom_ifmtu != NULL)
return (dp->dom_ifmtu(ifp));
}
return (ifp->if_mtu);
}
#endif
* Methods for drivers to access interface unicast and multicast
* link level addresses. Driver shall not know 'struct ifaddr' neither
* 'struct ifmultiaddr'.
*/
u_int
if_lladdr_count(if_t ifp)
{
struct epoch_tracker et;
struct ifaddr *ifa;
u_int count;
count = 0;
NET_EPOCH_ENTER(et);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if (ifa->ifa_addr->sa_family == AF_LINK)
count++;
NET_EPOCH_EXIT(et);
return (count);
}
#if 0
int
if_foreach(if_foreach_cb_t cb, void *cb_arg)
{
if_t ifp;
int error;
NET_EPOCH_ASSERT();
MPASS(cb);
error = 0;
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
error = cb(ifp, cb_arg);
if (error != 0)
break;
}
return (error);
}
* Iterates over the list of interfaces, permitting callback function @cb to sleep.
* Stops iteration if @cb returns non-zero error code.
* Returns the last error code from @cb.
* @match_cb: optional match callback limiting the iteration to only matched interfaces
* @match_arg: argument to pass to @match_cb
* @cb: iteration callback
* @cb_arg: argument to pass to @cb
*/
int
if_foreach_sleep(if_foreach_match_t match_cb, void *match_arg, if_foreach_cb_t cb,
void *cb_arg)
{
int match_count = 0, array_size = 16;
struct ifnet **match_array = NULL;
int error = 0;
MPASS(cb);
while (true) {
struct ifnet **new_array;
int new_size = array_size;
struct epoch_tracker et;
struct ifnet *ifp;
while (new_size < match_count)
new_size *= 2;
new_array = malloc(new_size * sizeof(void *), M_TEMP, M_WAITOK);
if (match_array != NULL)
memcpy(new_array, match_array, array_size * sizeof(void *));
free(match_array, M_TEMP);
match_array = new_array;
array_size = new_size;
match_count = 0;
NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (match_cb != NULL && !match_cb(ifp, match_arg))
continue;
if (match_count < array_size) {
if (if_try_ref(ifp))
match_array[match_count++] = ifp;
} else
match_count++;
}
NET_EPOCH_EXIT(et);
if (match_count > array_size) {
for (int i = 0; i < array_size; i++)
if_rele(match_array[i]);
continue;
} else {
for (int i = 0; i < match_count; i++) {
if (error == 0)
error = cb(match_array[i], cb_arg);
if_rele(match_array[i]);
}
free(match_array, M_TEMP);
break;
}
}
return (error);
}
* Uses just 1 pointer of the 4 available in the public struct.
*/
if_t
if_iter_start(struct if_iter *iter)
{
if_t ifp;
NET_EPOCH_ASSERT();
bzero(iter, sizeof(*iter));
ifp = CK_STAILQ_FIRST(&V_ifnet);
if (ifp != NULL)
iter->context[0] = CK_STAILQ_NEXT(ifp, if_link);
else
iter->context[0] = NULL;
return (ifp);
}
if_t
if_iter_next(struct if_iter *iter)
{
if_t cur_ifp = iter->context[0];
if (cur_ifp != NULL)
iter->context[0] = CK_STAILQ_NEXT(cur_ifp, if_link);
return (cur_ifp);
}
void
if_iter_finish(struct if_iter *iter)
{
}
#endif
u_int
if_foreach_lladdr(if_t ifp, iflladdr_cb_t cb, void *cb_arg)
{
struct epoch_tracker et;
struct ifaddr *ifa;
u_int count;
MPASS(cb);
count = 0;
NET_EPOCH_ENTER(et);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
count += (*cb)(cb_arg, (struct sockaddr_dl *)ifa->ifa_addr,
count);
}
NET_EPOCH_EXIT(et);
return (count);
}
u_int
if_llmaddr_count(if_t ifp)
{
struct epoch_tracker et;
struct ifmultiaddr *ifma;
int count;
count = 0;
NET_EPOCH_ENTER(et);
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
if (ifma->ifma_addr->sa_family == AF_LINK)
count++;
NET_EPOCH_EXIT(et);
return (count);
}
bool
if_maddr_empty(if_t ifp)
{
return (TAILQ_EMPTY(&ifp->if_multiaddrs));
}
u_int
if_foreach_llmaddr(if_t ifp, iflladdr_cb_t cb, void *cb_arg)
{
struct epoch_tracker et;
struct ifmultiaddr *ifma;
u_int count;
MPASS(cb);
count = 0;
NET_EPOCH_ENTER(et);
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
count += (*cb)(cb_arg, (struct sockaddr_dl *)ifma->ifma_addr,
count);
}
NET_EPOCH_EXIT(et);
return (count);
}
#if 0
u_int
if_foreach_addr_type(if_t ifp, int type, if_addr_cb_t cb, void *cb_arg)
{
struct epoch_tracker et;
struct ifaddr *ifa;
u_int count;
MPASS(cb);
count = 0;
NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != type)
continue;
count += (*cb)(cb_arg, ifa, count);
}
NET_EPOCH_EXIT(et);
return (count);
}
struct ifaddr *
ifa_iter_start(if_t ifp, struct ifa_iter *iter)
{
struct ifaddr *ifa;
NET_EPOCH_ASSERT();
bzero(iter, sizeof(*iter));
ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);
if (ifa != NULL)
iter->context[0] = CK_STAILQ_NEXT(ifa, ifa_link);
else
iter->context[0] = NULL;
return (ifa);
}
struct ifaddr *
ifa_iter_next(struct ifa_iter *iter)
{
struct ifaddr *ifa = iter->context[0];
if (ifa != NULL)
iter->context[0] = CK_STAILQ_NEXT(ifa, ifa_link);
return (ifa);
}
void
ifa_iter_finish(struct ifa_iter *iter)
{
}
#endif
int
if_setsoftc(if_t ifp, void *softc)
{
ifp->if_softc = softc;
return (0);
}
void *
if_getsoftc(const if_t ifp)
{
return (ifp->if_softc);
}
void
if_setrcvif(struct mbuf *m, if_t ifp)
{
#if 0
MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
#endif
m->m_pkthdr.rcvif = (struct ifnet *)ifp;
}
void
if_setvtag(struct mbuf *m, uint16_t tag)
{
m->m_pkthdr.ether_vtag = tag;
}
uint16_t
if_getvtag(struct mbuf *m)
{
return (m->m_pkthdr.ether_vtag);
}
int
if_sendq_empty(if_t ifp)
{
return (IFQ_DRV_IS_EMPTY(&ifp->if_snd));
}
struct ifaddr *
if_getifaddr(const if_t ifp)
{
return (ifp->if_addr);
}
int
if_getamcount(const if_t ifp)
{
return (ifp->if_amcount);
}
int
if_setsendqready(if_t ifp)
{
IFQ_SET_READY(&ifp->if_snd);
return (0);
}
int
if_setsendqlen(if_t ifp, int tx_desc_count)
{
IFQ_SET_MAXLEN(&ifp->if_snd, tx_desc_count);
ifp->if_snd.ifq_drv_maxlen = tx_desc_count;
return (0);
}
#if 0
void
if_setnetmapadapter(if_t ifp, struct netmap_adapter *na)
{
ifp->if_netmap = na;
}
struct netmap_adapter *
if_getnetmapadapter(if_t ifp)
{
return (ifp->if_netmap);
}
#endif
int
if_vlantrunkinuse(if_t ifp)
{
return (ifp->if_vlantrunk != NULL);
}
void
if_init(if_t ifp, void *ctx)
{
(*ifp->if_init)(ctx);
}
void
if_input(if_t ifp, struct mbuf* sendmp)
{
(*ifp->if_input)(ifp, sendmp);
}
int
if_transmit(if_t ifp, struct mbuf *m)
{
return ((*ifp->if_transmit)(ifp, m));
}
int
if_resolvemulti(if_t ifp, struct sockaddr **srcs, struct sockaddr *dst)
{
if (ifp->if_resolvemulti == NULL)
return (EOPNOTSUPP);
return (ifp->if_resolvemulti(ifp, srcs, dst));
}
int
if_ioctl(if_t ifp, u_long cmd, void *data)
{
if (ifp->if_ioctl == NULL)
return (EOPNOTSUPP);
return (ifp->if_ioctl(ifp, cmd, (caddr_t)data));
}
struct mbuf *
if_dequeue(if_t ifp)
{
struct mbuf *m;
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
return (m);
}
int
if_sendq_prepend(if_t ifp, struct mbuf *m)
{
IFQ_DRV_PREPEND(&ifp->if_snd, m);
return (0);
}
int
if_setifheaderlen(if_t ifp, int len)
{
ifp->if_hdrlen = len;
return (0);
}
caddr_t
if_getlladdr(const if_t ifp)
{
return (IF_LLADDR(ifp));
}
void *
if_gethandle(u_char type)
{
return (if_alloc(type));
}
void
if_vlancap(if_t ifp)
{
VLAN_CAPABILITIES(ifp);
}
int
if_sethwtsomax(if_t ifp, u_int if_hw_tsomax)
{
ifp->if_hw_tsomax = if_hw_tsomax;
return (0);
}
int
if_sethwtsomaxsegcount(if_t ifp, u_int if_hw_tsomaxsegcount)
{
ifp->if_hw_tsomaxsegcount = if_hw_tsomaxsegcount;
return (0);
}
int
if_sethwtsomaxsegsize(if_t ifp, u_int if_hw_tsomaxsegsize)
{
ifp->if_hw_tsomaxsegsize = if_hw_tsomaxsegsize;
return (0);
}
u_int
if_gethwtsomax(const if_t ifp)
{
return (ifp->if_hw_tsomax);
}
u_int
if_gethwtsomaxsegcount(const if_t ifp)
{
return (ifp->if_hw_tsomaxsegcount);
}
u_int
if_gethwtsomaxsegsize(const if_t ifp)
{
return (ifp->if_hw_tsomaxsegsize);
}
void
if_setinitfn(if_t ifp, if_init_fn_t init_fn)
{
ifp->if_init = init_fn;
}
#if 0
void
if_setinputfn(if_t ifp, if_input_fn_t input_fn)
{
ifp->if_input = input_fn;
}
if_input_fn_t
if_getinputfn(if_t ifp)
{
return (ifp->if_input);
}
#endif
void
if_setioctlfn(if_t ifp, if_ioctl_fn_t ioctl_fn)
{
ifp->if_ioctl = ioctl_fn;
}
#if 0
void
if_setoutputfn(if_t ifp, if_output_fn_t output_fn)
{
ifp->if_output = output_fn;
}
#endif
void
if_setstartfn(if_t ifp, if_start_fn_t start_fn)
{
ifp->if_start = start_fn;
}
if_start_fn_t
if_getstartfn(if_t ifp)
{
return (ifp->if_start);
}
void
if_settransmitfn(if_t ifp, if_transmit_fn_t start_fn)
{
ifp->if_transmit = start_fn;
}
if_transmit_fn_t
if_gettransmitfn(if_t ifp)
{
return (ifp->if_transmit);
}
void
if_setqflushfn(if_t ifp, if_qflush_fn_t flush_fn)
{
ifp->if_qflush = flush_fn;
}
#if 0
void
if_setsndtagallocfn(if_t ifp, if_snd_tag_alloc_t alloc_fn)
{
ifp->if_snd_tag_alloc = alloc_fn;
}
int
if_snd_tag_alloc(if_t ifp, union if_snd_tag_alloc_params *params,
struct m_snd_tag **mstp)
{
if (ifp->if_snd_tag_alloc == NULL)
return (EOPNOTSUPP);
return (ifp->if_snd_tag_alloc(ifp, params, mstp));
}
#endif
void
if_setgetcounterfn(if_t ifp, if_get_counter_t fn)
{
ifp->if_get_counter = fn;
}
#if 0
void
if_setreassignfn(if_t ifp, if_reassign_fn_t fn)
{
ifp->if_reassign = fn;
}
void
if_setratelimitqueryfn(if_t ifp, if_ratelimit_query_t fn)
{
ifp->if_ratelimit_query = fn;
}
void
if_setdebugnet_methods(if_t ifp, struct debugnet_methods *m)
{
ifp->if_debugnet_methods = m;
}
#endif
struct label *
if_getmaclabel(if_t ifp)
{
return (ifp->if_label);
}
void
if_setmaclabel(if_t ifp, struct label *label)
{
ifp->if_label = label;
}
int
if_gettype(if_t ifp)
{
return (ifp->if_type);
}
#if 0
void *
if_getllsoftc(if_t ifp)
{
return (ifp->if_llsoftc);
}
void
if_setllsoftc(if_t ifp, void *llsoftc)
{
ifp->if_llsoftc = llsoftc;
}
#endif
int
if_getlinkstate(if_t ifp)
{
return (ifp->if_link_state);
}
const uint8_t *
if_getbroadcastaddr(if_t ifp)
{
return (ifp->if_broadcastaddr);
}
void
if_setbroadcastaddr(if_t ifp, const uint8_t *addr)
{
ifp->if_broadcastaddr = addr;
}
#if 0
int
if_getnumadomain(if_t ifp)
{
return (ifp->if_numa_domain);
}
#endif
uint64_t
if_getcounter(if_t ifp, ift_counter counter)
{
return (ifp->if_get_counter(ifp, counter));
}
bool
if_altq_is_enabled(if_t ifp)
{
return (ALTQ_IS_ENABLED(&ifp->if_snd));
}
#if 0
struct vnet *
if_getvnet(if_t ifp)
{
return (ifp->if_vnet);
}
#endif
void *
if_getafdata(if_t ifp, int af)
{
return (ifp->if_afdata[af]);
}
#if 0
u_int
if_getfib(if_t ifp)
{
return (ifp->if_fib);
}
#endif
uint8_t
if_getaddrlen(if_t ifp)
{
return (ifp->if_addrlen);
}
struct bpf_if *
if_getbpf(if_t ifp)
{
return (ifp->if_bpf);
}
struct ifvlantrunk *
if_getvlantrunk(if_t ifp)
{
return (ifp->if_vlantrunk);
}
#if 0
uint8_t
if_getpcp(if_t ifp)
{
return (ifp->if_pcp);
}
#endif
void *
if_getl2com(if_t ifp)
{
return (ifp->if_l2com);
}