]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Learn about routing tables on Solaris.
authorRoy Marples <roy@marples.name>
Thu, 12 May 2016 16:51:36 +0000 (16:51 +0000)
committerRoy Marples <roy@marples.name>
Thu, 12 May 2016 16:51:36 +0000 (16:51 +0000)
if-sun.c

index bef4f59aeef6a5aa2776358b9b3e0ae16b64a31d..b7c7a33c96831d91910246caf8655be6b2c73469 100644 (file)
--- a/if-sun.c
+++ b/if-sun.c
  */
 
 #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>
 
@@ -65,19 +70,23 @@ int
 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;
 }
@@ -93,6 +102,7 @@ int
 if_managelink(struct dhcpcd_ctx *ctx)
 {
 
+       UNUSED(ctx);
        errno = ENOTSUP;
        return -1;
 }
@@ -101,6 +111,8 @@ int
 if_machinearch(char *str, size_t len)
 {
 
+       UNUSED(str);
+       UNUSED(len);
        errno = ENOTSUP;
        return -1;
 }
@@ -118,7 +130,7 @@ if_newaddr(const char *ifname, void *arg)
        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;
@@ -182,10 +194,8 @@ failed1:
 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);
@@ -197,6 +207,105 @@ if_getifaddrs(struct ifaddrs **ifap)
        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";
 
@@ -204,6 +313,8 @@ int
 if_openrawsocket(struct interface *ifp, uint16_t protocol)
 {
 
+       UNUSED(ifp);
+       UNUSED(protocol);
        errno = ENOTSUP;
        return -1;
 }
@@ -213,6 +324,10 @@ if_sendrawpacket(const struct interface *ifp, uint16_t protocol,
     const void *data, size_t len)
 {
 
+       UNUSED(ifp);
+       UNUSED(protocol);
+       UNUSED(data);
+       UNUSED(len);
        errno = ENOTSUP;
        return -1;
 }
@@ -222,16 +337,26 @@ if_readrawpacket(struct interface *ifp, uint16_t protocol,
     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;
 }
@@ -240,6 +365,8 @@ int
 if_addrflags(const struct in_addr *addr, const struct interface *ifp)
 {
 
+       UNUSED(addr);
+       UNUSED(ifp);
        errno = ENOTSUP;
        return -1;
 }
@@ -248,24 +375,72 @@ int
 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;
 }
@@ -274,6 +449,8 @@ int
 if_addrflags6(const struct in6_addr *addr, const struct interface *ifp)
 {
 
+       UNUSED(addr);
+       UNUSED(ifp);
        errno = ENOTSUP;
        return -1;
 }
@@ -282,6 +459,7 @@ int
 if_getlifetime6(struct ipv6_addr *addr)
 {
 
+       UNUSED(addr);
        errno = ENOTSUP;
        return -1;
 }
@@ -290,23 +468,68 @@ int
 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