*/
#include <sys/ioctl.h>
+#include <sys/tihdr.h>
#include <sys/utsname.h>
#include <errno.h>
+#include <fcntl.h>
#include <ifaddrs.h>
#include <libdlpi.h>
#include <stdlib.h>
+#include <stropts.h>
#include <string.h>
#include <unistd.h>
+#include <inet/ip.h>
+
#include <net/if_dl.h>
#include <net/if_types.h>
if_opensockets_os(struct dhcpcd_ctx *ctx)
{
- return 0;
+ ctx->link_fd = socket(PF_ROUTE,
+ SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+ return ctx->link_fd == -1 ? -1 : 0;
}
void
if_closesockets_os(struct dhcpcd_ctx *ctx)
{
+ UNUSED(ctx);
}
int
if_getssid(struct interface *ifp)
{
+ UNUSED(ifp);
errno = ENOTSUP;
return -1;
}
if_managelink(struct dhcpcd_ctx *ctx)
{
+ UNUSED(ctx);
errno = ENOTSUP;
return -1;
}
if_machinearch(char *str, size_t len)
{
+ UNUSED(str);
+ UNUSED(len);
errno = ENOTSUP;
return -1;
}
dlpi_handle_t dh;
dlpi_info_t dlinfo;
uint8_t pa[DLPI_PHYSADDR_MAX];
- unsigned int pa_len;
+ size_t pa_len;
struct sockaddr_dl *sdl;
ifa = NULL;
int
if_getifaddrs(struct ifaddrs **ifap)
{
- struct linkwalk lw = { NULL, 0 };
- int error;
+ struct linkwalk lw = { NULL, 0 };
- error = 0;
dlpi_walk(if_newaddr, &lw, 0);
if (lw.lw_error != 0) {
freeifaddrs(lw.lw_ifa);
return 0;
}
+static void
+if_octetstr(char *buf, const Octet_t *o, ssize_t len)
+{
+ int i;
+ char *p;
+
+ p = buf;
+ for (i = 0; i < o->o_length; i++) {
+ if ((p + 1) - buf < len)
+ *p++ = o->o_bytes[i];
+ }
+ *p = '\0';
+}
+
+static int
+if_parsert(struct dhcpcd_ctx *ctx, unsigned int level, unsigned int name,
+ int (*walkrt)(struct dhcpcd_ctx *, char *, size_t))
+{
+ int s, retval, code, flags;
+ uintptr_t buf[512 / sizeof(uintptr_t)];
+ struct strbuf ctlbuf, databuf;
+ struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf;
+ struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf;
+ struct T_error_ack *tea = (struct T_error_ack *)buf;
+ struct opthdr *req;
+
+ if ((s = open("/dev/arp", O_RDWR)) == -1)
+ return -1;
+
+ tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
+ tor->OPT_offset = sizeof (struct T_optmgmt_req);
+ tor->OPT_length = sizeof (struct opthdr);
+ tor->MGMT_flags = T_CURRENT;
+
+ req = (struct opthdr *)&tor[1];
+ req->level = EXPER_IP_AND_ALL_IRES;
+ req->name = 0;
+ req->len = 1;
+
+ ctlbuf.buf = (char *)buf;
+ ctlbuf.len = tor->OPT_length + tor->OPT_offset;
+ if (putmsg(s, &ctlbuf, NULL, 0) == 1) {
+ close(s);
+ return -1;
+ }
+
+ req = (struct opthdr *)&toa[1];
+ ctlbuf.maxlen = sizeof(buf);
+
+ retval = -1;
+ for (;;) {
+ flags = 0;
+ if ((code = getmsg(s, &ctlbuf, 0, &flags)) == -1)
+ break;
+ if (code == 0 &&
+ toa->PRIM_type == T_OPTMGMT_ACK &&
+ toa->MGMT_flags == T_SUCCESS &&
+ (size_t)ctlbuf.len >= sizeof(struct T_optmgmt_ack))
+ {
+ retval = 0;
+ break;
+ }
+ if (tea->PRIM_type == T_ERROR_ACK) {
+ errno = tea->TLI_error == TSYSERR ?
+ tea->UNIX_error : EPROTO;
+ break;
+ }
+ if (code != MOREDATA ||
+ toa->PRIM_type != T_OPTMGMT_ACK ||
+ toa->MGMT_flags != T_SUCCESS)
+ {
+ errno = ENOMSG;
+ break;
+ }
+
+ databuf.maxlen = req->len;
+ if ((databuf.buf = malloc(databuf.maxlen)) == NULL)
+ break;
+
+ flags = 0;
+ if (getmsg(s, NULL, &databuf, &flags) == -1) {
+ free(databuf.buf);
+ break;
+ }
+
+ if (req->level == level && req->name == name) {
+ if (walkrt(ctx, databuf.buf, databuf.len) == -1) {
+ free(databuf.buf);
+ break;
+ }
+ }
+
+ free(databuf.buf);
+ }
+
+ close(s);
+ return retval;
+}
+
#ifdef INET
const char *if_pfname = "SunOS";
if_openrawsocket(struct interface *ifp, uint16_t protocol)
{
+ UNUSED(ifp);
+ UNUSED(protocol);
errno = ENOTSUP;
return -1;
}
const void *data, size_t len)
{
+ UNUSED(ifp);
+ UNUSED(protocol);
+ UNUSED(data);
+ UNUSED(len);
errno = ENOTSUP;
return -1;
}
void *data, size_t len, int *flags)
{
+ UNUSED(ifp);
+ UNUSED(protocol);
+ UNUSED(data);
+ UNUSED(len);
+ UNUSED(flags);
errno = ENOTSUP;
return -1;
}
int
-if_address(const struct interface *iface, const struct in_addr *addr,
+if_address(const struct interface *ifp, const struct in_addr *addr,
const struct in_addr *net, const struct in_addr *bcast,
int action)
{
+ UNUSED(ifp);
+ UNUSED(addr);
+ UNUSED(net);
+ UNUSED(bcast);
+ UNUSED(action);
errno = ENOTSUP;
return -1;
}
if_addrflags(const struct in_addr *addr, const struct interface *ifp)
{
+ UNUSED(addr);
+ UNUSED(ifp);
errno = ENOTSUP;
return -1;
}
if_route(unsigned char cmd, const struct rt *rt)
{
+ UNUSED(cmd);
+ UNUSED(rt);
errno = ENOTSUP;
return -1;
}
+static int
+if_walkrt(struct dhcpcd_ctx *ctx, char *data, size_t len)
+{
+ mib2_ipRouteEntry_t *re, *e;
+ struct rt rt;
+ char ifname[IF_NAMESIZE];
+
+ if (len % sizeof(*re) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ re = (mib2_ipRouteEntry_t *)data;
+ e = (mib2_ipRouteEntry_t *)(data + len);
+ do {
+ /* Skip route types we don't want. */
+ switch (re->ipRouteInfo.re_ire_type) {
+ case IRE_IF_CLONE:
+ case IRE_BROADCAST:
+ case IRE_MULTICAST:
+ case IRE_NOROUTE:
+ case IRE_LOCAL:
+ continue;
+ default:
+ break;
+ }
+ memset(&rt, 0, sizeof(rt));
+ rt.dest.s_addr = re->ipRouteDest;
+ rt.net.s_addr = re->ipRouteMask;
+ rt.gate.s_addr = re->ipRouteNextHop;
+ rt.flags = re->ipRouteInfo.re_flags;
+ rt.src.s_addr = re->ipRouteInfo.re_src_addr;
+ rt.mtu = re->ipRouteInfo.re_max_frag;
+
+ if_octetstr(ifname, &re->ipRouteIfIndex, sizeof(ifname));
+ rt.iface = if_find(ctx->ifaces, ifname);
+ if (rt.iface != NULL)
+ ipv4_handlert(ctx, RTM_ADD, &rt, 1);
+ else
+ printf ("XX %s\n", ifname);
+ } while (++re < e);
+ return 0;
+}
+
int
-if_initrt(struct interface *ifp)
+if_initrt(struct dhcpcd_ctx *ctx)
{
- errno = ENOTSUP;
- return -1;
+ ipv4_freerts(ctx->ipv4_kroutes);
+ return if_parsert(ctx, MIB2_IP,MIB2_IP_ROUTE, if_walkrt);
}
#endif
#ifdef INET6
int
-if_address6(const struct ipv6_addr *a, int action)
+if_address6(const struct ipv6_addr *addr, int action)
{
+ UNUSED(addr);
+ UNUSED(action);
errno = ENOTSUP;
return -1;
}
if_addrflags6(const struct in6_addr *addr, const struct interface *ifp)
{
+ UNUSED(addr);
+ UNUSED(ifp);
errno = ENOTSUP;
return -1;
}
if_getlifetime6(struct ipv6_addr *addr)
{
+ UNUSED(addr);
errno = ENOTSUP;
return -1;
}
if_route6(unsigned char cmd, const struct rt6 *rt)
{
+ UNUSED(cmd);
+ UNUSED(rt);
errno = ENOTSUP;
return -1;
}
+static int
+if_walkrt6(struct dhcpcd_ctx *ctx, char *data, size_t len)
+{
+ mib2_ipv6RouteEntry_t *re, *e;
+ struct rt6 rt;
+ char ifname[IF_NAMESIZE];
+
+ if (len % sizeof(*re) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ re = (mib2_ipv6RouteEntry_t *)data;
+ e = (mib2_ipv6RouteEntry_t *)(data + len);
+
+ do {
+ /* Skip route types we don't want. */
+ switch (re->ipv6RouteInfo.re_ire_type) {
+ case IRE_IF_CLONE:
+ case IRE_BROADCAST:
+ case IRE_MULTICAST:
+ case IRE_NOROUTE:
+ case IRE_LOCAL:
+ continue;
+ default:
+ break;
+ }
+ memset(&rt, 0, sizeof(rt));
+ rt.dest = re->ipv6RouteDest;
+ ipv6_mask(&rt.net, re->ipv6RoutePfxLength);
+ rt.gate = re->ipv6RouteNextHop;
+ rt.mtu = re->ipv6RouteInfo.re_max_frag;
+
+ if_octetstr(ifname, &re->ipv6RouteIfIndex, sizeof(ifname));
+ rt.iface = if_find(ctx->ifaces, ifname);
+ if (rt.iface != NULL)
+ ipv6_handlert(ctx, RTM_ADD, &rt);
+ else
+ printf ("XX %s\n", ifname);
+ } while (++re < e);
+ return 0;
+}
+
int
-if_initrt6(struct interface *ifp)
+if_initrt6(struct dhcpcd_ctx *ctx)
{
- errno = ENOTSUP;
- return -1;
+ ipv6_freerts(&ctx->ipv6->kroutes);
+ return if_parsert(ctx, MIB2_IP6, MIB2_IP6_ROUTE, if_walkrt6);
}
int
-if_checkipv6(struct dhcpcd_ctx *ctx, const struct interface *ifp, int own)
+if_checkipv6(__unused struct dhcpcd_ctx *ctx,
+ __unused const struct interface *ifp, int __unused own)
{
- errno = ENOTSUP;
- return -1;
+ return 0;
}
#endif