sun: Fix carrier detection, MTU detection and plumbing

dhcpcd no longer needs ifconfig to do the initial plumbing.
This commit is contained in:
Roy Marples 2019-04-14 12:54:16 +03:00
parent 558c927371
commit 8fd4972237
4 changed files with 137 additions and 20 deletions

2
configure vendored
View File

@ -454,7 +454,7 @@ sunos*)
echo "CPPFLAGS+= -D_XPG4_2 -D__EXTENSIONS__ -DBSD_COMP" \
>>$CONFIG_MK
echo "DHCPCD_SRCS+= if-sun.c" >>$CONFIG_MK
echo "LDADD+= -ldlpi" >>$CONFIG_MK
echo "LDADD+= -ldlpi -lkstat" >>$CONFIG_MK
;;
*)
echo "DHCPCD_SRCS+= if-bsd.c" >>$CONFIG_MK

View File

@ -30,6 +30,7 @@
#include <fcntl.h>
#include <ifaddrs.h>
#include <libdlpi.h>
#include <kstat.h>
#include <stddef.h>
#include <stdlib.h>
#include <stropts.h>
@ -45,6 +46,7 @@
#include <netinet/udp.h>
#include <sys/ioctl.h>
#include <sys/mac.h>
#include <sys/pfmod.h>
#include <sys/tihdr.h>
#include <sys/utsname.h>
@ -162,6 +164,63 @@ if_closesockets_os(struct dhcpcd_ctx *ctx)
free(ctx->priv);
}
int
if_carrier_os(struct interface *ifp)
{
kstat_ctl_t *kcp;
kstat_t *ksp;
kstat_named_t *knp;
link_state_t linkstate;
kcp = kstat_open();
if (kcp == NULL)
goto err;
ksp = kstat_lookup(kcp, UNCONST("link"), 0, ifp->name);
if (ksp == NULL)
goto err;
if (kstat_read(kcp, ksp, NULL) == -1)
goto err;
knp = kstat_data_lookup(ksp, UNCONST("link_state"));
if (knp == NULL)
goto err;
if (knp->data_type != KSTAT_DATA_UINT32)
goto err;
linkstate = (link_state_t)knp->value.ui32;
kstat_close(kcp);
switch (linkstate) {
case LINK_STATE_UP:
ifp->flags |= IFF_UP;
return LINK_UP;
case LINK_STATE_DOWN:
return LINK_DOWN;
default:
return LINK_UNKNOWN;
}
err:
if (kcp != NULL)
kstat_close(kcp);
return LINK_UNKNOWN;
}
int
if_mtu_os(const struct interface *ifp)
{
dlpi_handle_t dh;
dlpi_info_t dlinfo;
int mtu;
if (dlpi_open(ifp->name, &dh, 0) != DLPI_SUCCESS)
return -1;
if (dlpi_info(dh, &dlinfo, 0) == DLPI_SUCCESS)
mtu = dlinfo.di_max_sdu;
else
mtu = -1;
dlpi_close(dh);
return mtu;
}
int
if_getssid(struct interface *ifp)
{
@ -723,15 +782,18 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm)
{
struct interface *ifp;
int state;
unsigned int flags;
if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL)
return;
if (ifm->ifm_flags & IFF_OFFLINE || !(ifm->ifm_flags & IFF_UP))
flags = (unsigned int)ifm->ifm_flags;
if (ifm->ifm_flags & IFF_OFFLINE)
state = LINK_DOWN;
else
else {
state = LINK_UP;
dhcpcd_handlecarrier(ctx, state,
(unsigned int)ifm->ifm_flags, ifp->name);
flags |= IFF_UP;
}
dhcpcd_handlecarrier(ctx, state, flags, ifp->name);
}
static void
@ -819,6 +881,7 @@ if_addaddr(int fd, const char *ifname,
if (ioctl(fd, SIOCSLIFFLAGS, &lifr) == -1)
return -1;
}
return 0;
}
@ -847,15 +910,20 @@ if_plumblif(int cmd, const struct dhcpcd_ctx *ctx, int af, const char *ifname)
static int
if_plumbif(const struct dhcpcd_ctx *ctx, int af, const char *ifname)
{
dlpi_handle_t dh;
int fd, af_fd, mux_fd, retval;
dlpi_handle_t dh, dh_arp = NULL;
int fd, af_fd, mux_fd, arp_fd = -1, mux_id, retval;
uint64_t flags;
struct lifreq lifr;
const char *udp_dev;
struct strioctl ioc;
struct if_spec spec;
if (if_nametospec(ifname, &spec) == -1)
return -1;
memset(&lifr, 0, sizeof(lifr));
switch (af) {
case AF_INET:
lifr.lifr_flags = IFF_IPV4;
flags = IFF_IPV4;
af_fd = ctx->pf_inet_fd;
udp_dev = UDP_DEV_NAME;
break;
@ -864,7 +932,7 @@ if_plumbif(const struct dhcpcd_ctx *ctx, int af, const char *ifname)
struct priv *priv;
/* We will take care of setting the link local address. */
lifr.lifr_flags = IFF_IPV6 | IFF_NOLINKLOCAL;
flags = IFF_IPV6 | IFF_NOLINKLOCAL;
priv = (struct priv *)ctx->priv;
af_fd = priv->pf_inet6_fd;
udp_dev = UDP6_DEV_NAME;
@ -885,13 +953,17 @@ if_plumbif(const struct dhcpcd_ctx *ctx, int af, const char *ifname)
mux_fd = -1;
if (ioctl(fd, I_PUSH, IP_MOD_NAME) == -1)
goto out;
memset(&lifr, 0, sizeof(lifr));
strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
lifr.lifr_ppa = spec.ppa;
lifr.lifr_flags = flags;
if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1)
goto out;
/* Get full flags. */
if (ioctl(af_fd, SIOCGLIFFLAGS, &lifr) == -1)
goto out;
flags = lifr.lifr_flags;
/* Open UDP as a multiplexor to PLINK the interface stream.
* UDP is used because STREAMS will not let you PLINK a driver
@ -903,20 +975,50 @@ if_plumbif(const struct dhcpcd_ctx *ctx, int af, const char *ifname)
;
if (errno != EINVAL)
goto out;
if (lifr.lifr_flags & IFF_IPV4 && !(lifr.lifr_flags & IFF_NOARP)) {
if (ioctl(mux_fd, I_PUSH, ARP_MOD_NAME) == -1)
goto out;
}
/* PLINK the interface stream so it persists. */
if (ioctl(mux_fd, I_PLINK, fd) == -1)
if(ioctl(mux_fd, I_PUSH, ARP_MOD_NAME) == -1)
goto out;
if (flags & (IFF_NOARP | IFF_IPV6)) {
/* PLINK the interface stream so it persists. */
if (ioctl(mux_fd, I_PLINK, fd) == -1)
goto out;
goto done;
}
if (dlpi_open(ifname, &dh_arp, DLPI_NOATTACH) != DLPI_SUCCESS)
goto out;
arp_fd = dlpi_fd(dh_arp);
if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1)
goto out;
memset(&lifr, 0, sizeof(lifr));
strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
lifr.lifr_ppa = spec.ppa;
lifr.lifr_flags = flags;
memset(&ioc, 0, sizeof(ioc));
ioc.ic_cmd = SIOCSLIFNAME;
ioc.ic_dp = (char *)&lifr;
ioc.ic_len = sizeof(lifr);
if (ioctl(arp_fd, I_STR, &ioc) == -1)
goto out;
/* PLINK the interface stream so it persists. */
mux_id = ioctl(mux_fd, I_PLINK, fd);
if (mux_id == -1)
goto out;
if (ioctl(mux_fd, I_PLINK, arp_fd) == -1) {
ioctl(mux_fd, I_PUNLINK, mux_id);
goto out;
}
done:
logerrx("plumb %d %d %d", mux_fd, fd, arp_fd);
retval = 0;
out:
dlpi_close(dh);
if (dh_arp != NULL)
dlpi_close(dh_arp);
if (mux_fd != -1)
close(mux_fd);
return retval;

View File

@ -136,9 +136,15 @@ if_carrier(struct interface *ifp)
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
r = ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr);
if (r != -1)
ifp->flags = (unsigned int)ifr.ifr_flags;
#ifdef __sun
return if_carrier_os(ifp);
#else
if (r == -1)
return LINK_UNKNOWN;
ifp->flags = (unsigned int)ifr.ifr_flags;
#ifdef SIOCGIFMEDIA
memset(&ifmr, 0, sizeof(ifmr));
@ -155,6 +161,7 @@ if_carrier(struct interface *ifp)
#else
r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN;
#endif
#endif /* __sun */
return r;
}
@ -711,6 +718,11 @@ if_domtu(const struct interface *ifp, short int mtu)
int r;
struct ifreq ifr;
#ifdef __sun
if (mtu == 0)
return if_mtu_os(ifp);
#endif
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
ifr.ifr_mtu = mtu;

View File

@ -129,6 +129,9 @@ int if_domtu(const struct interface *, short int);
#define if_setmtu(ifp, mtu) if_domtu((ifp), (mtu))
int if_carrier(struct interface *);
int if_carrier_os(struct interface *);
int if_mtu_os(const struct interface *);
/*
* Helper to decode an interface name of bge0:1 to
* devname = bge0, drvname = bge0, ppa = 0, lun = 1.