From 038918b0d7c1edab7f866039faef6042c337edf9 Mon Sep 17 00:00:00 2001 From: suz Date: Sat, 5 Nov 2005 10:50:09 +0000 Subject: [PATCH] MFC: added an ioctl option in kernel so that ndp/rtadvd can change some NDP-related kernel variables based on their configurations (RFC2461 p.43 6.2.1 mandates this for IPv6 routers) Revision Changes Path 1.56 +1 -0 src/sys/netinet6/in6.c 1.26 +1 -0 src/sys/netinet6/in6_var.h 1.57 +28 -0 src/sys/netinet6/nd6.c 1.17 +21 -8 src/usr.sbin/ndp/ndp.8 1.17 +31 -2 src/usr.sbin/ndp/ndp.c 1.25 +30 -0 src/usr.sbin/rtadvd/config.c --- sys/netinet6/in6.c | 1 + sys/netinet6/in6_var.h | 1 + sys/netinet6/nd6.c | 30 ++++++++++++++++++++++++++++++ usr.sbin/ndp/ndp.8 | 29 +++++++++++++++++++++-------- usr.sbin/ndp/ndp.c | 33 +++++++++++++++++++++++++++++++-- usr.sbin/rtadvd/config.c | 30 ++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 10 deletions(-) diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 463d8aa073c5..013bfa025999 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -364,6 +364,7 @@ in6_control(so, cmd, data, ifp, td) /* FALLTHROUGH */ case OSIOCGIFINFO_IN6: case SIOCGIFINFO_IN6: + case SIOCSIFINFO_IN6: case SIOCGDRLST_IN6: case SIOCGPRLST_IN6: case SIOCGNBRINFO_IN6: diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index 34f52fde88ea..a718c2dc085e 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -404,6 +404,7 @@ struct in6_rrenumreq { #define OSIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ondireq) #endif #define SIOCGIFINFO_IN6 _IOWR('i', 108, struct in6_ndireq) +#define SIOCSIFINFO_IN6 _IOWR('i', 109, struct in6_ndireq) #define SIOCSNDFLUSH_IN6 _IOWR('i', 77, struct in6_ifreq) #define SIOCGNBRINFO_IN6 _IOWR('i', 78, struct in6_nbrinfo) #define SIOCSPFXFLUSH_IN6 _IOWR('i', 79, struct in6_ifreq) diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 0707a29ca428..44228fd817ec 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1426,6 +1426,7 @@ nd6_ioctl(cmd, data, ifp) break; case OSIOCGIFINFO_IN6: +#define ND ndi->ndi /* XXX: old ndp(8) assumes a positive value for linkmtu. */ bzero(&ndi->ndi, sizeof(ndi->ndi)); ndi->ndi.linkmtu = IN6_LINKMTU(ifp); @@ -1441,9 +1442,38 @@ nd6_ioctl(cmd, data, ifp) ndi->ndi = *ND_IFINFO(ifp); ndi->ndi.linkmtu = IN6_LINKMTU(ifp); break; + case SIOCSIFINFO_IN6: + /* + * used to change host variables from userland. + * intented for a use on router to reflect RA configurations. + */ + /* 0 means 'unspecified' */ + if (ND.linkmtu != 0) { + if (ND.linkmtu < IPV6_MMTU || + ND.linkmtu > IN6_LINKMTU(ifp)) { + error = EINVAL; + break; + } + ND_IFINFO(ifp)->linkmtu = ND.linkmtu; + } + + if (ND.basereachable != 0) { + int obasereachable = ND_IFINFO(ifp)->basereachable; + + ND_IFINFO(ifp)->basereachable = ND.basereachable; + if (ND.basereachable != obasereachable) + ND_IFINFO(ifp)->reachable = + ND_COMPUTE_RTIME(ND.basereachable); + } + if (ND.retrans != 0) + ND_IFINFO(ifp)->retrans = ND.retrans; + if (ND.chlim != 0) + ND_IFINFO(ifp)->chlim = ND.chlim; + /* FALLTHROUGH */ case SIOCSIFINFO_FLAGS: ND_IFINFO(ifp)->flags = ndi->ndi.flags; break; +#undef ND case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ /* flush default router list */ /* diff --git a/usr.sbin/ndp/ndp.8 b/usr.sbin/ndp/ndp.8 index 9d853827c0ea..4d99527d781f 100644 --- a/usr.sbin/ndp/ndp.8 +++ b/usr.sbin/ndp/ndp.8 @@ -63,7 +63,7 @@ .Op Fl nt .Fl i .Ar interface -.Op Ar flags ... +.Op Ar expressions ... .Nm .Op Fl nt .Fl I Op Ar interface | Li delete @@ -153,19 +153,20 @@ The will be used as the default. .It Fl I Li delete The current default interface will be deleted from the kernel. -.It Fl i Ar interface Op Ar flags ... +.It Fl i Ar interface Op Ar expressions ... View ND information for the specified interface. If additional arguments -.Ar flags +.Ar expressions are given, .Nm -sets or clears the specified flags for the interface. -Each flag should be separated by white spaces or tab characters. -Possible flags are as follows. -All of the flags can begin with the +sets or clears the flags or variables for the interface as specified in +the expression. +Each expression should be separated by white spaces or tab characters. +Possible expressions are as follows. +Some of the expressions can begin with the special character .Ql - , -which means the flag should be cleared. +which means the flag specified in the expression should be cleared. Note that you need .Fl - before @@ -209,6 +210,18 @@ a certain failure of Duplicate Address Detection. While the flag can be set or cleared by hand with the .Nm command, it is not generally advisable to modify this flag manually. +.It Xo +.Ic basereachable=(number) +.Xc +Specify the BaseReachbleTimer on the interface in millisecond. +.It Xo +.Ic retrans=(number) +.Xc +Specify the RetransTimer on the interface in millisecond. +.It Xo +.Ic curhlim=(number) +.Xc +Specify the Cur Hop Limit on the interface. .El .It Fl n Do not try to resolve numeric addresses to hostnames. diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c index 9287f9a4efe4..5068ce9a761a 100644 --- a/usr.sbin/ndp/ndp.c +++ b/usr.sbin/ndp/ndp.c @@ -969,6 +969,27 @@ ifinfo(ifname, argc, argv) newflags |= (f);\ }\ } while (0) +/* + * XXX: this macro is not 100% correct, in that it matches "nud" against + * "nudbogus". But we just let it go since this is minor. + */ +#define SETVALUE(f, v) \ + do { \ + char *valptr; \ + unsigned long newval; \ + v = 0; /* unspecified */ \ + if (strncmp(cp, f, strlen(f)) == 0) { \ + valptr = strchr(cp, '='); \ + if (valptr == NULL) \ + err(1, "syntax error in %s field", (f)); \ + errno = 0; \ + newval = strtoul(++valptr, NULL, 0); \ + if (errno) \ + err(1, "syntax error in %s's value", (f)); \ + v = newval; \ + } \ + } while (0) + SETFLAG("disabled", ND6_IFF_IFDISABLED); SETFLAG("nud", ND6_IFF_PERFORMNUD); #ifdef ND6_IFF_ACCEPT_RTADV @@ -977,13 +998,17 @@ ifinfo(ifname, argc, argv) #ifdef ND6_IFF_PREFER_SOURCE SETFLAG("prefer_source", ND6_IFF_PREFER_SOURCE); #endif + SETVALUE("basereachable", ND.basereachable); + SETVALUE("retrans", ND.retrans); + SETVALUE("curhlim", ND.chlim); ND.flags = newflags; - if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) { - err(1, "ioctl(SIOCSIFINFO_FLAGS)"); + if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) { + err(1, "ioctl(SIOCSIFINFO_IN6)"); /* NOTREACHED */ } #undef SETFLAG +#undef SETVALUE } if (!ND.initialized) { @@ -991,6 +1016,10 @@ ifinfo(ifname, argc, argv) /* NOTREACHED */ } + if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { + err(1, "ioctl(SIOCGIFINFO_IN6)"); + /* NOTREACHED */ + } printf("linkmtu=%d", ND.linkmtu); printf(", maxmtu=%d", ND.maxmtu); printf(", curhlim=%d", ND.chlim); diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index 09e4eac659b5..e9e3b97246c9 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -407,6 +408,35 @@ getconfig(intface) exit(1); } +#ifdef SIOCSIFINFO_IN6 + { + struct in6_ndireq ndi; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "<%s> socket: %s", __func__, + strerror(errno)); + exit(1); + } + memset(&ndi, 0, sizeof(ndi)); + strncpy(ndi.ifname, intface, IFNAMSIZ); + if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) { + syslog(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s", + __func__, intface, strerror(errno)); + } + + /* reflect the RA info to the host variables in kernel */ + ndi.ndi.chlim = tmp->hoplimit; + ndi.ndi.retrans = tmp->retranstimer; + ndi.ndi.basereachable = tmp->reachabletime; + if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) { + syslog(LOG_INFO, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s", + __func__, intface, strerror(errno)); + } + close(s); + } +#endif + /* route information */ #ifdef ROUTEINFO tmp->routes = 0;