summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCody Peter Mello <cody.mello@joyent.com>2016-02-26 08:52:54 -0800
committerRobert Mustacchi <rm@joyent.com>2016-03-23 21:57:43 -0700
commit797f979d1fe26bfb1cdeb3e7a86ed24c0b654200 (patch)
tree0438fca8beae8ebed526339f97afec565c777030
parent23db4d6f668fd45f22b6b1fb668988cdf671a67b (diff)
downloadillumos-joyent-797f979d1fe26bfb1cdeb3e7a86ed24c0b654200.tar.gz
6684 Allow sending from IPv6 SLAAC addresses within a zone using IP spoofing protection
Reviewed by: Robert Mustacchi <rm@joyent.com> Approved by: Dan McDonald <danmcd@omniti.com>
-rw-r--r--usr/src/pkg/manifests/system-test-ostest.mf1
-rw-r--r--usr/src/test/os-tests/tests/Makefile2
-rw-r--r--usr/src/test/os-tests/tests/spoof-ras/Makefile57
-rw-r--r--usr/src/test/os-tests/tests/spoof-ras/spoof-ras.c683
-rw-r--r--usr/src/uts/common/io/mac/mac_client.c6
-rw-r--r--usr/src/uts/common/io/mac/mac_datapath_setup.c4
-rw-r--r--usr/src/uts/common/io/mac/mac_protect.c339
-rw-r--r--usr/src/uts/common/io/mac/mac_sched.c4
-rw-r--r--usr/src/uts/common/sys/mac_client_impl.h4
-rw-r--r--usr/src/uts/common/sys/mac_impl.h6
10 files changed, 1061 insertions, 45 deletions
diff --git a/usr/src/pkg/manifests/system-test-ostest.mf b/usr/src/pkg/manifests/system-test-ostest.mf
index 0858f94612..fde9d5bb0a 100644
--- a/usr/src/pkg/manifests/system-test-ostest.mf
+++ b/usr/src/pkg/manifests/system-test-ostest.mf
@@ -32,6 +32,7 @@ file path=opt/os-tests/runfiles/omnios.run mode=0444
file path=opt/os-tests/runfiles/openindiana.run mode=0444
file path=opt/os-tests/tests/poll_test mode=0555
file path=opt/os-tests/tests/sigqueue/sigqueue_queue_size mode=0555
+file path=opt/os-tests/tests/spoof-ras mode=0555
license cr_Sun license=cr_Sun
license lic_CDDL license=lic_CDDL
depend fmri=system/test/testrunner type=require
diff --git a/usr/src/test/os-tests/tests/Makefile b/usr/src/test/os-tests/tests/Makefile
index f3958afd29..cd4104500c 100644
--- a/usr/src/test/os-tests/tests/Makefile
+++ b/usr/src/test/os-tests/tests/Makefile
@@ -13,6 +13,6 @@
# Copyright (c) 2012 by Delphix. All rights reserved.
#
-SUBDIRS = poll sigqueue
+SUBDIRS = poll sigqueue spoof-ras
include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/os-tests/tests/spoof-ras/Makefile b/usr/src/test/os-tests/tests/spoof-ras/Makefile
new file mode 100644
index 0000000000..c629a03594
--- /dev/null
+++ b/usr/src/test/os-tests/tests/spoof-ras/Makefile
@@ -0,0 +1,57 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2015 by Joyent, Inc. All rights reserved.
+#
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+PROG = spoof-ras
+OBJS = $(PROG:%=%.o)
+SRCS = $(OBJS:%.o=%.c)
+
+LDLIBS += -lsocket -lnsl
+C99MODE = -xc99=%all
+
+ROOTOPTPKG = $(ROOT)/opt/os-tests
+TESTDIR = $(ROOTOPTPKG)/tests
+
+CMDS = $(PROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+%.o: ../%.c
+ $(COMPILE.c) $<
+
+install: all $(CMDS)
+
+lint: lint_SRCS
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+ -$(RM) $(OBJS)
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/test/os-tests/tests/spoof-ras/spoof-ras.c b/usr/src/test/os-tests/tests/spoof-ras/spoof-ras.c
new file mode 100644
index 0000000000..e36f084f64
--- /dev/null
+++ b/usr/src/test/os-tests/tests/spoof-ras/spoof-ras.c
@@ -0,0 +1,683 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc. All rights reserved.
+ */
+
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <err.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <signal.h>
+#include <netinet/in_systm.h> /* legacy network types needed by ip_icmp.h */
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <priv.h>
+
+/*
+ * This program is meant to test the behaviour of processing incoming Router
+ * Advertisements when IP spoofing protection (ip-nospoof) is enabled. When
+ * run, it creates an etherstub on which it places two VNICs: a source VNIC,
+ * and a destination VNIC with protection enabled. It then sends out spoofed
+ * Router Advertisements with varying incorrect values.
+ *
+ * IMPORTANT: These tests expect that there is no other IPv6 traffic on the
+ * machine that would be delivered to a VNIC with spoofing protection enabled,
+ * since this would trip the DTrace probes installed by this suite of tests.
+ * Care should therefore be taken to not run it as a part of any series of
+ * tests which may be executed in such an environment, as it could lead to
+ * spurious failures.
+ */
+
+#define DLADM(args...) spoof_run_proc("/usr/sbin/dladm", \
+ (char *[]) { "dladm", args, NULL })
+#define IFCONFIG(args...) spoof_run_proc("/usr/sbin/ifconfig", \
+ (char *[]) { "ifconfig", args, NULL })
+
+typedef struct sockaddr_in6 sin6_t;
+typedef int (spoof_test_f)(int, struct lif_nd_req *, sin6_t *);
+
+/*
+ * Get the link-layer address of the given interface by querying
+ * the neighbour cache.
+ */
+static int
+spoof_get_lla(int s, const char *iface, struct lifreq *addrp,
+ struct lifreq *llap)
+{
+ if (strstr(iface, ":")) {
+ warnx("Specified interface should be the zeroth "
+ "logical interface on the physical device.");
+ }
+
+ bzero(addrp, sizeof (*addrp));
+ bzero(llap, sizeof (*llap));
+
+ (void) strlcpy(addrp->lifr_name, iface, LIFNAMSIZ);
+ if (ioctl(s, SIOCGLIFADDR, addrp) < 0) {
+ warn("Unable to get link-local address");
+ return (-1);
+ }
+
+ (void) strlcpy(llap->lifr_name, iface, LIFNAMSIZ);
+ bcopy(&addrp->lifr_addr, &llap->lifr_nd.lnr_addr,
+ sizeof (struct sockaddr_storage));
+
+ if (ioctl(s, SIOCLIFGETND, llap) < 0) {
+ warn("Failed to get link-layer address");
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+spoof_prepare_lla(struct nd_opt_lla *llap, struct lif_nd_req *nce,
+ struct iovec *iov)
+{
+ uint_t optlen;
+
+ bzero(llap, sizeof (*llap));
+ llap->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR;
+ optlen = ((sizeof (struct nd_opt_hdr) +
+ nce->lnr_hdw_len + 7) / 8) * 8;
+ llap->nd_opt_lla_len = optlen / 8;
+ bcopy(&nce->lnr_hdw_addr,
+ &llap->nd_opt_lla_hdw_addr, nce->lnr_hdw_len);
+
+ iov->iov_base = (caddr_t)llap;
+ iov->iov_len = optlen;
+}
+
+static void
+spoof_prepare_pi(const char *prefix, int prefix_len,
+ struct nd_opt_prefix_info *pip, struct iovec *iov)
+{
+ bzero(pip, sizeof (*pip));
+
+ pip->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
+ pip->nd_opt_pi_len = 4;
+ pip->nd_opt_pi_prefix_len = prefix_len;
+ pip->nd_opt_pi_flags_reserved =
+ ND_OPT_PI_FLAG_AUTO | ND_OPT_PI_FLAG_ONLINK;
+ pip->nd_opt_pi_valid_time = 86400;
+ pip->nd_opt_pi_preferred_time = 86400;
+ if (inet_pton(AF_INET6, prefix, &pip->nd_opt_pi_prefix) == 0) {
+ errx(EXIT_FAILURE, "The prefix \"%s\" is "
+ "not a valid input prefix", prefix);
+ }
+
+ iov->iov_base = (caddr_t)pip;
+ iov->iov_len = sizeof (*pip);
+}
+
+static void
+spoof_prepare_header(struct nd_router_advert *ichdrp, struct iovec *iov)
+{
+ bzero(ichdrp, sizeof (*ichdrp));
+
+ ichdrp->nd_ra_type = ND_ROUTER_ADVERT;
+ ichdrp->nd_ra_curhoplimit = 0;
+
+ iov->iov_base = (caddr_t)ichdrp;
+ iov->iov_len = sizeof (*ichdrp);
+}
+
+static int
+spoof_set_max_hops(int s)
+{
+ int ttl = 255;
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ (char *)&ttl, sizeof (ttl)) < 0) {
+ warn("Failed to set IPV6_UNICAST_HOPS socket option");
+ return (-1);
+ }
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ (char *)&ttl, sizeof (ttl)) < 0) {
+ warn("Failed to set IPV6_UNICAST_HOPS socket option");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Send bad option lengths in the Link-Layer Source Address option
+ */
+static int
+spoof_bad_lla_optlen_test(int s, struct lif_nd_req *nce, sin6_t *multicast)
+{
+ struct msghdr msg6;
+ struct iovec iovs[3];
+ struct nd_router_advert ichdr;
+ struct nd_opt_lla lla;
+ struct nd_opt_prefix_info pi;
+ uint8_t old_lla_len;
+
+ spoof_prepare_header(&ichdr, &iovs[0]);
+ spoof_prepare_lla(&lla, nce, &iovs[1]);
+ spoof_prepare_pi("fd00::", 64, &pi, &iovs[2]);
+
+ /* Prepare message */
+ bzero(&msg6, sizeof (struct msghdr));
+ msg6.msg_name = multicast;
+ msg6.msg_namelen = sizeof (sin6_t);
+ msg6.msg_iov = iovs;
+ msg6.msg_iovlen = 3;
+
+ old_lla_len = lla.nd_opt_lla_len;
+
+
+ /*
+ * Length is now smaller than the option is, so this should
+ * be rejected.
+ */
+ lla.nd_opt_lla_len = 0;
+ if (sendmsg(s, &msg6, 0) < 0) {
+ warn("Failed to send ICMPv6 message");
+ return (-1);
+ }
+
+ /*
+ * Length is bigger than the option, so the following prefix
+ * will be offset.
+ */
+ lla.nd_opt_lla_len = 2;
+ if (sendmsg(s, &msg6, 0) < 0) {
+ warn("Failed to send ICMPv6 message");
+ return (-1);
+ }
+
+ /*
+ * Restore the length, but shorten the amount of data to send, so we're
+ * sending truncated packets. (Stop before 0, so that we still send part
+ * of the option.)
+ */
+ lla.nd_opt_lla_len = old_lla_len;
+ for (iovs[1].iov_len--; iovs[1].iov_len > 0; iovs[1].iov_len--) {
+ if (sendmsg(s, &msg6, 0) < 0) {
+ warn("Failed to send ICMPv6 message");
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Send bad option lengths in the Prefix Information option
+ */
+static int
+spoof_bad_pi_optlen_test(int s, struct lif_nd_req *nce, sin6_t *multicast)
+{
+ struct msghdr msg6;
+ struct iovec iovs[3];
+ struct nd_router_advert ichdr;
+ struct nd_opt_lla lla;
+ struct nd_opt_prefix_info pi;
+ uint8_t old_pi_len;
+
+ spoof_prepare_header(&ichdr, &iovs[0]);
+ spoof_prepare_lla(&lla, nce, &iovs[1]);
+ spoof_prepare_pi("fd00::", 64, &pi, &iovs[2]);
+
+ /* Prepare message */
+ bzero(&msg6, sizeof (struct msghdr));
+ msg6.msg_name = multicast;
+ msg6.msg_namelen = sizeof (sin6_t);
+ msg6.msg_iov = iovs;
+ msg6.msg_iovlen = 3;
+
+ old_pi_len = pi.nd_opt_pi_len;
+
+ /*
+ * Length is now smaller than the option is, so this should
+ * be rejected.
+ */
+ pi.nd_opt_pi_len = 0;
+ if (sendmsg(s, &msg6, 0) < 0) {
+ warn("Failed to send ICMPv6 message");
+ return (-1);
+ }
+
+ /*
+ * Length is smaller than a PI option should be.
+ */
+ pi.nd_opt_pi_len = 3;
+ if (sendmsg(s, &msg6, 0) < 0) {
+ warn("Failed to send ICMPv6 message");
+ return (-1);
+ }
+
+ /*
+ * Length is bigger than the option, so the following prefix
+ * will be offset.
+ */
+ pi.nd_opt_pi_len = 5;
+ if (sendmsg(s, &msg6, 0) < 0) {
+ warn("Failed to send ICMPv6 message");
+ return (-1);
+ }
+
+ /*
+ * Restore the length, but shorten the amount of data to send, so we're
+ * sending truncated packets. (Stop before 0, so that we still send part
+ * of the option.)
+ */
+ pi.nd_opt_pi_len = old_pi_len;
+ for (iovs[2].iov_len--; iovs[2].iov_len > 0; iovs[2].iov_len--) {
+ if (sendmsg(s, &msg6, 0) < 0) {
+ warn("Failed to send ICMPv6 message");
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Advertise a prefix with a prefix length greater than 128.
+ */
+static int
+spoof_bad_plen_test(int s, struct lif_nd_req *nce, sin6_t *multicast)
+{
+ struct msghdr msg6;
+ struct iovec iovs[3];
+ struct nd_router_advert ichdr;
+ struct nd_opt_lla lla;
+ struct nd_opt_prefix_info pi;
+
+ spoof_prepare_header(&ichdr, &iovs[0]);
+ spoof_prepare_lla(&lla, nce, &iovs[1]);
+ spoof_prepare_pi("fd00::", 130, &pi, &iovs[2]);
+
+ /* Prepare message */
+ bzero(&msg6, sizeof (struct msghdr));
+ msg6.msg_name = multicast;
+ msg6.msg_namelen = sizeof (sin6_t);
+ msg6.msg_iov = iovs;
+ msg6.msg_iovlen = 3;
+
+ if (sendmsg(s, &msg6, 0) < 0) {
+ warn("Failed to send ICMPv6 message");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Advertise a link-local prefix, which should be disallowed and ignored.
+ */
+static int
+spoof_link_local_test(int s, struct lif_nd_req *nce, sin6_t *multicast)
+{
+ struct msghdr msg6;
+ struct iovec iovs[3];
+ struct nd_router_advert ichdr;
+ struct nd_opt_lla lla;
+ struct nd_opt_prefix_info pi;
+
+ spoof_prepare_header(&ichdr, &iovs[0]);
+ spoof_prepare_lla(&lla, nce, &iovs[1]);
+ spoof_prepare_pi("fe80::", 64, &pi, &iovs[2]);
+
+ /* Prepare message */
+ bzero(&msg6, sizeof (struct msghdr));
+ msg6.msg_name = multicast;
+ msg6.msg_namelen = sizeof (sin6_t);
+ msg6.msg_iov = iovs;
+ msg6.msg_iovlen = 3;
+
+ if (sendmsg(s, &msg6, 0) < 0) {
+ warn("Failed to send ICMPv6 message");
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+spoof_good_test(int s, struct lif_nd_req *nce, sin6_t *multicast)
+{
+ struct msghdr msg6;
+ struct iovec iovs[3];
+ struct nd_router_advert ichdr;
+ struct nd_opt_lla lla;
+ struct nd_opt_prefix_info pi;
+
+ spoof_prepare_header(&ichdr, &iovs[0]);
+ spoof_prepare_lla(&lla, nce, &iovs[1]);
+ spoof_prepare_pi("fd00::", 64, &pi, &iovs[2]);
+
+ /* Prepare message */
+ bzero(&msg6, sizeof (struct msghdr));
+ msg6.msg_name = multicast;
+ msg6.msg_namelen = sizeof (sin6_t);
+ msg6.msg_iov = iovs;
+ msg6.msg_iovlen = 3;
+
+ if (sendmsg(s, &msg6, 0) < 0) {
+ warn("Failed to send ICMPv6 message");
+ return (-1);
+ }
+
+ return (0);
+}
+
+static spoof_test_f *test_cases[] = {
+ spoof_bad_lla_optlen_test,
+ spoof_bad_pi_optlen_test,
+ spoof_bad_plen_test,
+ spoof_link_local_test
+};
+
+static int test_cases_count = sizeof (test_cases) / sizeof (spoof_test_f *);
+
+static pid_t
+spoof_dtrace_launch(void)
+{
+ pid_t child_pid = fork();
+ if (child_pid == (pid_t)-1) {
+ err(EXIT_FAILURE, "Failed to fork to execute dtrace");
+ } else if (child_pid == (pid_t)0) {
+ (void) execl("/usr/sbin/dtrace", "dtrace", "-q",
+ "-n", "sdt:mac:insert_slaac_ip:generated-addr { exit(10) }",
+ NULL);
+ err(EXIT_FAILURE, "Failed to execute dtrace");
+ }
+
+ return (child_pid);
+}
+
+static pid_t
+spoof_dtrace_wait(pid_t dtrace, int *stat)
+{
+ int retpid;
+
+ /* Give time for probe to fire before checking status */
+ (void) sleep(5);
+
+ while ((retpid = waitpid(dtrace, stat, WNOHANG)) == -1) {
+ if (errno == EINTR)
+ continue;
+
+ err(EXIT_FAILURE, "Failed to wait on child");
+ }
+
+ return (retpid);
+}
+
+/*
+ * Run a function that's going to exec in a child process, and don't return
+ * until it exits.
+ */
+static int
+spoof_run_proc(char *path, char *args[])
+{
+ pid_t child_pid;
+ int childstat = 0, status = 0;
+
+ child_pid = fork();
+ if (child_pid == (pid_t)-1) {
+ err(EXIT_FAILURE, "Unable to fork to execute %s", path);
+ } else if (child_pid == (pid_t)0) {
+ (void) execv(path, args);
+ err(EXIT_FAILURE, "Failed to execute %s", path);
+ }
+
+ while (waitpid(child_pid, &childstat, 0) == -1) {
+ if (errno == EINTR)
+ continue;
+
+ warn("Failed to wait on child");
+ return (-1);
+ }
+
+ status = WEXITSTATUS(childstat);
+ if (status != 0) {
+ warnx("Child process %s exited with %d", path, status);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+spoof_network_teardown(char *testether, char *testvnic0, char *testvnic1)
+{
+ // Delete dest vnic
+ (void) IFCONFIG(testvnic1, "inet6", "unplumb");
+ (void) DLADM("delete-vnic", testvnic1);
+
+ // Delete source vnic
+ (void) IFCONFIG(testvnic0, "inet6", "unplumb");
+ (void) DLADM("delete-vnic", testvnic0);
+
+ // Delete etherstub
+ (void) DLADM("delete-etherstub", testether);
+}
+
+static int
+spoof_network_setup(char *testether, char *testvnic0, char *testvnic1)
+{
+ // Create etherstub
+ if (DLADM("create-etherstub", "-t", testether) != 0) {
+ warnx("Failed to create etherstub for test network");
+ return (-1);
+ }
+
+ // Create source vnic
+ if (DLADM("create-vnic", "-t", "-l", testether, testvnic0) != 0) {
+ warnx("Failed to create source VNIC for test network");
+ return (-1);
+ }
+
+ if (IFCONFIG(testvnic0, "inet6", "plumb", "up") != 0) {
+ warnx("Failed to plumb source VNIC for test network");
+ return (-1);
+ }
+
+ // Create dest vnic
+ if (DLADM("create-vnic", "-t", "-l", testether,
+ "-p", "protection=mac-nospoof,restricted,ip-nospoof,dhcp-nospoof",
+ testvnic1) != 0) {
+ warnx("Failed to create destination VNIC for test network");
+ return (-1);
+ }
+
+ if (IFCONFIG(testvnic1, "inet6", "plumb", "up") != 0) {
+ warnx("Failed to plumb destination VNIC for test network");
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+spoof_run_test(spoof_test_f *func, int s, struct lif_nd_req *nce,
+ sin6_t *multicast)
+{
+ static int cas = 1;
+ (void) printf("Executing test case #%d...", cas++);
+ if (func(s, nce, multicast) == 0) {
+ (void) printf(" Done.\n");
+ } else {
+ (void) printf(" Error while running!\n");
+ }
+}
+
+static int
+spoof_run_tests(int s, struct lif_nd_req *nce)
+{
+ int cas, stat;
+ pid_t dtrace;
+ sin6_t multicast;
+
+ /* Prepare all-nodes multicast address */
+ bzero(&multicast, sizeof (multicast));
+ multicast.sin6_family = AF_INET6;
+ (void) inet_pton(AF_INET6, "ff02::1", &multicast.sin6_addr);
+
+ dtrace = spoof_dtrace_launch();
+
+ /* Wait an adequate amount of time for the probes to be installed */
+ (void) sleep(5);
+
+ /*
+ * We send a packet where everything is good, except for the hop limit.
+ * This packet should be rejected.
+ */
+ spoof_run_test(spoof_good_test, s, nce, &multicast);
+
+ if (spoof_set_max_hops(s) != 0) {
+ warnx("Failed to set hop limit on socket");
+ return (EXIT_FAILURE);
+ }
+
+ for (cas = 0; cas < test_cases_count; cas++) {
+ spoof_run_test(test_cases[cas], s, nce, &multicast);
+ }
+
+
+ if (spoof_dtrace_wait(dtrace, &stat) != 0) {
+ (void) printf("One or more tests of bad behaviour failed!\n");
+ return (EXIT_FAILURE);
+ }
+
+ /*
+ * Now that we've executed all of the test cases that should fail, we
+ * can execute the test that should succeed, to make sure the normal
+ * case works properly. This should trip the dtrace probe.
+ */
+ spoof_run_test(spoof_good_test, s, nce, &multicast);
+
+ if (spoof_dtrace_wait(dtrace, &stat) != 0 && WIFEXITED(stat) &&
+ WEXITSTATUS(stat) == 10) {
+ (void) printf("Tests completed successfully!\n");
+ } else {
+ if (kill(dtrace, SIGKILL) != 0) {
+ warn("Failed to kill dtrace child (pid %d)", dtrace);
+ }
+ (void) printf("Test of normal behaviour didn't succeed!\n");
+ return (EXIT_FAILURE);
+ }
+
+ return (0);
+}
+
+/*
+ * Make sure that we have all of the privileges we need to execute these tests,
+ * so that we can error out before we would fail.
+ */
+void
+spoof_check_privs(void)
+{
+ priv_set_t *privset = priv_allocset();
+
+ if (privset == NULL) {
+ err(EXIT_FAILURE, "Failed to allocate memory for "
+ "checking privileges");
+ }
+
+ if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
+ err(EXIT_FAILURE, "Failed to get current privileges");
+ }
+
+ if (!priv_ismember(privset, PRIV_DTRACE_KERNEL)) {
+ errx(EXIT_FAILURE, "These tests need to be run as a user "
+ "capable of tracing the kernel.");
+ }
+
+ if (!priv_ismember(privset, PRIV_SYS_NET_CONFIG)) {
+ errx(EXIT_FAILURE, "These tests need to be run as a user "
+ "capable of creating and configuring network interfaces.");
+ }
+
+ if (!priv_ismember(privset, PRIV_NET_ICMPACCESS)) {
+ errx(EXIT_FAILURE, "These tests need to be run as a user "
+ "capable of sending ICMP packets.");
+ }
+
+ priv_freeset(privset);
+}
+
+int
+main(void)
+{
+ struct lifreq addr, llar;
+ int error, s;
+ char testether[LIFNAMSIZ];
+ char testvnic0[LIFNAMSIZ];
+ char testvnic1[LIFNAMSIZ];
+ pid_t curpid = getpid();
+
+ spoof_check_privs();
+
+ /*
+ * Set up the socket and test network for sending
+ */
+ s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ if (s < 0) {
+ err(EXIT_FAILURE, "Failed to open ICMPv6 socket");
+ }
+
+ (void) snprintf(testether, sizeof (testether), "testether%d", curpid);
+ (void) snprintf(testvnic0, sizeof (testvnic0), "testvnic%d_0", curpid);
+ (void) snprintf(testvnic1, sizeof (testvnic1), "testvnic%d_1", curpid);
+
+ if (spoof_network_setup(testether, testvnic0, testvnic1) != 0) {
+ warnx("Failed to set up test network");
+ error = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ if (spoof_get_lla(s, testvnic0, &addr, &llar) != 0) {
+ warnx("Failed to get link-layer address");
+ error = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF,
+ (char *)&((sin6_t *)&addr.lifr_addr)->sin6_scope_id,
+ sizeof (int)) < 0) {
+ warn("Failed to set IPV6_UNICAST_HOPS socket option");
+ return (-1);
+ }
+
+ if (bind(s, (struct sockaddr *)&addr.lifr_addr, sizeof (sin6_t)) != 0) {
+ warnx("Failed to bind to link-local address");
+ error = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ error = spoof_run_tests(s, &llar.lifr_nd);
+
+cleanup:
+ if (close(s) != 0) {
+ warnx("Failed to close ICMPv6 socket");
+ }
+ spoof_network_teardown(testether, testvnic0, testvnic1);
+ return (error);
+}
diff --git a/usr/src/uts/common/io/mac/mac_client.c b/usr/src/uts/common/io/mac/mac_client.c
index 85e92930c1..8f0ec9eb67 100644
--- a/usr/src/uts/common/io/mac/mac_client.c
+++ b/usr/src/uts/common/io/mac/mac_client.c
@@ -858,10 +858,10 @@ mac_unicast_update_client_flow(mac_client_impl_t *mcip)
mac_flow_set_desc(flent, &flow_desc);
/*
- * The v6 local addr (used by mac protection) needs to be
+ * The v6 local and SLAAC addrs (used by mac protection) need to be
* regenerated because our mac address has changed.
*/
- mac_protect_update_v6_local_addr(mcip);
+ mac_protect_update_mac_token(mcip);
/*
* A MAC client could have one MAC address but multiple
@@ -2956,7 +2956,7 @@ mac_client_datapath_teardown(mac_client_handle_t mch, mac_unicast_impl_t *muip,
if (muip != NULL)
kmem_free(muip, sizeof (mac_unicast_impl_t));
mac_protect_cancel_timer(mcip);
- mac_protect_flush_dhcp(mcip);
+ mac_protect_flush_dynamic(mcip);
bzero(&mcip->mci_misc_stat, sizeof (mcip->mci_misc_stat));
/*
diff --git a/usr/src/uts/common/io/mac/mac_datapath_setup.c b/usr/src/uts/common/io/mac/mac_datapath_setup.c
index 5ca673ea6e..14d94981cd 100644
--- a/usr/src/uts/common/io/mac/mac_datapath_setup.c
+++ b/usr/src/uts/common/io/mac/mac_datapath_setup.c
@@ -3018,8 +3018,8 @@ mac_datapath_setup(mac_client_impl_t *mcip, flow_entry_t *flent,
goto setup_failed;
mcip->mci_unicast = mac_find_macaddr(mip, mac_addr);
ASSERT(mcip->mci_unicast != NULL);
- /* Initialize the v6 local addr used by link protection */
- mac_protect_update_v6_local_addr(mcip);
+ /* (Re)init the v6 token & local addr used by link protection */
+ mac_protect_update_mac_token(mcip);
break;
default:
diff --git a/usr/src/uts/common/io/mac/mac_protect.c b/usr/src/uts/common/io/mac/mac_protect.c
index 4438cb90fb..805b5d36f9 100644
--- a/usr/src/uts/common/io/mac/mac_protect.c
+++ b/usr/src/uts/common/io/mac/mac_protect.c
@@ -27,6 +27,7 @@
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
+#include <sys/cmn_err.h>
#include <sys/strsun.h>
#include <sys/sdt.h>
#include <sys/mac.h>
@@ -145,6 +146,7 @@
*/
static ulong_t dhcp_max_pending_txn = 512;
static ulong_t dhcp_max_completed_txn = 512;
+static ulong_t slaac_max_allowed = 512;
static hrtime_t txn_cleanup_interval = 60 * NANOSEC;
/*
@@ -196,6 +198,16 @@ typedef struct dhcpv6_txn {
struct dhcpv6_txn *dt_next;
} dhcpv6_txn_t;
+/*
+ * Stateless address autoconfiguration (SLAAC) address. May be added to
+ * mci_v6_slaac_ip.
+ */
+typedef struct slaac_addr {
+ in6_addr_t sla_prefix;
+ in6_addr_t sla_addr;
+ avl_node_t sla_node;
+} slaac_addr_t;
+
static void start_txn_cleanup_timer(mac_client_impl_t *);
static boolean_t allowed_ips_set(mac_resource_props_t *, uint32_t);
@@ -654,16 +666,13 @@ done:
* Core logic for intercepting inbound DHCPv4 packets.
*/
static void
-intercept_dhcpv4_inbound(mac_client_impl_t *mcip, ipha_t *ipha, uchar_t *end)
+intercept_dhcpv4_inbound(mac_client_impl_t *mcip, uchar_t *end,
+ struct dhcp *dh4)
{
uchar_t *opt;
- struct dhcp *dh4;
dhcpv4_txn_t *txn, *ctxn;
uint8_t opt_len, mtype;
- if (get_dhcpv4_info(ipha, end, &dh4) != 0)
- return;
-
if (get_dhcpv4_option(dh4, end, CD_DHCP_TYPE, &opt, &opt_len) != 0 ||
opt_len != 1) {
DTRACE_PROBE2(mtype__not__found, mac_client_impl_t *, mcip,
@@ -771,6 +780,21 @@ compare_dhcpv6_cid(const void *arg1, const void *arg2)
return (0);
}
+static int
+compare_slaac_ip(const void *arg1, const void *arg2)
+{
+ const slaac_addr_t *ip1 = arg1, *ip2 = arg2;
+ int ret;
+
+ ret = memcmp(&ip1->sla_addr, &ip2->sla_addr, sizeof (in6_addr_t));
+ if (ret < 0)
+ return (-1);
+ else if (ret > 0)
+ return (1);
+ else
+ return (0);
+}
+
/*
* Locate the start of a DHCPv6 header.
* The possible return values and associated meanings are:
@@ -829,6 +853,51 @@ get_dhcpv6_info(ip6_t *ip6h, uchar_t *end, dhcpv6_message_t **dh6)
return (0);
}
+static int
+get_ra_info(ip6_t *ip6h, uchar_t *end, nd_router_advert_t **ra)
+{
+ uint16_t hdrlen;
+ ip6_frag_t *frag = NULL;
+ uint8_t proto;
+ uchar_t *hdrp;
+ struct icmp6_hdr *icmp;
+
+ if (!mac_ip_hdr_length_v6(ip6h, end, &hdrlen, &proto, &frag))
+ return (ENOSPC);
+
+ if (proto != IPPROTO_ICMPV6)
+ return (EINVAL);
+
+ if (frag != NULL) {
+ /*
+ * All non-initial fragments may pass because we cannot
+ * identify their type. It's safe to let them through
+ * because reassembly will fail if we decide to drop the
+ * initial fragment.
+ */
+ if ((ntohs(frag->ip6f_offlg) & ~7) != 0)
+ return (EINVAL);
+ return (ENOSPC);
+ }
+
+ /*
+ * Ensure that the ICMP header falls w/in packet boundaries, in case
+ * we've received a malicious packet that reports incorrect lengths.
+ */
+ hdrp = (uchar_t *)ip6h + hdrlen;
+ if ((hdrp + sizeof (struct icmp6_hdr)) > end) {
+ return (EINVAL);
+ }
+ icmp = (struct icmp6_hdr *)hdrp;
+
+ if (icmp->icmp6_type != ND_ROUTER_ADVERT ||
+ icmp->icmp6_code != 0)
+ return (EINVAL);
+
+ *ra = (nd_router_advert_t *)icmp;
+ return (0);
+}
+
/*
* Find the specified DHCPv6 option.
*/
@@ -1172,6 +1241,18 @@ flush_dhcpv6(mac_client_impl_t *mcip)
}
}
+void
+flush_slaac(mac_client_impl_t *mcip)
+{
+ void *cookie = NULL;
+ slaac_addr_t *addr = NULL;
+
+ while ((addr = avl_destroy_nodes(&mcip->mci_v6_slaac_ip, &cookie)) !=
+ NULL) {
+ kmem_free(addr, sizeof (slaac_addr_t));
+ }
+}
+
/*
* Cleanup stale DHCPv6 transactions.
*/
@@ -1287,17 +1368,14 @@ done:
* Core logic for intercepting inbound DHCPv6 packets.
*/
static void
-intercept_dhcpv6_inbound(mac_client_impl_t *mcip, ip6_t *ip6h, uchar_t *end)
+intercept_dhcpv6_inbound(mac_client_impl_t *mcip, uchar_t *end,
+ dhcpv6_message_t *dh6)
{
- dhcpv6_message_t *dh6;
dhcpv6_txn_t *txn;
uint32_t xid;
uint8_t mtype;
uint16_t status;
- if (get_dhcpv6_info(ip6h, end, &dh6) != 0)
- return;
-
mtype = dh6->d6m_msg_type;
if (mtype != DHCPV6_MSG_REPLY)
return;
@@ -1340,6 +1418,134 @@ done:
}
/*
+ * Check whether an IP address is in the SLAAC table.
+ */
+static boolean_t
+check_slaac_ip(mac_client_impl_t *mcip, in6_addr_t *addr)
+{
+ slaac_addr_t tmp_addr, *a;
+
+ mutex_enter(&mcip->mci_protect_lock);
+ bcopy(addr, &tmp_addr.sla_addr, sizeof (in6_addr_t));
+ a = avl_find(&mcip->mci_v6_slaac_ip, &tmp_addr, NULL);
+ mutex_exit(&mcip->mci_protect_lock);
+ return (a != NULL);
+}
+
+static boolean_t
+insert_slaac_ip(avl_tree_t *tree, in6_addr_t *token, slaac_addr_t *addr)
+{
+ uint_t i;
+ avl_index_t where;
+ in6_addr_t *prefix = &addr->sla_prefix;
+ in6_addr_t *in6p = &addr->sla_addr;
+
+ bcopy(prefix, in6p, sizeof (struct in6_addr));
+
+ for (i = 0; i < 4; i++) {
+ in6p->s6_addr32[i] = token->s6_addr32[i] |
+ in6p->s6_addr32[i];
+ }
+
+ DTRACE_PROBE1(generated__addr, in6_addr_t *, in6p);
+
+ if (avl_find(tree, addr, &where) != NULL)
+ return (B_FALSE);
+
+ avl_insert(tree, addr, where);
+ return (B_TRUE);
+}
+
+static void
+insert_slaac_prefix(mac_client_impl_t *mcip, nd_opt_prefix_info_t *po)
+{
+ slaac_addr_t *addr = NULL;
+ in6_addr_t *token = &mcip->mci_v6_mac_token;
+
+ ASSERT(MUTEX_HELD(&mcip->mci_protect_lock));
+
+ if (avl_numnodes(&mcip->mci_v6_slaac_ip) >= slaac_max_allowed) {
+ DTRACE_PROBE(limit__reached);
+ return;
+ }
+
+ if ((addr = kmem_zalloc(sizeof (slaac_addr_t),
+ KM_NOSLEEP | KM_NORMALPRI)) == NULL)
+ return;
+
+ bcopy(&po->nd_opt_pi_prefix, &addr->sla_prefix,
+ sizeof (struct in6_addr));
+
+ if (!insert_slaac_ip(&mcip->mci_v6_slaac_ip, token, addr)) {
+ kmem_free(addr, sizeof (slaac_addr_t));
+ }
+}
+
+static void
+intercept_prefix_info(mac_client_impl_t *mcip, nd_opt_prefix_info_t *po)
+{
+ if (8 * po->nd_opt_pi_len != sizeof (nd_opt_prefix_info_t)) {
+ DTRACE_PROBE(invalid__length);
+ return;
+ }
+
+ if (po->nd_opt_pi_prefix_len > 128) {
+ DTRACE_PROBE(invalid__plen);
+ return;
+ }
+
+ if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
+ DTRACE_PROBE(link__local);
+ return;
+ }
+
+ if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) == 0)
+ return;
+
+ mutex_enter(&mcip->mci_protect_lock);
+ insert_slaac_prefix(mcip, po);
+ mutex_exit(&mcip->mci_protect_lock);
+}
+
+/*
+ * If we receive a Router Advertisement carrying prefix information and
+ * indicating that SLAAC should be performed, then track the prefix.
+ */
+static void
+intercept_ra_inbound(mac_client_impl_t *mcip, ip6_t *ip6h, uchar_t *end,
+ nd_router_advert_t *ra)
+{
+ struct nd_opt_hdr *opt;
+ int len, optlen;
+
+ if (ip6h->ip6_hlim != 255) {
+ DTRACE_PROBE1(invalid__hoplimit, uint8_t, ip6h->ip6_hlim);
+ return;
+ }
+
+ len = ip6h->ip6_plen - sizeof (nd_router_advert_t);
+ opt = (struct nd_opt_hdr *)&ra[1];
+ while (len >= sizeof (struct nd_opt_hdr) &&
+ ((uchar_t *)opt + sizeof (struct nd_opt_hdr)) <= end) {
+ optlen = opt->nd_opt_len * 8;
+
+ if (optlen < sizeof (struct nd_opt_hdr) ||
+ ((uchar_t *)opt + optlen) > end) {
+ DTRACE_PROBE(invalid__length);
+ return;
+ }
+
+ if (opt->nd_opt_type == ND_OPT_PREFIX_INFORMATION) {
+ intercept_prefix_info(mcip,
+ (nd_opt_prefix_info_t *)opt);
+ }
+
+ opt = (struct nd_opt_hdr *)((char *)opt + optlen);
+ len -= optlen;
+ }
+}
+
+/*
* Timer for cleaning up stale transactions.
*/
static void
@@ -1446,7 +1652,7 @@ get_l3_info(mblk_t *mp, size_t hdrsize, uchar_t **start, uchar_t **end,
}
void
-mac_protect_intercept_dhcp_one(mac_client_impl_t *mcip, mblk_t *mp)
+mac_protect_intercept_dynamic_one(mac_client_impl_t *mcip, mblk_t *mp)
{
mac_impl_t *mip = mcip->mci_mip;
uchar_t *start, *end;
@@ -1470,21 +1676,31 @@ mac_protect_intercept_dhcp_one(mac_client_impl_t *mcip, mblk_t *mp)
switch (mhi.mhi_bindsap) {
case ETHERTYPE_IP: {
- ipha_t *ipha = (ipha_t *)start;
+ struct dhcp *dh4;
+ ipha_t *ipha = (ipha_t *)start;
if (start + sizeof (ipha_t) > end)
return;
- intercept_dhcpv4_inbound(mcip, ipha, end);
+ if (get_dhcpv4_info(ipha, end, &dh4) == 0) {
+ intercept_dhcpv4_inbound(mcip, end, dh4);
+ }
break;
}
case ETHERTYPE_IPV6: {
- ip6_t *ip6h = (ip6_t *)start;
+ dhcpv6_message_t *dh6;
+ nd_router_advert_t *ra;
+ ip6_t *ip6h = (ip6_t *)start;
if (start + sizeof (ip6_t) > end)
return;
- intercept_dhcpv6_inbound(mcip, ip6h, end);
+ if (get_dhcpv6_info(ip6h, end, &dh6) == 0) {
+ intercept_dhcpv6_inbound(mcip, end, dh6);
+ } else if (get_ra_info(ip6h, end, &ra) == 0) {
+ intercept_ra_inbound(mcip, ip6h, end, ra);
+ }
+
break;
}
}
@@ -1492,7 +1708,7 @@ mac_protect_intercept_dhcp_one(mac_client_impl_t *mcip, mblk_t *mp)
}
void
-mac_protect_intercept_dhcp(mac_client_impl_t *mcip, mblk_t *mp)
+mac_protect_intercept_dynamic(mac_client_impl_t *mcip, mblk_t *mp)
{
/*
* Skip checks if we are part of an aggr.
@@ -1501,15 +1717,16 @@ mac_protect_intercept_dhcp(mac_client_impl_t *mcip, mblk_t *mp)
return;
for (; mp != NULL; mp = mp->b_next)
- mac_protect_intercept_dhcp_one(mcip, mp);
+ mac_protect_intercept_dynamic_one(mcip, mp);
}
void
-mac_protect_flush_dhcp(mac_client_impl_t *mcip)
+mac_protect_flush_dynamic(mac_client_impl_t *mcip)
{
mutex_enter(&mcip->mci_protect_lock);
flush_dhcpv4(mcip);
flush_dhcpv6(mcip);
+ flush_slaac(mcip);
mutex_exit(&mcip->mci_protect_lock);
}
@@ -1586,8 +1803,13 @@ ipnospoof_check_v6(mac_client_impl_t *mcip, mac_protect_t *protect,
v6addr->ip_netmask))
return (B_TRUE);
}
- return (protect->mp_ipaddrcnt == 0 ?
- check_dhcpv6_dyn_ip(mcip, addr) : B_FALSE);
+
+ if (protect->mp_ipaddrcnt == 0) {
+ return (check_slaac_ip(mcip, addr) ||
+ check_dhcpv6_dyn_ip(mcip, addr));
+ } else {
+ return (B_FALSE);
+ }
}
/*
@@ -1943,19 +2165,68 @@ fail:
}
/*
- * This needs to be called whenever the mac client's mac address changes.
+ * This is called whenever the mac client's mac address changes, to make sure
+ * we allow use of the new link-local address.
*/
-void
+static void
mac_protect_update_v6_local_addr(mac_client_impl_t *mcip)
{
- uint8_t *p, *macaddr = mcip->mci_unicast->ma_addr;
- uint_t i, media = mcip->mci_mip->mi_info.mi_media;
- in6_addr_t token, *v6addr = &mcip->mci_v6_local_addr;
+ uint_t i;
+ in6_addr_t *token = &mcip->mci_v6_mac_token;
+ in6_addr_t *v6addr = &mcip->mci_v6_local_addr;
in6_addr_t ll_template = {(uint32_t)V6_LINKLOCAL, 0x0, 0x0, 0x0};
+ for (i = 0; i < 4; i++) {
+ v6addr->s6_addr32[i] = token->s6_addr32[i] |
+ ll_template.s6_addr32[i];
+ }
+ mcip->mci_protect_flags |= MPT_FLAG_V6_LOCAL_ADDR_SET;
+}
- bzero(&token, sizeof (token));
- p = (uint8_t *)&token.s6_addr32[2];
+/*
+ * This is called whenever the mac client's mac address changes, to make sure
+ * that any existing addresses gained via SLAAC are appropriately updated.
+ */
+static void
+mac_protect_update_v6_slaac_addr(mac_client_impl_t *mcip)
+{
+ void *cookie = NULL;
+ avl_tree_t temp_tree;
+ avl_tree_t *ttp = &temp_tree, *sip = &mcip->mci_v6_slaac_ip;
+ in6_addr_t *token = &mcip->mci_v6_mac_token;
+ slaac_addr_t *addr = NULL;
+
+ avl_create(ttp, compare_slaac_ip, sizeof (slaac_addr_t),
+ offsetof(slaac_addr_t, sla_node));
+
+ /* Copy everything over to the temporary tree, and fix the IP address */
+ while ((addr = avl_destroy_nodes(sip, &cookie)) != NULL) {
+ VERIFY(insert_slaac_ip(ttp, token, addr) == B_TRUE);
+ }
+
+ /*
+ * Now that the tempory tree has all of the modified addresses, we can
+ * swap them over to the original tree once it's reset.
+ */
+ avl_destroy(sip);
+ avl_create(sip, compare_slaac_ip, sizeof (slaac_addr_t),
+ offsetof(slaac_addr_t, sla_node));
+ avl_swap(ttp, sip);
+}
+
+/*
+ * After the unicast MAC address changes, we need to update the derived token,
+ * and update the IPv6 addresses that use the token.
+ */
+void
+mac_protect_update_mac_token(mac_client_impl_t *mcip)
+{
+ uint_t media = mcip->mci_mip->mi_info.mi_media;
+ uint8_t *p, *macaddr = mcip->mci_unicast->ma_addr;
+ in6_addr_t *token = &mcip->mci_v6_mac_token;
+
+ bzero(token, sizeof (in6_addr_t));
+ p = (uint8_t *)&token->s6_addr32[2];
switch (media) {
case DL_ETHER:
@@ -1974,19 +2245,18 @@ mac_protect_update_v6_local_addr(mac_client_impl_t *mcip)
/*
* We do not need to generate the local address for link types
* that do not support link protection. Wifi pretends to be
- * ethernet so it is covered by the DL_ETHER case (note the
+ * Ethernet so it is covered by the DL_ETHER case (note the
* use of mi_media instead of mi_nativemedia).
*/
return;
}
- for (i = 0; i < 4; i++) {
- v6addr->s6_addr32[i] = token.s6_addr32[i] |
- ll_template.s6_addr32[i];
- }
- mcip->mci_protect_flags |= MPT_FLAG_V6_LOCAL_ADDR_SET;
+ mac_protect_update_v6_local_addr(mcip);
+ mac_protect_update_v6_slaac_addr(mcip);
}
+
+
/*
* Enforce link protection on one packet.
*/
@@ -2304,6 +2574,8 @@ mac_protect_init(mac_client_impl_t *mcip)
sizeof (dhcpv6_cid_t), offsetof(dhcpv6_cid_t, dc_node));
avl_create(&mcip->mci_v6_dyn_ip, compare_dhcpv6_ip,
sizeof (dhcpv6_addr_t), offsetof(dhcpv6_addr_t, da_node));
+ avl_create(&mcip->mci_v6_slaac_ip, compare_slaac_ip,
+ sizeof (slaac_addr_t), offsetof(slaac_addr_t, sla_node));
}
void
@@ -2315,6 +2587,7 @@ mac_protect_fini(mac_client_impl_t *mcip)
avl_destroy(&mcip->mci_v4_dyn_ip);
avl_destroy(&mcip->mci_v4_completed_txn);
avl_destroy(&mcip->mci_v4_pending_txn);
+ avl_destroy(&mcip->mci_v6_slaac_ip);
mcip->mci_txn_cleanup_tid = 0;
mcip->mci_protect_flags = 0;
mutex_destroy(&mcip->mci_protect_lock);
diff --git a/usr/src/uts/common/io/mac/mac_sched.c b/usr/src/uts/common/io/mac/mac_sched.c
index eb179b07c7..148f739d52 100644
--- a/usr/src/uts/common/io/mac/mac_sched.c
+++ b/usr/src/uts/common/io/mac/mac_sched.c
@@ -2632,7 +2632,7 @@ again:
}
if (MAC_PROTECT_ENABLED(mcip, MPT_IPNOSPOOF)) {
mutex_exit(&mac_srs->srs_lock);
- mac_protect_intercept_dhcp(mcip, head);
+ mac_protect_intercept_dynamic(mcip, head);
mutex_enter(&mac_srs->srs_lock);
}
}
@@ -2910,7 +2910,7 @@ again:
}
if (MAC_PROTECT_ENABLED(mcip, MPT_IPNOSPOOF)) {
mutex_exit(&mac_srs->srs_lock);
- mac_protect_intercept_dhcp(mcip, head);
+ mac_protect_intercept_dynamic(mcip, head);
mutex_enter(&mac_srs->srs_lock);
}
}
diff --git a/usr/src/uts/common/sys/mac_client_impl.h b/usr/src/uts/common/sys/mac_client_impl.h
index 3c89b7c434..0904b28645 100644
--- a/usr/src/uts/common/sys/mac_client_impl.h
+++ b/usr/src/uts/common/sys/mac_client_impl.h
@@ -96,7 +96,7 @@ typedef union mac_tx_percpu_s {
#define pcpu_tx_refcnt pcpu_lr._pcpu_tx_refcnt
/*
- * One of these is instanciated for each MAC client.
+ * One of these is instantiated for each MAC client.
*/
struct mac_client_impl_s { /* Protected by */
struct mac_client_impl_s *mci_client_next; /* mi_rw_lock */
@@ -182,6 +182,7 @@ struct mac_client_impl_s { /* Protected by */
*/
kmutex_t mci_protect_lock;
uint32_t mci_protect_flags; /* SL */
+ in6_addr_t mci_v6_mac_token; /* SL */
in6_addr_t mci_v6_local_addr; /* SL */
avl_tree_t mci_v4_pending_txn; /* mci_protect_lock */
avl_tree_t mci_v4_completed_txn; /* mci_protect_lock */
@@ -189,6 +190,7 @@ struct mac_client_impl_s { /* Protected by */
avl_tree_t mci_v6_pending_txn; /* mci_protect_lock */
avl_tree_t mci_v6_cid; /* mci_protect_lock */
avl_tree_t mci_v6_dyn_ip; /* mci_protect_lock */
+ avl_tree_t mci_v6_slaac_ip; /* mci_protect_lock */
timeout_id_t mci_txn_cleanup_tid; /* mci_protect_lock */
/*
diff --git a/usr/src/uts/common/sys/mac_impl.h b/usr/src/uts/common/sys/mac_impl.h
index 3c9c6b77a4..2286b587e8 100644
--- a/usr/src/uts/common/sys/mac_impl.h
+++ b/usr/src/uts/common/sys/mac_impl.h
@@ -884,9 +884,9 @@ extern int mac_protect_set(mac_client_handle_t, mac_resource_props_t *);
extern boolean_t mac_protect_enabled(mac_client_handle_t, uint32_t);
extern int mac_protect_validate(mac_resource_props_t *);
extern void mac_protect_update(mac_resource_props_t *, mac_resource_props_t *);
-extern void mac_protect_update_v6_local_addr(mac_client_impl_t *);
-extern void mac_protect_intercept_dhcp(mac_client_impl_t *, mblk_t *);
-extern void mac_protect_flush_dhcp(mac_client_impl_t *);
+extern void mac_protect_update_mac_token(mac_client_impl_t *);
+extern void mac_protect_intercept_dynamic(mac_client_impl_t *, mblk_t *);
+extern void mac_protect_flush_dynamic(mac_client_impl_t *);
extern void mac_protect_cancel_timer(mac_client_impl_t *);
extern void mac_protect_init(mac_client_impl_t *);
extern void mac_protect_fini(mac_client_impl_t *);