changeset 4433:4262dbc903e8 draft

sun: Fix carrier detection, MTU detection and plumbing dhcpcd no longer needs ifconfig to do the initial plumbing.
author Roy Marples <roy@marples.name>
date Sun, 14 Apr 2019 12:54:16 +0300
parents 693209ca41db
children 7d588b6cb52d
files configure src/if-sun.c src/if.c src/if.h
diffstat 4 files changed, 133 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/configure	Sun Apr 14 12:53:25 2019 +0300
+++ b/configure	Sun Apr 14 12:54:16 2019 +0300
@@ -454,7 +454,7 @@
 	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
--- a/src/if-sun.c	Sun Apr 14 12:53:25 2019 +0300
+++ b/src/if-sun.c	Sun Apr 14 12:54:16 2019 +0300
@@ -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>
@@ -163,6 +165,63 @@
 }
 
 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 @@
 {
 	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 (ioctl(fd, SIOCSLIFFLAGS, &lifr) == -1)
 			return -1;
 	}
+
 	return 0;
 }
 
@@ -847,15 +910,20 @@
 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;
 
-	memset(&lifr, 0, sizeof(lifr));
+	if (if_nametospec(ifname, &spec) == -1)
+		return -1;
+
 	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 @@
 		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 @@
 	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 (errno != EINVAL)
 		goto out;
+	if(ioctl(mux_fd, I_PUSH, ARP_MOD_NAME) == -1)
+		goto out;
 
-	if (lifr.lifr_flags & IFF_IPV4 && !(lifr.lifr_flags & IFF_NOARP)) {
-		if (ioctl(mux_fd, I_PUSH, ARP_MOD_NAME) == -1)
+	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;
 	}
 
-	/* PLINK the interface stream so it persists. */
-	if (ioctl(mux_fd, I_PLINK, fd) == -1)
+	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;
--- a/src/if.c	Sun Apr 14 12:53:25 2019 +0300
+++ b/src/if.c	Sun Apr 14 12:54:16 2019 +0300
@@ -136,9 +136,15 @@
 
 	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 @@
 #else
 	r = ifr.ifr_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN;
 #endif
+#endif /* __sun */
 	return r;
 }
 
@@ -711,6 +718,11 @@
 	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;
--- a/src/if.h	Sun Apr 14 12:53:25 2019 +0300
+++ b/src/if.h	Sun Apr 14 12:54:16 2019 +0300
@@ -129,6 +129,9 @@
 #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.