/* ndflagset: set ND6_IFF_ACCEPT_RTADV on an interface via SIOCSIFINFO_IN6.
 * The global sysctl net.inet6.ip6.accept_rtadv only takes effect at
 * interface-attach time (nd6_ifattach, nd6.c:210); this sets the live
 * per-interface flag so already-attached interfaces accept Router Adverts.
 * Usage: ndflagset <ifname>   (must run as root) */
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv) {
    if (argc < 2) { fprintf(stderr, "usage: %s ifname\n", argv[0]); return 2; }
    int s = socket(AF_INET6, SOCK_DGRAM, 0);
    if (s < 0) { perror("socket"); return 2; }
    struct in6_ndireq nd;
    memset(&nd, 0, sizeof(nd));
    strncpy(nd.ifname, argv[1], IFNAMSIZ);
    if (ioctl(s, SIOCGIFINFO_IN6, &nd) < 0) { perror("SIOCGIFINFO_IN6"); return 2; }
    printf("before: flags=0x%x\n", nd.ndi.flags);
    nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV | ND6_IFF_PERFORMNUD;
    /* SIOCSIFINFO_IN6 treats 0 fields as 'unspecified'; clear mtu/etc */
    nd.ndi.linkmtu = 0; nd.ndi.basereachable = 0; nd.ndi.retrans = 0; nd.ndi.chlim = 0;
    if (ioctl(s, SIOCSIFINFO_IN6, &nd) < 0) { perror("SIOCSIFINFO_IN6"); return 2; }
    /* re-read */
    memset(&nd, 0, sizeof(nd));
    strncpy(nd.ifname, argv[1], IFNAMSIZ);
    ioctl(s, SIOCGIFINFO_IN6, &nd);
    printf("after:  flags=0x%x (ACCEPT_RTADV=%d)\n", nd.ndi.flags,
        !!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV));
    return 0;
}
