linux(4): Migrate to IfAPI
Migrate linux and linprocfs to use the IfAPI interfaces instead of
direct ifnet accesses.
The code initially writed by jhibbits@, and adapted by me to 3ab3c9c2
.
Reviewed by: jhibbits
Differential Revision: https://reviews.freebsd.org/D38735
This commit is contained in:
parent
290f7f4a09
commit
6c5786fd37
@ -1478,12 +1478,49 @@ linprocfs_doprocmem(PFS_FILL_ARGS)
|
||||
/*
|
||||
* Filler function for proc/net/dev
|
||||
*/
|
||||
static int
|
||||
linprocfs_donetdev_cb(if_t ifp, void *arg)
|
||||
{
|
||||
char ifname[LINUX_IFNAMSIZ];
|
||||
struct sbuf *sb = arg;
|
||||
|
||||
if (ifname_bsd_to_linux_ifp(ifp, ifname, sizeof(ifname)) <= 0)
|
||||
return (ENODEV);
|
||||
|
||||
sbuf_printf(sb, "%6.6s: ", ifname);
|
||||
sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
|
||||
(uintmax_t)if_getcounter(ifp, IFCOUNTER_IBYTES),
|
||||
(uintmax_t)if_getcounter(ifp, IFCOUNTER_IPACKETS),
|
||||
(uintmax_t)if_getcounter(ifp, IFCOUNTER_IERRORS),
|
||||
(uintmax_t)if_getcounter(ifp, IFCOUNTER_IQDROPS),
|
||||
/* rx_missed_errors */
|
||||
0UL, /* rx_fifo_errors */
|
||||
0UL, /* rx_length_errors +
|
||||
* rx_over_errors +
|
||||
* rx_crc_errors +
|
||||
* rx_frame_errors */
|
||||
0UL, /* rx_compressed */
|
||||
(uintmax_t)if_getcounter(ifp, IFCOUNTER_IMCASTS));
|
||||
/* XXX-BZ rx only? */
|
||||
sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
|
||||
(uintmax_t)if_getcounter(ifp, IFCOUNTER_OBYTES),
|
||||
(uintmax_t)if_getcounter(ifp, IFCOUNTER_OPACKETS),
|
||||
(uintmax_t)if_getcounter(ifp, IFCOUNTER_OERRORS),
|
||||
(uintmax_t)if_getcounter(ifp, IFCOUNTER_OQDROPS),
|
||||
0UL, /* tx_fifo_errors */
|
||||
(uintmax_t)if_getcounter(ifp, IFCOUNTER_COLLISIONS),
|
||||
0UL, /* tx_carrier_errors +
|
||||
* tx_aborted_errors +
|
||||
* tx_window_errors +
|
||||
* tx_heartbeat_errors*/
|
||||
0UL); /* tx_compressed */
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
linprocfs_donetdev(PFS_FILL_ARGS)
|
||||
{
|
||||
struct epoch_tracker et;
|
||||
char ifname[16]; /* XXX LINUX_IFNAMSIZ */
|
||||
struct ifnet *ifp;
|
||||
|
||||
sbuf_printf(sb, "%6s|%58s|%s\n"
|
||||
"%6s|%58s|%58s\n",
|
||||
@ -1494,36 +1531,7 @@ linprocfs_donetdev(PFS_FILL_ARGS)
|
||||
|
||||
CURVNET_SET(TD_TO_VNET(curthread));
|
||||
NET_EPOCH_ENTER(et);
|
||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
||||
ifname_bsd_to_linux_ifp(ifp, ifname, sizeof(ifname));
|
||||
sbuf_printf(sb, "%6.6s: ", ifname);
|
||||
sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
|
||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
|
||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
|
||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
|
||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
|
||||
/* rx_missed_errors */
|
||||
0UL, /* rx_fifo_errors */
|
||||
0UL, /* rx_length_errors +
|
||||
* rx_over_errors +
|
||||
* rx_crc_errors +
|
||||
* rx_frame_errors */
|
||||
0UL, /* rx_compressed */
|
||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
|
||||
/* XXX-BZ rx only? */
|
||||
sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
|
||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
|
||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
|
||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
|
||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
|
||||
0UL, /* tx_fifo_errors */
|
||||
(uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
|
||||
0UL, /* tx_carrier_errors +
|
||||
* tx_aborted_errors +
|
||||
* tx_window_errors +
|
||||
* tx_heartbeat_errors*/
|
||||
0UL); /* tx_compressed */
|
||||
}
|
||||
if_foreach(linprocfs_donetdev_cb, sb);
|
||||
NET_EPOCH_EXIT(et);
|
||||
CURVNET_RESTORE();
|
||||
|
||||
|
@ -287,13 +287,37 @@ ifname_bsd_to_linux_idx(u_int idx, char *lxname, size_t len)
|
||||
|
||||
/*
|
||||
* Translate a FreeBSD interface name to a Linux interface name,
|
||||
* and return the number of bytes copied to lxname.
|
||||
* and return the number of bytes copied to lxname, 0 if interface
|
||||
* not found, -1 on error.
|
||||
*/
|
||||
struct ifname_bsd_to_linux_ifp_cb_s {
|
||||
struct ifnet *ifp;
|
||||
int ethno;
|
||||
char *lxname;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static int
|
||||
ifname_bsd_to_linux_ifp_cb(if_t ifp, void *arg)
|
||||
{
|
||||
struct ifname_bsd_to_linux_ifp_cb_s *cbs = arg;
|
||||
|
||||
if (ifp == cbs->ifp)
|
||||
return (snprintf(cbs->lxname, cbs->len, "eth%d", cbs->ethno));
|
||||
if (IFP_IS_ETH(ifp))
|
||||
cbs->ethno++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len)
|
||||
{
|
||||
struct ifnet *ifscan;
|
||||
int unit;
|
||||
struct ifname_bsd_to_linux_ifp_cb_s arg = {
|
||||
.ifp = ifp,
|
||||
.ethno = 0,
|
||||
.lxname = lxname,
|
||||
.len = len,
|
||||
};
|
||||
|
||||
NET_EPOCH_ASSERT();
|
||||
|
||||
@ -306,17 +330,10 @@ ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len)
|
||||
|
||||
/* Short-circuit non ethernet interfaces. */
|
||||
if (!IFP_IS_ETH(ifp) || linux_use_real_ifname(ifp))
|
||||
return (strlcpy(lxname, ifp->if_xname, len));
|
||||
return (strlcpy(lxname, if_name(ifp), len));
|
||||
|
||||
/* Determine the (relative) unit number for ethernet interfaces. */
|
||||
unit = 0;
|
||||
CK_STAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
|
||||
if (ifscan == ifp)
|
||||
return (snprintf(lxname, len, "eth%d", unit));
|
||||
if (IFP_IS_ETH(ifscan))
|
||||
unit++;
|
||||
}
|
||||
return (0);
|
||||
return (if_foreach(ifname_bsd_to_linux_ifp_cb, &arg));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -325,14 +342,53 @@ ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len)
|
||||
* bsdname and lxname need to be least IFNAMSIZ bytes long, but
|
||||
* can point to the same buffer.
|
||||
*/
|
||||
struct ifname_linux_to_bsd_cb_s {
|
||||
bool is_lo;
|
||||
bool is_eth;
|
||||
int ethno;
|
||||
int unit;
|
||||
const char *lxname;
|
||||
if_t ifp;
|
||||
};
|
||||
|
||||
static int
|
||||
ifname_linux_to_bsd_cb(if_t ifp, void *arg)
|
||||
{
|
||||
struct ifname_linux_to_bsd_cb_s *cbs = arg;
|
||||
|
||||
NET_EPOCH_ASSERT();
|
||||
|
||||
/*
|
||||
* Allow Linux programs to use FreeBSD names. Don't presume
|
||||
* we never have an interface named "eth", so don't make
|
||||
* the test optional based on is_eth.
|
||||
*/
|
||||
if (strncmp(if_name(ifp), cbs->lxname, LINUX_IFNAMSIZ) == 0)
|
||||
goto out;
|
||||
if (cbs->is_eth && IFP_IS_ETH(ifp) && cbs->unit == cbs->ethno)
|
||||
goto out;
|
||||
if (cbs->is_lo && IFP_IS_LOOP(ifp))
|
||||
goto out;
|
||||
if (IFP_IS_ETH(ifp))
|
||||
cbs->ethno++;
|
||||
return (0);
|
||||
|
||||
out:
|
||||
cbs->ifp = ifp;
|
||||
return (1);
|
||||
}
|
||||
|
||||
struct ifnet *
|
||||
ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
int len, unit;
|
||||
struct ifname_linux_to_bsd_cb_s arg = {
|
||||
.ethno = 0,
|
||||
.lxname = lxname,
|
||||
.ifp = NULL,
|
||||
};
|
||||
struct epoch_tracker et;
|
||||
int len, ret;
|
||||
char *ep;
|
||||
int index;
|
||||
bool is_eth, is_lo;
|
||||
|
||||
for (len = 0; len < LINUX_IFNAMSIZ; ++len)
|
||||
if (!isalpha(lxname[len]) || lxname[len] == '\0')
|
||||
@ -343,34 +399,21 @@ ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
|
||||
* Linux loopback interface name is lo (not lo0),
|
||||
* we translate lo to lo0, loX to loX.
|
||||
*/
|
||||
is_lo = (len == 2 && strncmp(lxname, "lo", LINUX_IFNAMSIZ) == 0);
|
||||
unit = (int)strtoul(lxname + len, &ep, 10);
|
||||
arg.is_lo = (len == 2 && strncmp(lxname, "lo", LINUX_IFNAMSIZ) == 0);
|
||||
arg.unit = (int)strtoul(lxname + len, &ep, 10);
|
||||
if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) &&
|
||||
is_lo == 0)
|
||||
arg.is_lo == 0)
|
||||
return (NULL);
|
||||
index = 0;
|
||||
is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
|
||||
arg.is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
|
||||
|
||||
CURVNET_SET(TD_TO_VNET(td));
|
||||
IFNET_RLOCK();
|
||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
||||
/*
|
||||
* Allow Linux programs to use FreeBSD names. Don't presume
|
||||
* we never have an interface named "eth", so don't make
|
||||
* the test optional based on is_eth.
|
||||
*/
|
||||
if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
|
||||
break;
|
||||
if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
|
||||
break;
|
||||
if (is_lo && IFP_IS_LOOP(ifp))
|
||||
break;
|
||||
}
|
||||
IFNET_RUNLOCK();
|
||||
NET_EPOCH_ENTER(et);
|
||||
ret = if_foreach(ifname_linux_to_bsd_cb, &arg);
|
||||
NET_EPOCH_EXIT(et);
|
||||
CURVNET_RESTORE();
|
||||
if (ifp != NULL && bsdname != NULL)
|
||||
strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
|
||||
return (ifp);
|
||||
if (ret > 0 && arg.ifp != NULL && bsdname != NULL)
|
||||
strlcpy(bsdname, if_name(arg.ifp), IFNAMSIZ);
|
||||
return (arg.ifp);
|
||||
}
|
||||
|
||||
void
|
||||
@ -378,7 +421,7 @@ linux_ifflags(struct ifnet *ifp, short *flags)
|
||||
{
|
||||
unsigned short fl;
|
||||
|
||||
fl = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
|
||||
fl = (if_getflags(ifp) | if_getdrvflags(ifp)) & 0xffff;
|
||||
*flags = 0;
|
||||
if (fl & IFF_UP)
|
||||
*flags |= LINUX_IFF_UP;
|
||||
@ -402,32 +445,35 @@ linux_ifflags(struct ifnet *ifp, short *flags)
|
||||
*flags |= LINUX_IFF_MULTICAST;
|
||||
}
|
||||
|
||||
static u_int
|
||||
linux_ifhwaddr_cb(void *arg, struct ifaddr *ifa, u_int count)
|
||||
{
|
||||
struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
|
||||
struct l_sockaddr *lsa = arg;
|
||||
|
||||
if (count > 0)
|
||||
return (0);
|
||||
if (sdl->sdl_type != IFT_ETHER)
|
||||
return (0);
|
||||
bzero(lsa, sizeof(*lsa));
|
||||
lsa->sa_family = LINUX_ARPHRD_ETHER;
|
||||
bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN);
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa)
|
||||
{
|
||||
struct ifaddr *ifa;
|
||||
struct sockaddr_dl *sdl;
|
||||
|
||||
if (IFP_IS_LOOP(ifp)) {
|
||||
bzero(lsa, sizeof(*lsa));
|
||||
lsa->sa_family = LINUX_ARPHRD_LOOPBACK;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!IFP_IS_ETH(ifp))
|
||||
return (ENOENT);
|
||||
|
||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
sdl = (struct sockaddr_dl*)ifa->ifa_addr;
|
||||
if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
|
||||
(sdl->sdl_type == IFT_ETHER)) {
|
||||
bzero(lsa, sizeof(*lsa));
|
||||
lsa->sa_family = LINUX_ARPHRD_ETHER;
|
||||
bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN);
|
||||
if (if_foreach_addr_type(ifp, AF_LINK, linux_ifhwaddr_cb, lsa) > 0)
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
|
@ -287,8 +287,8 @@ struct l_statx {
|
||||
/*
|
||||
* Criteria for interface name translation
|
||||
*/
|
||||
#define IFP_IS_ETH(ifp) ((ifp)->if_type == IFT_ETHER)
|
||||
#define IFP_IS_LOOP(ifp) ((ifp)->if_type == IFT_LOOP)
|
||||
#define IFP_IS_ETH(ifp) (if_gettype(ifp) == IFT_ETHER)
|
||||
#define IFP_IS_LOOP(ifp) (if_gettype(ifp) == IFT_LOOP)
|
||||
|
||||
struct ifnet;
|
||||
|
||||
|
@ -2108,40 +2108,91 @@ linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr)
|
||||
/*
|
||||
* Implement the SIOCGIFCONF ioctl
|
||||
*/
|
||||
static u_int
|
||||
linux_ifconf_ifaddr_cb(void *arg, struct ifaddr *ifa, u_int count)
|
||||
{
|
||||
#ifdef COMPAT_LINUX32
|
||||
struct l_ifconf *ifc;
|
||||
#else
|
||||
struct ifconf *ifc;
|
||||
#endif
|
||||
|
||||
ifc = arg;
|
||||
ifc->ifc_len += sizeof(struct l_ifreq);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
linux_ifconf_ifnet_cb(if_t ifp, void *arg)
|
||||
{
|
||||
|
||||
if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb, arg);
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct linux_ifconfig_ifaddr_cb2_s {
|
||||
struct l_ifreq ifr;
|
||||
struct sbuf *sb;
|
||||
size_t max_len;
|
||||
size_t valid_len;
|
||||
};
|
||||
|
||||
static u_int
|
||||
linux_ifconf_ifaddr_cb2(void *arg, struct ifaddr *ifa, u_int len)
|
||||
{
|
||||
struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
|
||||
struct sockaddr *sa = ifa->ifa_addr;
|
||||
|
||||
cbs->ifr.ifr_addr.sa_family = LINUX_AF_INET;
|
||||
memcpy(cbs->ifr.ifr_addr.sa_data, sa->sa_data,
|
||||
sizeof(cbs->ifr.ifr_addr.sa_data));
|
||||
sbuf_bcat(cbs->sb, &cbs->ifr, sizeof(cbs->ifr));
|
||||
cbs->max_len += sizeof(cbs->ifr);
|
||||
|
||||
if (sbuf_error(cbs->sb) == 0)
|
||||
cbs->valid_len = sbuf_len(cbs->sb);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
linux_ifconf_ifnet_cb2(if_t ifp, void *arg)
|
||||
{
|
||||
struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
|
||||
|
||||
bzero(&cbs->ifr, sizeof(cbs->ifr));
|
||||
ifname_bsd_to_linux_ifp(ifp, cbs->ifr.ifr_name,
|
||||
sizeof(cbs->ifr.ifr_name));
|
||||
|
||||
/* Walk the address list */
|
||||
if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb2, cbs);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
linux_ifconf(struct thread *td, struct ifconf *uifc)
|
||||
{
|
||||
struct linux_ifconfig_ifaddr_cb2_s cbs;
|
||||
struct epoch_tracker et;
|
||||
#ifdef COMPAT_LINUX32
|
||||
struct l_ifconf ifc;
|
||||
#else
|
||||
struct ifconf ifc;
|
||||
#endif
|
||||
struct l_ifreq ifr;
|
||||
struct ifnet *ifp;
|
||||
struct ifaddr *ifa;
|
||||
struct sbuf *sb;
|
||||
int error, full = 0, valid_len, max_len;
|
||||
int error, full;
|
||||
|
||||
error = copyin(uifc, &ifc, sizeof(ifc));
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
max_len = maxphys - 1;
|
||||
full = 0;
|
||||
cbs.max_len = maxphys - 1;
|
||||
|
||||
CURVNET_SET(TD_TO_VNET(td));
|
||||
/* handle the 'request buffer size' case */
|
||||
if ((l_uintptr_t)ifc.ifc_buf == PTROUT(NULL)) {
|
||||
ifc.ifc_len = 0;
|
||||
NET_EPOCH_ENTER(et);
|
||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
struct sockaddr *sa = ifa->ifa_addr;
|
||||
if (sa->sa_family == AF_INET)
|
||||
ifc.ifc_len += sizeof(ifr);
|
||||
}
|
||||
}
|
||||
if_foreach(linux_ifconf_ifnet_cb, &ifc);
|
||||
NET_EPOCH_EXIT(et);
|
||||
error = copyout(&ifc, uifc, sizeof(ifc));
|
||||
CURVNET_RESTORE();
|
||||
@ -2154,56 +2205,25 @@ linux_ifconf(struct thread *td, struct ifconf *uifc)
|
||||
}
|
||||
|
||||
again:
|
||||
if (ifc.ifc_len <= max_len) {
|
||||
max_len = ifc.ifc_len;
|
||||
if (ifc.ifc_len <= cbs.max_len) {
|
||||
cbs.max_len = ifc.ifc_len;
|
||||
full = 1;
|
||||
}
|
||||
sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
|
||||
max_len = 0;
|
||||
valid_len = 0;
|
||||
cbs.sb = sb = sbuf_new(NULL, NULL, cbs.max_len + 1, SBUF_FIXEDLEN);
|
||||
cbs.max_len = 0;
|
||||
cbs.valid_len = 0;
|
||||
|
||||
/* Return all AF_INET addresses of all interfaces */
|
||||
NET_EPOCH_ENTER(et);
|
||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
||||
int addrs = 0;
|
||||
|
||||
bzero(&ifr, sizeof(ifr));
|
||||
ifname_bsd_to_linux_ifp(ifp, ifr.ifr_name,
|
||||
sizeof(ifr.ifr_name));
|
||||
|
||||
/* Walk the address list */
|
||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
struct sockaddr *sa = ifa->ifa_addr;
|
||||
|
||||
if (sa->sa_family == AF_INET) {
|
||||
ifr.ifr_addr.sa_family = LINUX_AF_INET;
|
||||
memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
|
||||
sizeof(ifr.ifr_addr.sa_data));
|
||||
sbuf_bcat(sb, &ifr, sizeof(ifr));
|
||||
max_len += sizeof(ifr);
|
||||
addrs++;
|
||||
}
|
||||
|
||||
if (sbuf_error(sb) == 0)
|
||||
valid_len = sbuf_len(sb);
|
||||
}
|
||||
if (addrs == 0) {
|
||||
bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
|
||||
sbuf_bcat(sb, &ifr, sizeof(ifr));
|
||||
max_len += sizeof(ifr);
|
||||
|
||||
if (sbuf_error(sb) == 0)
|
||||
valid_len = sbuf_len(sb);
|
||||
}
|
||||
}
|
||||
if_foreach(linux_ifconf_ifnet_cb2, &cbs);
|
||||
NET_EPOCH_EXIT(et);
|
||||
|
||||
if (valid_len != max_len && !full) {
|
||||
if (cbs.valid_len != cbs.max_len && !full) {
|
||||
sbuf_delete(sb);
|
||||
goto again;
|
||||
}
|
||||
|
||||
ifc.ifc_len = valid_len;
|
||||
ifc.ifc_len = cbs.valid_len;
|
||||
sbuf_finish(sb);
|
||||
error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
|
||||
if (error == 0)
|
||||
|
Loading…
Reference in New Issue
Block a user