PSARC/2007/565 IP_XMIT_IF removal and IP_BOUND_IF rationalization
PSARC/2007/571 IP_DHCPINIT_IF socket option
4354207 dhcpagent should use sockets rather than DLPI
6533610 IP_XMIT_IF should fade from in.routed's view
6607674 DHCP client's "checkaddr" warnings have output reversed
6607676 DHCP client misreports dhcp_bound_complete as configure_bound
6609845 torch IP_XMIT_IF and complete IP_BOUND_IF
6609852 need a way to receive IP unicast DHCP traffic before lease acquisition
6609868 IP should create broadcast IREs when bringing up 0.0.0.0
6616106 IP_UNSPEC_SRC sockets should skip calls to ipif_select_source()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c Tue Oct 30 11:15:43 2007 -0700
@@ -0,0 +1,343 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/pfmod.h>
+#include <sys/socket.h>
+#include <netinet/in.h> /* in_addr (ip.h) */
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <stropts.h>
+#include <string.h> /* strpbrk */
+#include <sys/uio.h>
+#include <stdlib.h>
+#include <dhcpmsg.h>
+
+#include "dlpi_io.h"
+#include "v4_sum_impl.h"
+#include "common.h"
+
+/*
+ * timeout to wait for acknowledgement of packet filter, in seconds.
+ */
+#define FILTER_TIMEOUT 5
+
+/*
+ * dlpi_recvfrom(): receives data on a DLPI stream
+ *
+ * input: dlpi_handle_t: dlpi handle to receive the data on
+ * void *: a buffer to store the data in
+ * size_t: the size of the buffer
+ * struct sockaddr_in *: if non-NULL, sender's IP address is filled in
+ * struct sockaddr_in *: if non-NULL, recipient's IP address
+ * output: ssize_t: the number of bytes read on success, -1 on failure
+ */
+ssize_t
+dlpi_recvfrom(dlpi_handle_t dh, void *buf, size_t buflen,
+ struct sockaddr_in *from, struct sockaddr_in *to)
+{
+ struct ip *ip;
+ struct udphdr *udphdr;
+ void *msgbuf;
+ size_t msglen;
+ dlpi_recvinfo_t dlrecv;
+ int rc;
+
+ msglen = buflen + sizeof (struct ip) + sizeof (struct udphdr);
+ msgbuf = malloc(msglen);
+
+ if (msgbuf == NULL) {
+ dhcpmsg(MSG_ERR, "dlpi_recvfrom: cannot allocate packet");
+ return (-1);
+ }
+
+ rc = dlpi_recv(dh, NULL, NULL, msgbuf, &msglen, -1, &dlrecv);
+ if (rc != DLPI_SUCCESS) {
+ dhcpmsg(MSG_ERR, "dlpi_recvfrom: dlpi_recv failed: %s",
+ dlpi_strerror(rc));
+ free(msgbuf);
+ return (-1);
+ }
+
+ /*
+ * since we're just pulling data off the wire, what we have
+ * may look nothing like a DHCP packet. note that this
+ * shouldn't happen (pfmod should have tossed it already).
+ */
+ if (msglen < sizeof (struct ip) + sizeof (struct udphdr)) {
+ dhcpmsg(MSG_WARNING, "dlpi_recvfrom: dropped short packet");
+ free(msgbuf);
+ return (-1);
+ }
+
+ if (msglen < dlrecv.dri_totmsglen) {
+ dhcpmsg(MSG_WARNING, "dlpi_recvfrom: discarding stray "
+ "data on streamhead");
+ }
+
+ /*
+ * verify checksums
+ */
+ ip = msgbuf;
+ if (ipv4cksum((uint16_t *)ip, ip->ip_hl << 2) != 0) {
+ dhcpmsg(MSG_WARNING, "dlpi_recvfrom: dropped packet with bad "
+ "ipv4 checksum");
+ free(msgbuf);
+ return (-1);
+ }
+
+ udphdr = (struct udphdr *)&ip[1];
+ if ((udphdr->uh_sum != 0) &&
+ (udp_chksum(udphdr, &ip->ip_src, &ip->ip_dst, ip->ip_p) != 0)) {
+ dhcpmsg(MSG_WARNING, "dlpi_recvfrom: dropped packet with bad "
+ "UDP checksum");
+ free(msgbuf);
+ return (-1);
+ }
+
+ msglen -= (sizeof (struct ip) + sizeof (struct udphdr));
+ (void) memcpy(buf, &udphdr[1], msglen);
+
+ if (from != NULL) {
+ from->sin_family = AF_INET;
+ from->sin_addr = ip->ip_src;
+ from->sin_port = udphdr->uh_sport;
+ }
+
+ if (to != NULL) {
+ to->sin_family = AF_INET;
+ to->sin_addr = ip->ip_dst;
+ to->sin_port = udphdr->uh_dport;
+ }
+
+ free(msgbuf);
+ return (msglen);
+}
+
+/*
+ * dlpi_sendto(): sends UDP packets on a DLPI stream
+ *
+ * input: dlpi_handle_t: dlpi handle to send the packet on
+ * void *: a buffer to send
+ * size_t: the size of the buffer
+ * struct sockaddr_in *: the IP address to send the data to
+ * uchar_t *: the link-layer destination address
+ * size_t: the size of the link-layer destination address
+ * output: ssize_t: the number of bytes sent on success, -1 on failure
+ */
+ssize_t
+dlpi_sendto(dlpi_handle_t dh, void *buf, size_t buflen,
+ struct sockaddr_in *to, uchar_t *dl_to, size_t dl_to_len)
+{
+ struct ip *ip;
+ struct udphdr *udphdr;
+ void *msgbuf;
+ size_t msglen;
+ static uint16_t ip_id = 0;
+ int rc;
+
+ /*
+ * TODO: someday we might want to support `to' not being
+ * the same as INADDR_BROADCAST. we don't need the support
+ * right now, but it's annoying to have a general interface
+ * that only supports a specific function.
+ */
+ if (to->sin_addr.s_addr != htonl(INADDR_BROADCAST)) {
+ dhcpmsg(MSG_ERROR, "dlpi_sendto: send to unicast address");
+ return (-1);
+ }
+
+ /*
+ * we allocate one extra byte here in case the UDP checksum
+ * routine needs it to get the packet length to be even.
+ */
+ msglen = sizeof (struct ip) + sizeof (struct udphdr) + buflen;
+ msgbuf = calloc(1, msglen + 1);
+ if (msgbuf == NULL) {
+ dhcpmsg(MSG_ERR, "dlpi_sendto: cannot allocate packet");
+ return (-1);
+ }
+
+ ip = (struct ip *)msgbuf;
+ udphdr = (struct udphdr *)&ip[1];
+
+ (void) memcpy(&udphdr[1], buf, buflen);
+
+ /*
+ * build the ipv4 header. assume that our source address is 0
+ * (since we wouldn't be using DLPI if we could actually send
+ * packets an easier way). note that we only need to set nonzero
+ * fields since we got calloc()'d memory above.
+ */
+
+ /*
+ * From a purist's perspective, we should set the TTL to 1 for
+ * limited broadcasts. But operational experience (cisco routers)
+ * has shown that doing so results in the relay agent dropping our
+ * packets. These same devices (ciscos) also don't set the TTL
+ * to MAXTTL on the unicast side of the relay agent. Thus, the only
+ * safe thing to do is to always set the ttl to MAXTTL. Sigh.
+ */
+
+ ip->ip_ttl = MAXTTL;
+
+ ip->ip_v = 4;
+ ip->ip_hl = sizeof (struct ip) / 4;
+ ip->ip_id = htons(ip_id++);
+ ip->ip_off = htons(IP_DF);
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_len = htons(msglen);
+ ip->ip_dst = to->sin_addr;
+ ip->ip_src.s_addr = htonl(INADDR_ANY);
+ ip->ip_sum = ipv4cksum((uint16_t *)ip, sizeof (struct ip));
+
+ udphdr->uh_ulen = htons(sizeof (struct udphdr) + buflen);
+ udphdr->uh_sport = htons(IPPORT_BOOTPC);
+ udphdr->uh_dport = htons(IPPORT_BOOTPS);
+ udphdr->uh_sum = udp_chksum(udphdr, &ip->ip_src, &ip->ip_dst, ip->ip_p);
+
+ rc = dlpi_send(dh, dl_to, dl_to_len, msgbuf, msglen, NULL);
+ if (rc != DLPI_SUCCESS) {
+ free(msgbuf);
+ dhcpmsg(MSG_ERR, "dlpi_sendto: dlpi_send: %s",
+ dlpi_strerror(rc));
+ return (-1);
+ }
+
+ free(msgbuf);
+ return (buflen);
+}
+
+/*
+ * set_packet_filter(): sets the current packet filter on a DLPI stream
+ *
+ * input: dlpi_handle_t: the DLPI handle to set the packet filter on
+ * filter_func_t *: the filter to use
+ * void *: an argument to pass to the filter function
+ * const char *: a text description of the filter's purpose
+ * output: boolean_t: B_TRUE on success, B_FALSE on failure.
+ */
+boolean_t
+set_packet_filter(dlpi_handle_t dh, filter_func_t *filter, void *arg,
+ const char *filter_name)
+{
+ struct strioctl sioc;
+ struct packetfilt pf;
+ ushort_t *pfp = pf.Pf_Filter;
+ int fd = dlpi_fd(dh);
+
+ if (ioctl(fd, I_PUSH, "pfmod") == -1) {
+ dhcpmsg(MSG_ERR,
+ "open_dlpi_pif: cannot push pfmod on stream");
+ return (B_FALSE);
+ }
+
+ pf.Pf_FilterLen = filter(pfp, arg) - pf.Pf_Filter;
+
+ sioc.ic_cmd = PFIOCSETF;
+ sioc.ic_timout = FILTER_TIMEOUT;
+ sioc.ic_len = sizeof (struct packetfilt);
+ sioc.ic_dp = (caddr_t)&pf;
+
+ /*
+ * if this ioctl() fails, we're really hosed. the best we can
+ * really do is play on.
+ */
+
+ if (ioctl(fd, I_STR, &sioc) == -1)
+ dhcpmsg(MSG_ERR, "set_packet_filter: PFIOCSETF");
+ else
+ dhcpmsg(MSG_DEBUG, "set_packet_filter: set filter %p "
+ "(%s filter)", (void *)filter, filter_name);
+
+ /*
+ * clean out any potential cruft on the descriptor that
+ * appeared before we were able to set the filter
+ */
+
+ (void) ioctl(fd, I_FLUSH, FLUSHR);
+
+ return (B_TRUE);
+}
+
+/*
+ * dhcp_filter(): builds a packet filter that permits only DHCP/BOOTP messages
+ *
+ * input: ushort_t *: a place to store the packet filter code
+ * void *: not used
+ * output: ushort_t *: two bytes past the last byte in the packet filter
+ */
+
+/* ARGSUSED */
+ushort_t *
+dhcp_filter(ushort_t *pfp, void *arg)
+{
+ /*
+ * only pass up UDP packets -- 8th byte is the ttl/proto field
+ */
+
+ *pfp++ = ENF_PUSHWORD + 4;
+ *pfp++ = ENF_PUSHLIT | ENF_AND;
+ *pfp++ = htons(0xff);
+ *pfp++ = ENF_PUSHLIT | ENF_CAND;
+ *pfp++ = htons(IPPROTO_UDP);
+
+ /*
+ * make sure the IP packet doesn't have any options. 2nd
+ * nibble is the header length field.
+ * TODO: if we decide to handle options, this code goes away.
+ */
+
+ *pfp++ = ENF_PUSHWORD + 0;
+ *pfp++ = ENF_PUSHLIT | ENF_AND;
+ *pfp++ = htons(0x0f00); /* only care about 2nd nibble */
+ *pfp++ = ENF_PUSHLIT | ENF_CAND;
+ *pfp++ = htons(0x0500); /* which should be 5 * 4 = 20 */
+
+ /*
+ * if there's a fragment offset, or if the IP_MF bit is lit,
+ * pitch the packet. this pitches all fragments.
+ * TODO: if we decide to handle fragments, this code goes away.
+ */
+
+ *pfp++ = ENF_PUSHWORD + 3;
+ *pfp++ = ENF_PUSHLIT | ENF_AND;
+ *pfp++ = htons(0x1fff | IP_MF);
+ *pfp++ = ENF_PUSHZERO | ENF_CAND;
+
+ /*
+ * make sure the packet is for the DHCP client port -- 22nd
+ * byte is the UDP port number.
+ */
+
+ *pfp++ = ENF_PUSHWORD + 11;
+ *pfp++ = ENF_PUSHLIT | ENF_CAND;
+ *pfp++ = htons(IPPORT_BOOTPC);
+
+ return (pfp);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.h Tue Oct 30 11:15:43 2007 -0700
@@ -0,0 +1,59 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef DLPI_IO_H
+#define DLPI_IO_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <libdlpi.h>
+
+/*
+ * dlpi_io.[ch] contain the interface the agent uses to interact with
+ * DLPI for data transfer primitives. see dlpi_io.c for documentation
+ * on how to use the exported functions.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef ushort_t *filter_func_t(ushort_t *, void *);
+
+filter_func_t dhcp_filter;
+boolean_t set_packet_filter(dlpi_handle_t, filter_func_t *, void *,
+ const char *);
+ssize_t dlpi_recvfrom(dlpi_handle_t, void *, size_t,
+ struct sockaddr_in *, struct sockaddr_in *);
+ssize_t dlpi_sendto(dlpi_handle_t, void *, size_t, struct sockaddr_in *,
+ uchar_t *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DLPI_IO_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/deleted_files/usr/src/cmd/cmd-inet/sbin/dhcpagent/inc.flg Tue Oct 30 11:15:43 2007 -0700
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+
+find_files "s.*" usr/src/common/net/dhcp
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile Tue Oct 30 11:15:43 2007 -0700
@@ -29,26 +29,21 @@
ROOTFS_PROG = $(PROG)
DEFAULTFILES = dhcpagent.dfl
-LOCOBJS = adopt.o agent.o async.o bound.o class_id.o defaults.o \
- dlpi_io.o inform.o init_reboot.o interface.o ipc_action.o \
- packet.o release.o renew.o request.o script_handler.o select.o \
- states.o util.o
-COMDIR = $(SRC)/common/net/dhcp
-COMOBJS = ipv4_sum.o udp_sum.o
+OBJS = adopt.o agent.o async.o bound.o class_id.o defaults.o inform.o \
+ init_reboot.o interface.o ipc_action.o packet.o release.o renew.o \
+ request.o script_handler.o select.o states.o util.o
include ../../../Makefile.cmd
-OBJS = $(COMOBJS) $(LOCOBJS)
-SRCS = $(COMOBJS:%.o=$(COMDIR)/%.c) $(LOCOBJS:%.o=%.c)
-
-POFILES = $(LOCOBJS:%.o=%.po)
+SRCS = $(OBJS:%.o=%.c)
+POFILES = $(OBJS:%.o=%.po)
XGETFLAGS += -a -x dhcpagent.xcl
#
# to compile a debug version, do a `make COPTFLAG="-g -XO0"'
#
-CPPFLAGS += -I$(COMDIR) -D_XOPEN_SOURCE=500 -D__EXTENSIONS__
+CPPFLAGS += -D_XOPEN_SOURCE=500 -D__EXTENSIONS__
LDLIBS += -lxnet -lnvpair -ldhcpagent -ldhcputil -linetutil -ldevinfo -ldlpi
# Disable warnings that affect all XPG applications.
@@ -64,10 +59,6 @@
$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
$(POST_PROCESS)
-%.o: $(COMDIR)/%.c
- $(COMPILE.c) $(OUTPUT_OPTION) $<
- $(POST_PROCESS_O)
-
$(POFILE): $(POFILES)
$(RM) $@; $(CAT) $(POFILES) > $@; $(RM) $(POFILES)
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/README Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/README Tue Oct 30 11:15:43 2007 -0700
@@ -81,8 +81,8 @@
difference between this and the first group is that the
interfaces exported from these files do not operate on
an "object", but rather perform a specific task. Examples
- include "dlpi_io.c", which provides a useful interface
- to DLPI-related i/o operations.
+ include "defaults.c", which provides a useful interface
+ to /etc/default/dhcpagent file operations.
OVERVIEW
========
@@ -306,9 +306,7 @@
the DHCP packet. Finally, send_pkt() and send_pkt_v6() can be used to
transmit the packet to a given IP address.
-The send_pkt() function is actually quite complicated; for one, it
-must internally use either DLPI or sockets depending on the machine
-state; for another, it handles the details of packet timeout and
+The send_pkt() function handles the details of packet timeout and
retransmission. The last argument to send_pkt() is a pointer to a
"stop function." If this argument is passed as NULL, then the packet
will only be sent once (it won't be retransmitted). Otherwise, before
@@ -325,24 +323,20 @@
The recv_pkt() function is simpler but still complicated by the fact
that one may want to receive several different types of packets at
-once and in different ways (DLPI or sockets). The caller registers an
-event handler on the file descriptor, and then calls recv_pkt() to
-read in the packet along with meta information about the message (the
-sender and interface identifier).
-
+once. The caller registers an event handler on the file descriptor,
+and then calls recv_pkt() to read in the packet along with meta
+information about the message (the sender and interface identifier).
+
For IPv6, packet reception is done with a single socket, using
IPV6_PKTINFO to determine the actual destination address and receiving
interface. Packets are then matched against the state machines on the
given interface through the transaction ID.
-The same facility exists for inbound IPv4 packets, but because there's
-no IP_PKTINFO processing on output yet in Solaris, and because IPv4
-still relies on DLPI, DHCP packets are handled on a per-LIF (when
-bound) and per-PIF (when unbound) basis. Eventually, when IP_PKTINFO
-is available for IPv4, the per-LIF sockets can go away. If it ever
-becomes possible to send and receive IP packets without having an IP
-address configured on an interface, then the DLPI streams can go as
-well.
+For IPv4, due to oddities in the DHCP specification (discussed in
+PSARC/2007/571), a special IP_DHCPINIT_IF socket option must be used
+to allow unicast DHCP traffic to be received on an interface during
+lease acquisition. Since the IP_DHCPINIT_IF socket option can only
+enable one interface at a time, one socket must be used per interface.
Time
----
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/README.v6 Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/README.v6 Tue Oct 30 11:15:43 2007 -0700
@@ -22,6 +22,15 @@
ident "%Z%%M% %I% %E% SMI"
+
+** PLEASE NOTE:
+**
+** This document discusses aspects of the DHCPv4 client design that have
+** since changed (e.g., DLPI is no longer used). However, since those
+** aspects affected the DHCPv6 design, the discussion has been left for
+** historical record.
+
+
DHCPv6 Client Low-Level Design
Introduction
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c Tue Oct 30 11:15:43 2007 -0700
@@ -1163,6 +1163,7 @@
lif->lif_name);
lif_mark_decline(lif, "duplicate address");
close_ip_lif(lif);
+ (void) open_ip_lif(lif, INADDR_ANY);
}
dad_wait = lif->lif_dad_wait;
@@ -1404,20 +1405,8 @@
* remove them from the list. Any leases that become empty are
* also removed as part of the decline-generation process.
*/
- if (dsmp->dsm_lif_down != 0) {
- /*
- * We need to switch back to PRE_BOUND state so that
- * send_pkt_internal() uses DLPI instead of sockets.
- * Our logical interface has already been torn down by
- * the kernel, and thus we can't send DHCPDECLINE by
- * way of regular IP. (Unless we're adopting -- allow
- * the grandparent to be handled as expected.)
- */
- if (oldstate != ADOPTING) {
- (void) set_smach_state(dsmp, PRE_BOUND);
- }
+ if (dsmp->dsm_lif_down != 0)
send_declines(dsmp);
- }
if (dsmp->dsm_leases == NULL) {
dsmp->dsm_bad_offers++;
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c Tue Oct 30 11:15:43 2007 -0700
@@ -337,7 +337,7 @@
*/
if (dsmp->dsm_isv6) {
(void) set_smach_state(dsmp, BOUND);
- dhcpmsg(MSG_DEBUG, "configure_bound: bound %s",
+ dhcpmsg(MSG_DEBUG, "dhcp_bound_complete: bound %s",
dsmp->dsm_name);
(void) script_start(dsmp, EVENT_BOUND6, bound_event_cb, NULL,
NULL);
@@ -363,7 +363,7 @@
dsmp->dsm_nrouters = router_list->len / sizeof (ipaddr_t);
dsmp->dsm_routers = malloc(router_list->len);
if (dsmp->dsm_routers == NULL) {
- dhcpmsg(MSG_ERR, "configure_bound: cannot allocate "
+ dhcpmsg(MSG_ERR, "dhcp_bound_complete: cannot allocate "
"default router list, ignoring default routers");
dsmp->dsm_nrouters = 0;
}
@@ -376,8 +376,8 @@
if (!add_default_route(lif->lif_pif->pif_index,
&dsmp->dsm_routers[i])) {
- dhcpmsg(MSG_ERR, "configure_bound: cannot add "
- "default router %s on %s", inet_ntoa(
+ dhcpmsg(MSG_ERR, "dhcp_bound_complete: cannot "
+ "add default router %s on %s", inet_ntoa(
dsmp->dsm_routers[i]), dsmp->dsm_name);
dsmp->dsm_routers[i].s_addr = htonl(INADDR_ANY);
continue;
@@ -391,12 +391,12 @@
oldstate = dsmp->dsm_state;
if (!set_smach_state(dsmp, BOUND)) {
dhcpmsg(MSG_ERR,
- "configure_bound: cannot set bound state on %s",
+ "dhcp_bound_complete: cannot set bound state on %s",
dsmp->dsm_name);
return;
}
- dhcpmsg(MSG_DEBUG, "configure_bound: bound %s", dsmp->dsm_name);
+ dhcpmsg(MSG_DEBUG, "dhcp_bound_complete: bound %s", dsmp->dsm_name);
/*
* We're now committed to this binding, so if it came from BOOTP, set
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c Tue Oct 30 09:32:44 2007 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,343 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/pfmod.h>
-#include <sys/socket.h>
-#include <netinet/in.h> /* in_addr (ip.h) */
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <stropts.h>
-#include <string.h> /* strpbrk */
-#include <sys/uio.h>
-#include <stdlib.h>
-#include <dhcpmsg.h>
-
-#include "dlpi_io.h"
-#include "v4_sum_impl.h"
-#include "common.h"
-
-/*
- * timeout to wait for acknowledgement of packet filter, in seconds.
- */
-#define FILTER_TIMEOUT 5
-
-/*
- * dlpi_recvfrom(): receives data on a DLPI stream
- *
- * input: dlpi_handle_t: dlpi handle to receive the data on
- * void *: a buffer to store the data in
- * size_t: the size of the buffer
- * struct sockaddr_in *: if non-NULL, sender's IP address is filled in
- * struct sockaddr_in *: if non-NULL, recipient's IP address
- * output: ssize_t: the number of bytes read on success, -1 on failure
- */
-ssize_t
-dlpi_recvfrom(dlpi_handle_t dh, void *buf, size_t buflen,
- struct sockaddr_in *from, struct sockaddr_in *to)
-{
- struct ip *ip;
- struct udphdr *udphdr;
- void *msgbuf;
- size_t msglen;
- dlpi_recvinfo_t dlrecv;
- int rc;
-
- msglen = buflen + sizeof (struct ip) + sizeof (struct udphdr);
- msgbuf = malloc(msglen);
-
- if (msgbuf == NULL) {
- dhcpmsg(MSG_ERR, "dlpi_recvfrom: cannot allocate packet");
- return (-1);
- }
-
- rc = dlpi_recv(dh, NULL, NULL, msgbuf, &msglen, -1, &dlrecv);
- if (rc != DLPI_SUCCESS) {
- dhcpmsg(MSG_ERR, "dlpi_recvfrom: dlpi_recv failed: %s",
- dlpi_strerror(rc));
- free(msgbuf);
- return (-1);
- }
-
- /*
- * since we're just pulling data off the wire, what we have
- * may look nothing like a DHCP packet. note that this
- * shouldn't happen (pfmod should have tossed it already).
- */
- if (msglen < sizeof (struct ip) + sizeof (struct udphdr)) {
- dhcpmsg(MSG_WARNING, "dlpi_recvfrom: dropped short packet");
- free(msgbuf);
- return (-1);
- }
-
- if (msglen < dlrecv.dri_totmsglen) {
- dhcpmsg(MSG_WARNING, "dlpi_recvfrom: discarding stray "
- "data on streamhead");
- }
-
- /*
- * verify checksums
- */
- ip = msgbuf;
- if (ipv4cksum((uint16_t *)ip, ip->ip_hl << 2) != 0) {
- dhcpmsg(MSG_WARNING, "dlpi_recvfrom: dropped packet with bad "
- "ipv4 checksum");
- free(msgbuf);
- return (-1);
- }
-
- udphdr = (struct udphdr *)&ip[1];
- if ((udphdr->uh_sum != 0) &&
- (udp_chksum(udphdr, &ip->ip_src, &ip->ip_dst, ip->ip_p) != 0)) {
- dhcpmsg(MSG_WARNING, "dlpi_recvfrom: dropped packet with bad "
- "UDP checksum");
- free(msgbuf);
- return (-1);
- }
-
- msglen -= (sizeof (struct ip) + sizeof (struct udphdr));
- (void) memcpy(buf, &udphdr[1], msglen);
-
- if (from != NULL) {
- from->sin_family = AF_INET;
- from->sin_addr = ip->ip_src;
- from->sin_port = udphdr->uh_sport;
- }
-
- if (to != NULL) {
- to->sin_family = AF_INET;
- to->sin_addr = ip->ip_dst;
- to->sin_port = udphdr->uh_dport;
- }
-
- free(msgbuf);
- return (msglen);
-}
-
-/*
- * dlpi_sendto(): sends UDP packets on a DLPI stream
- *
- * input: dlpi_handle_t: dlpi handle to send the packet on
- * void *: a buffer to send
- * size_t: the size of the buffer
- * struct sockaddr_in *: the IP address to send the data to
- * uchar_t *: the link-layer destination address
- * size_t: the size of the link-layer destination address
- * output: ssize_t: the number of bytes sent on success, -1 on failure
- */
-ssize_t
-dlpi_sendto(dlpi_handle_t dh, void *buf, size_t buflen,
- struct sockaddr_in *to, uchar_t *dl_to, size_t dl_to_len)
-{
- struct ip *ip;
- struct udphdr *udphdr;
- void *msgbuf;
- size_t msglen;
- static uint16_t ip_id = 0;
- int rc;
-
- /*
- * TODO: someday we might want to support `to' not being
- * the same as INADDR_BROADCAST. we don't need the support
- * right now, but it's annoying to have a general interface
- * that only supports a specific function.
- */
- if (to->sin_addr.s_addr != htonl(INADDR_BROADCAST)) {
- dhcpmsg(MSG_ERROR, "dlpi_sendto: send to unicast address");
- return (-1);
- }
-
- /*
- * we allocate one extra byte here in case the UDP checksum
- * routine needs it to get the packet length to be even.
- */
- msglen = sizeof (struct ip) + sizeof (struct udphdr) + buflen;
- msgbuf = calloc(1, msglen + 1);
- if (msgbuf == NULL) {
- dhcpmsg(MSG_ERR, "dlpi_sendto: cannot allocate packet");
- return (-1);
- }
-
- ip = (struct ip *)msgbuf;
- udphdr = (struct udphdr *)&ip[1];
-
- (void) memcpy(&udphdr[1], buf, buflen);
-
- /*
- * build the ipv4 header. assume that our source address is 0
- * (since we wouldn't be using DLPI if we could actually send
- * packets an easier way). note that we only need to set nonzero
- * fields since we got calloc()'d memory above.
- */
-
- /*
- * From a purist's perspective, we should set the TTL to 1 for
- * limited broadcasts. But operational experience (cisco routers)
- * has shown that doing so results in the relay agent dropping our
- * packets. These same devices (ciscos) also don't set the TTL
- * to MAXTTL on the unicast side of the relay agent. Thus, the only
- * safe thing to do is to always set the ttl to MAXTTL. Sigh.
- */
-
- ip->ip_ttl = MAXTTL;
-
- ip->ip_v = 4;
- ip->ip_hl = sizeof (struct ip) / 4;
- ip->ip_id = htons(ip_id++);
- ip->ip_off = htons(IP_DF);
- ip->ip_p = IPPROTO_UDP;
- ip->ip_len = htons(msglen);
- ip->ip_dst = to->sin_addr;
- ip->ip_src.s_addr = htonl(INADDR_ANY);
- ip->ip_sum = ipv4cksum((uint16_t *)ip, sizeof (struct ip));
-
- udphdr->uh_ulen = htons(sizeof (struct udphdr) + buflen);
- udphdr->uh_sport = htons(IPPORT_BOOTPC);
- udphdr->uh_dport = htons(IPPORT_BOOTPS);
- udphdr->uh_sum = udp_chksum(udphdr, &ip->ip_src, &ip->ip_dst, ip->ip_p);
-
- rc = dlpi_send(dh, dl_to, dl_to_len, msgbuf, msglen, NULL);
- if (rc != DLPI_SUCCESS) {
- free(msgbuf);
- dhcpmsg(MSG_ERR, "dlpi_sendto: dlpi_send: %s",
- dlpi_strerror(rc));
- return (-1);
- }
-
- free(msgbuf);
- return (buflen);
-}
-
-/*
- * set_packet_filter(): sets the current packet filter on a DLPI stream
- *
- * input: dlpi_handle_t: the DLPI handle to set the packet filter on
- * filter_func_t *: the filter to use
- * void *: an argument to pass to the filter function
- * const char *: a text description of the filter's purpose
- * output: boolean_t: B_TRUE on success, B_FALSE on failure.
- */
-boolean_t
-set_packet_filter(dlpi_handle_t dh, filter_func_t *filter, void *arg,
- const char *filter_name)
-{
- struct strioctl sioc;
- struct packetfilt pf;
- ushort_t *pfp = pf.Pf_Filter;
- int fd = dlpi_fd(dh);
-
- if (ioctl(fd, I_PUSH, "pfmod") == -1) {
- dhcpmsg(MSG_ERR,
- "open_dlpi_pif: cannot push pfmod on stream");
- return (B_FALSE);
- }
-
- pf.Pf_FilterLen = filter(pfp, arg) - pf.Pf_Filter;
-
- sioc.ic_cmd = PFIOCSETF;
- sioc.ic_timout = FILTER_TIMEOUT;
- sioc.ic_len = sizeof (struct packetfilt);
- sioc.ic_dp = (caddr_t)&pf;
-
- /*
- * if this ioctl() fails, we're really hosed. the best we can
- * really do is play on.
- */
-
- if (ioctl(fd, I_STR, &sioc) == -1)
- dhcpmsg(MSG_ERR, "set_packet_filter: PFIOCSETF");
- else
- dhcpmsg(MSG_DEBUG, "set_packet_filter: set filter %p "
- "(%s filter)", (void *)filter, filter_name);
-
- /*
- * clean out any potential cruft on the descriptor that
- * appeared before we were able to set the filter
- */
-
- (void) ioctl(fd, I_FLUSH, FLUSHR);
-
- return (B_TRUE);
-}
-
-/*
- * dhcp_filter(): builds a packet filter that permits only DHCP/BOOTP messages
- *
- * input: ushort_t *: a place to store the packet filter code
- * void *: not used
- * output: ushort_t *: two bytes past the last byte in the packet filter
- */
-
-/* ARGSUSED */
-ushort_t *
-dhcp_filter(ushort_t *pfp, void *arg)
-{
- /*
- * only pass up UDP packets -- 8th byte is the ttl/proto field
- */
-
- *pfp++ = ENF_PUSHWORD + 4;
- *pfp++ = ENF_PUSHLIT | ENF_AND;
- *pfp++ = htons(0xff);
- *pfp++ = ENF_PUSHLIT | ENF_CAND;
- *pfp++ = htons(IPPROTO_UDP);
-
- /*
- * make sure the IP packet doesn't have any options. 2nd
- * nibble is the header length field.
- * TODO: if we decide to handle options, this code goes away.
- */
-
- *pfp++ = ENF_PUSHWORD + 0;
- *pfp++ = ENF_PUSHLIT | ENF_AND;
- *pfp++ = htons(0x0f00); /* only care about 2nd nibble */
- *pfp++ = ENF_PUSHLIT | ENF_CAND;
- *pfp++ = htons(0x0500); /* which should be 5 * 4 = 20 */
-
- /*
- * if there's a fragment offset, or if the IP_MF bit is lit,
- * pitch the packet. this pitches all fragments.
- * TODO: if we decide to handle fragments, this code goes away.
- */
-
- *pfp++ = ENF_PUSHWORD + 3;
- *pfp++ = ENF_PUSHLIT | ENF_AND;
- *pfp++ = htons(0x1fff | IP_MF);
- *pfp++ = ENF_PUSHZERO | ENF_CAND;
-
- /*
- * make sure the packet is for the DHCP client port -- 22nd
- * byte is the UDP port number.
- */
-
- *pfp++ = ENF_PUSHWORD + 11;
- *pfp++ = ENF_PUSHLIT | ENF_CAND;
- *pfp++ = htons(IPPORT_BOOTPC);
-
- return (pfp);
-}
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.h Tue Oct 30 09:32:44 2007 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef DLPI_IO_H
-#define DLPI_IO_H
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <libdlpi.h>
-
-/*
- * dlpi_io.[ch] contain the interface the agent uses to interact with
- * DLPI for data transfer primitives. see dlpi_io.c for documentation
- * on how to use the exported functions.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef ushort_t *filter_func_t(ushort_t *, void *);
-
-filter_func_t dhcp_filter;
-boolean_t set_packet_filter(dlpi_handle_t, filter_func_t *, void *,
- const char *);
-ssize_t dlpi_recvfrom(dlpi_handle_t, void *, size_t,
- struct sockaddr_in *, struct sockaddr_in *);
-ssize_t dlpi_sendto(dlpi_handle_t, void *, size_t, struct sockaddr_in *,
- uchar_t *, size_t);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* DLPI_IO_H */
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/inc.flg Tue Oct 30 09:32:44 2007 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-#!/bin/sh
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright (c) 1999 by Sun Microsystems, Inc.
-# All rights reserved.
-#
-
-find_files "s.*" usr/src/common/net/dhcp
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.c Tue Oct 30 11:15:43 2007 -0700
@@ -41,12 +41,10 @@
#include <arpa/inet.h>
#include <dhcpmsg.h>
#include <dhcp_inittab.h>
-#include <stropts.h>
#include "agent.h"
#include "interface.h"
#include "util.h"
-#include "dlpi_io.h"
#include "packet.h"
#include "states.h"
@@ -80,6 +78,7 @@
{
dhcp_pif_t *pif;
struct lifreq lifr;
+ dlpi_handle_t dh = NULL;
if ((pif = calloc(1, sizeof (*pif))) == NULL) {
dhcpmsg(MSG_ERR, "insert_pif: cannot allocate pif entry for "
@@ -89,8 +88,6 @@
}
pif->pif_isv6 = isv6;
- pif->pif_dlpi_hd = NULL;
- pif->pif_dlpi_id = -1;
pif->pif_hold_count = 1;
pif->pif_running = B_TRUE;
@@ -104,17 +101,14 @@
/* We do not use DLPI with DHCPv6 */
if (!isv6) {
int rc;
- dlpi_handle_t dh;
dlpi_info_t dlinfo;
/*
* Do the allocations necessary for IPv4 DHCP.
*
* 1. open the interface using DLPI
- * 2. get the interface max SDU
- * 3. get the interface hardware type and hardware length
- * 4. get the interface hardware address
- * 5. get the interface hardware broadcast address
+ * 2. get the interface hardware type and hardware length
+ * 3. get the interface hardware address
*/
/* step 1 */
@@ -124,7 +118,6 @@
*error = DHCP_IPC_E_INVIF;
goto failure;
}
- pif->pif_dlpi_hd = dh;
if ((rc = dlpi_bind(dh, ETHERTYPE_IP, NULL)) != DLPI_SUCCESS) {
dhcpmsg(MSG_ERROR, "insert_pif: dlpi_bind: %s",
@@ -134,7 +127,7 @@
}
/* step 2 */
- rc = dlpi_info(pif->pif_dlpi_hd, &dlinfo, 0);
+ rc = dlpi_info(dh, &dlinfo, 0);
if (rc != DLPI_SUCCESS) {
dhcpmsg(MSG_ERROR, "insert_pif: dlpi_info: %s",
dlpi_strerror(rc));
@@ -142,25 +135,13 @@
goto failure;
}
- pif->pif_max = dlinfo.di_max_sdu;
- if (pif->pif_max < DHCP_DEF_MAX_SIZE) {
- dhcpmsg(MSG_ERROR, "insert_pif: %s does not have a "
- "large enough maximum SDU to support DHCP "
- "(%u < %u)", pname, pif->pif_max,
- DHCP_DEF_MAX_SIZE);
- *error = DHCP_IPC_E_INVIF;
- goto failure;
- }
-
- /* step 3 */
pif->pif_hwtype = dlpi_arptype(dlinfo.di_mactype);
pif->pif_hwlen = dlinfo.di_physaddrlen;
- dhcpmsg(MSG_DEBUG, "insert_pif: %s: sdumax %u, hwtype %d, "
- "hwlen %d", pname, pif->pif_max, pif->pif_hwtype,
- pif->pif_hwlen);
+ dhcpmsg(MSG_DEBUG, "insert_pif: %s: hwtype %d, hwlen %d",
+ pname, pif->pif_hwtype, pif->pif_hwlen);
- /* step 4 */
+ /* step 3 */
if (pif->pif_hwlen > 0) {
pif->pif_hwaddr = malloc(pif->pif_hwlen);
if (pif->pif_hwaddr == NULL) {
@@ -169,29 +150,12 @@
*error = DHCP_IPC_E_MEMORY;
goto failure;
}
+ (void) memcpy(pif->pif_hwaddr, dlinfo.di_physaddr,
+ pif->pif_hwlen);
}
- (void) memcpy(pif->pif_hwaddr, dlinfo.di_physaddr,
- pif->pif_hwlen);
-
- /*
- * step 5
- * Some media types has no broadcast address.
- */
- if ((pif->pif_dlen = dlinfo.di_bcastaddrlen) != 0) {
- pif->pif_daddr = malloc(pif->pif_dlen);
- if (pif->pif_daddr == NULL) {
- dhcpmsg(MSG_ERR, "insert_pif: cannot allocate "
- "pif_daddr for %s", pname);
- *error = DHCP_IPC_E_MEMORY;
- goto failure;
- }
- }
- (void) memcpy(pif->pif_daddr, dlinfo.di_bcastaddr,
- pif->pif_dlen);
-
- /* Close the DLPI stream until actually needed */
- close_dlpi_pif(pif);
+ dlpi_close(dh);
+ dh = NULL;
}
/*
@@ -202,20 +166,34 @@
(void) strlcpy(lifr.lifr_name, pname, LIFNAMSIZ);
if (ioctl(isv6 ? v6_sock_fd : v4_sock_fd, SIOCGLIFINDEX, &lifr) == -1) {
- if (errno == ENXIO)
- *error = DHCP_IPC_E_INVIF;
- else
- *error = DHCP_IPC_E_INT;
+ *error = (errno == ENXIO) ? DHCP_IPC_E_INVIF : DHCP_IPC_E_INT;
dhcpmsg(MSG_ERR, "insert_pif: SIOCGLIFINDEX for %s", pname);
goto failure;
}
pif->pif_index = lifr.lifr_index;
+ if (ioctl(isv6 ? v6_sock_fd : v4_sock_fd, SIOCGLIFMTU, &lifr) == -1) {
+ *error = (errno == ENXIO) ? DHCP_IPC_E_INVIF : DHCP_IPC_E_INT;
+ dhcpmsg(MSG_ERR, "insert_pif: SIOCGLIFMTU for %s", pname);
+ goto failure;
+ }
+ pif->pif_max = lifr.lifr_mtu;
+
+ if (pif->pif_max < DHCP_DEF_MAX_SIZE) {
+ dhcpmsg(MSG_ERROR, "insert_pif: MTU of %s is too small to "
+ "support DHCP (%u < %u)", pname, pif->pif_max,
+ DHCP_DEF_MAX_SIZE);
+ *error = DHCP_IPC_E_INVIF;
+ goto failure;
+ }
+
insque(pif, isv6 ? &v6root : &v4root);
return (pif);
failure:
+ if (dh != NULL)
+ dlpi_close(dh);
release_pif(pif);
return (NULL);
}
@@ -256,10 +234,7 @@
pif->pif_name);
remque(pif);
- pif->pif_dlpi_count = 1;
- close_dlpi_pif(pif);
free(pif->pif_hwaddr);
- free(pif->pif_daddr);
free(pif);
} else {
dhcpmsg(MSG_DEBUG2, "release_pif: hold count on %s: %u",
@@ -343,80 +318,9 @@
}
/*
- * open_dlpi_pif(): register the use of DLPI I/O by a LIF on a PIF, opening
- * the connection if necessary.
- *
- * input: dhcp_pif_t *: the physical interface on which to use DLPI
- * output: boolean_t: B_TRUE on success, B_FALSE on failure.
- */
-
-boolean_t
-open_dlpi_pif(dhcp_pif_t *pif)
-{
- int rc;
- dlpi_handle_t dh;
-
- if (pif->pif_dlpi_hd == NULL) {
- if ((rc = dlpi_open(pif->pif_name, &dh, 0)) != DLPI_SUCCESS) {
- dhcpmsg(MSG_ERROR, "open_dlpi_pif: dlpi_open: %s",
- dlpi_strerror(rc));
- return (B_FALSE);
- }
-
- if ((rc = dlpi_bind(dh, ETHERTYPE_IP, NULL)) != DLPI_SUCCESS) {
- dhcpmsg(MSG_ERROR, "open_dlpi_pif: dlpi_bind: %s",
- dlpi_strerror(rc));
- dlpi_close(dh);
- return (B_FALSE);
- }
-
- if (!(set_packet_filter(dh, dhcp_filter, NULL, "DHCP"))) {
- dlpi_close(dh);
- return (B_FALSE);
- }
- pif->pif_dlpi_id = iu_register_event(eh, dlpi_fd(dh), POLLIN,
- dhcp_collect_dlpi, pif);
- if (pif->pif_dlpi_id == -1) {
- dlpi_close(dh);
- return (B_FALSE);
- }
-
- pif->pif_dlpi_hd = dh;
- }
- pif->pif_dlpi_count++;
- return (B_TRUE);
-}
-
-/*
- * close_dlpi_pif(): unregister the use of DLPI I/O by a LIF on a PIF, closing
- * the connection if this was the last user.
- *
- * input: dhcp_pif_t *: the physical interface on which we're using DLPI
- * output: none
- */
-
-void
-close_dlpi_pif(dhcp_pif_t *pif)
-{
- if (pif->pif_dlpi_count > 1) {
- pif->pif_dlpi_count--;
- return;
- }
- pif->pif_dlpi_count = 0;
- if (pif->pif_dlpi_id != -1) {
- (void) iu_unregister_event(eh, pif->pif_dlpi_id, NULL);
- pif->pif_dlpi_id = -1;
- }
- if (pif->pif_dlpi_hd != NULL) {
- dlpi_close(pif->pif_dlpi_hd);
- pif->pif_dlpi_hd = NULL;
- }
-}
-
-/*
* pif_status(): update the physical interface up/down status.
*
- * input: dhcp_pif_t *: the physical interface on which we're using DLPI
+ * input: dhcp_pif_t *: the physical interface to be updated
* boolean_t: B_TRUE if the interface is going up
* output: none
*/
@@ -478,7 +382,7 @@
}
lif->lif_sock_ip_fd = -1;
- lif->lif_acknak_id = -1;
+ lif->lif_packet_id = -1;
lif->lif_iaid_id = -1;
lif->lif_hold_count = 1;
lif->lif_pif = pif;
@@ -729,6 +633,8 @@
boolean_t isv6;
int fd;
struct lifreq lifr;
+ char abuf1[INET6_ADDRSTRLEN];
+ char abuf2[INET6_ADDRSTRLEN];
(void) memset(&lifr, 0, sizeof (struct lifreq));
(void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ);
@@ -748,32 +654,27 @@
} else if (isv6) {
struct sockaddr_in6 *sin6 =
(struct sockaddr_in6 *)&lifr.lifr_addr;
- char abuf1[INET6_ADDRSTRLEN];
- char abuf2[INET6_ADDRSTRLEN];
if (!IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, addr)) {
dhcpmsg(MSG_WARNING,
- "checkaddr: expected %s %s on %s, have %s",
- aname, inet_ntop(AF_INET6, &sin6->sin6_addr, abuf1,
- sizeof (abuf1)), lif->lif_name,
- inet_ntop(AF_INET6, addr, abuf2, sizeof (abuf2)));
+ "checkaddr: expected %s %s on %s, have %s", aname,
+ inet_ntop(AF_INET6, addr, abuf1, sizeof (abuf1)),
+ lif->lif_name, inet_ntop(AF_INET6, &sin6->sin6_addr,
+ abuf2, sizeof (abuf2)));
return (B_FALSE);
}
} else {
struct sockaddr_in *sinp =
(struct sockaddr_in *)&lifr.lifr_addr;
ipaddr_t v4addr;
- char abuf1[INET_ADDRSTRLEN];
- char abuf2[INET_ADDRSTRLEN];
IN6_V4MAPPED_TO_IPADDR(addr, v4addr);
if (sinp->sin_addr.s_addr != v4addr) {
dhcpmsg(MSG_WARNING,
- "checkaddr: expected %s %s on %s, have %s",
- aname, inet_ntop(AF_INET, &sinp->sin_addr, abuf1,
- sizeof (abuf1)), lif->lif_name,
- inet_ntop(AF_INET, &v4addr, abuf2,
- sizeof (abuf2)));
+ "checkaddr: expected %s %s on %s, have %s", aname,
+ inet_ntop(AF_INET, &v4addr, abuf1, sizeof (abuf1)),
+ lif->lif_name, inet_ntop(AF_INET, &sinp->sin_addr,
+ abuf2, sizeof (abuf2)));
return (B_FALSE);
}
}
@@ -896,11 +797,12 @@
* unplumb_lif().
*
* input: dhcp_lif_t *: the interface to canonize
+ * boolean_t: only canonize lif if it's under DHCP control
* output: none
*/
static void
-canonize_lif(dhcp_lif_t *lif)
+canonize_lif(dhcp_lif_t *lif, boolean_t dhcponly)
{
boolean_t isv6;
int fd;
@@ -934,8 +836,7 @@
return;
}
- /* Should not happen */
- if (!(lifr.lifr_flags & IFF_DHCPRUNNING)) {
+ if (dhcponly && !(lifr.lifr_flags & IFF_DHCPRUNNING)) {
dhcpmsg(MSG_INFO,
"canonize_lif: cannot clear %s; flags are %llx",
lif->lif_name, lifr.lifr_flags);
@@ -1117,7 +1018,7 @@
* just canonize it and remove it from the lease.
*/
if ((dlp = lif->lif_lease) != NULL && dlp->dl_smach->dsm_lif == lif) {
- canonize_lif(lif);
+ canonize_lif(lif, B_TRUE);
cancel_lif_timers(lif);
if (lif->lif_declined != NULL) {
dlp->dl_smach->dsm_lif_down--;
@@ -1349,12 +1250,17 @@
* open_ip_lif(): open up an IP socket for I/O on a given LIF (v4 only).
*
* input: dhcp_lif_t *: the logical interface to operate on
+ * in_addr_t: the address the socket will be bound to (in hbo)
* output: boolean_t: B_TRUE if the socket was opened successfully.
*/
boolean_t
-open_ip_lif(dhcp_lif_t *lif)
+open_ip_lif(dhcp_lif_t *lif, in_addr_t addr_hbo)
{
+ const char *errmsg;
+ struct lifreq lifr;
+ int on = 1;
+
if (lif->lif_sock_ip_fd != -1) {
dhcpmsg(MSG_WARNING, "open_ip_lif: socket already open on %s",
lif->lif_name);
@@ -1363,27 +1269,90 @@
lif->lif_sock_ip_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (lif->lif_sock_ip_fd == -1) {
- dhcpmsg(MSG_ERR, "open_ip_lif: cannot create v4 socket on %s",
- lif->lif_name);
- return (B_FALSE);
+ errmsg = "cannot create v4 socket";
+ goto failure;
+ }
+
+ if (!bind_sock(lif->lif_sock_ip_fd, IPPORT_BOOTPC, addr_hbo)) {
+ errmsg = "cannot bind v4 socket";
+ goto failure;
+ }
+
+ /*
+ * If we bound to INADDR_ANY, we have no IFF_UP source address to use.
+ * Thus, enable IP_UNSPEC_SRC so that we can send packets with an
+ * unspecified (0.0.0.0) address. Also, enable IP_DHCPINIT_IF so that
+ * the IP module will accept unicast DHCP traffic regardless of the IP
+ * address it's sent to. (We'll then figure out which packets are
+ * ours based on the xid.)
+ */
+ if (addr_hbo == INADDR_ANY) {
+ if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_UNSPEC_SRC,
+ &on, sizeof (int)) == -1) {
+ errmsg = "cannot set IP_UNSPEC_SRC";
+ goto failure;
+ }
+
+ if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_DHCPINIT_IF,
+ &lif->lif_pif->pif_index, sizeof (int)) == -1) {
+ errmsg = "cannot set IP_DHCPINIT_IF";
+ goto failure;
+ }
+ }
+
+ if (setsockopt(lif->lif_sock_ip_fd, IPPROTO_IP, IP_BOUND_IF,
+ &lif->lif_pif->pif_index, sizeof (int)) == -1) {
+ errmsg = "cannot set IP_BOUND_IF";
+ goto failure;
}
- if (!bind_sock(lif->lif_sock_ip_fd, IPPORT_BOOTPC,
- ntohl(lif->lif_addr))) {
- dhcpmsg(MSG_ERR, "open_ip_lif: cannot bind v4 socket on %s",
- lif->lif_name);
- return (B_FALSE);
+ /*
+ * Make sure at least one lif on the interface we used in IP_BOUND_IF
+ * is IFF_UP so that we can send and receive IP packets.
+ */
+ (void) strlcpy(lifr.lifr_name, lif->lif_name, LIFNAMSIZ);
+ if (ioctl(v4_sock_fd, SIOCGLIFFLAGS, &lifr) == -1) {
+ errmsg = "cannot get interface flags";
+ goto failure;
}
- lif->lif_acknak_id = iu_register_event(eh, lif->lif_sock_ip_fd, POLLIN,
- dhcp_acknak_lif, lif);
- if (lif->lif_acknak_id == -1) {
- dhcpmsg(MSG_WARNING, "open_ip_lif: cannot register to "
- "receive IP unicast");
- close_ip_lif(lif);
- return (B_FALSE);
+ if (!(lifr.lifr_flags & IFF_UP)) {
+ /*
+ * Start from a clean slate.
+ */
+ canonize_lif(lif, B_FALSE);
+
+ lifr.lifr_flags |= IFF_UP;
+ if (ioctl(v4_sock_fd, SIOCSLIFFLAGS, &lifr) == -1) {
+ errmsg = "cannot bring up";
+ goto failure;
+ }
+
+ /*
+ * When bringing 0.0.0.0 IFF_UP, the kernel changes the
+ * netmask to 255.0.0.0, so re-fetch our expected netmask.
+ */
+ if (ioctl(v4_sock_fd, SIOCGLIFNETMASK, &lifr) == -1) {
+ errmsg = "cannot get netmask";
+ goto failure;
+ }
+
+ lif->lif_netmask =
+ ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr.s_addr;
}
+
+ lif->lif_packet_id = iu_register_event(eh, lif->lif_sock_ip_fd, POLLIN,
+ dhcp_packet_lif, lif);
+ if (lif->lif_packet_id == -1) {
+ errmsg = "cannot register to receive DHCP packets";
+ goto failure;
+ }
+
return (B_TRUE);
+failure:
+ dhcpmsg(MSG_ERR, "open_ip_lif: %s: %s", lif->lif_name, errmsg);
+ close_ip_lif(lif);
+ return (B_FALSE);
}
/*
@@ -1396,9 +1365,9 @@
void
close_ip_lif(dhcp_lif_t *lif)
{
- if (lif->lif_acknak_id != -1) {
- (void) iu_unregister_event(eh, lif->lif_acknak_id, NULL);
- lif->lif_acknak_id = -1;
+ if (lif->lif_packet_id != -1) {
+ (void) iu_unregister_event(eh, lif->lif_packet_id, NULL);
+ lif->lif_packet_id = -1;
}
if (lif->lif_sock_ip_fd != -1) {
(void) close(lif->lif_sock_ip_fd);
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.h Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.h Tue Oct 30 11:15:43 2007 -0700
@@ -47,7 +47,6 @@
#include <netinet/dhcp.h>
#include <dhcpagent_ipc.h>
#include <libinetutil.h>
-#include <libdlpi.h>
#include "common.h"
#include "util.h"
@@ -65,14 +64,7 @@
uchar_t pif_hwtype; /* type of link-layer */
boolean_t pif_isv6;
boolean_t pif_running; /* interface is running */
- dlpi_handle_t pif_dlpi_hd; /* dlpi handle */
- int pif_dlpi_count;
- iu_event_id_t pif_dlpi_id; /* event id for ack/nak/offer */
uint_t pif_hold_count; /* reference count */
-
- uchar_t *pif_daddr; /* our L2 destination address */
- uchar_t pif_dlen; /* our L2 destination address len */
-
char pif_name[LIFNAMSIZ];
};
@@ -84,7 +76,7 @@
dhcp_lease_t *lif_lease; /* backpointer to lease holding LIF */
uint64_t lif_flags; /* Interface flags (IFF_*) */
int lif_sock_ip_fd; /* Bound to addr.BOOTPC for src addr */
- iu_event_id_t lif_acknak_id; /* event acknak id */
+ iu_event_id_t lif_packet_id; /* event packet id */
uint_t lif_max; /* maximum IP message size */
uint_t lif_hold_count; /* reference count */
boolean_t lif_dad_wait; /* waiting for DAD resolution */
@@ -177,8 +169,6 @@
dhcp_pif_t *lookup_pif_by_index(uint_t, boolean_t);
dhcp_pif_t *lookup_pif_by_uindex(uint16_t, dhcp_pif_t *, boolean_t);
dhcp_pif_t *lookup_pif_by_name(const char *, boolean_t);
-boolean_t open_dlpi_pif(dhcp_pif_t *);
-void close_dlpi_pif(dhcp_pif_t *);
void pif_status(dhcp_pif_t *, boolean_t);
dhcp_lif_t *insert_lif(dhcp_pif_t *, const char *, int *);
@@ -193,7 +183,7 @@
int set_lif_dhcp(dhcp_lif_t *, boolean_t);
void set_lif_deprecated(dhcp_lif_t *);
boolean_t clear_lif_deprecated(dhcp_lif_t *);
-boolean_t open_ip_lif(dhcp_lif_t *);
+boolean_t open_ip_lif(dhcp_lif_t *, in_addr_t);
void close_ip_lif(dhcp_lif_t *);
void lif_mark_decline(dhcp_lif_t *, const char *);
boolean_t schedule_lif_timer(dhcp_lif_t *, dhcp_timer_t *,
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c Tue Oct 30 11:15:43 2007 -0700
@@ -46,7 +46,6 @@
#include "agent.h"
#include "packet.h"
#include "util.h"
-#include "dlpi_io.h"
int v6_sock_fd = -1;
int v4_sock_fd = -1;
@@ -157,19 +156,18 @@
dhcp_pkt_t *
init_pkt(dhcp_smach_t *dsmp, uchar_t type)
{
- uint_t mtu;
dhcp_pkt_t *dpkt = &dsmp->dsm_send_pkt;
dhcp_lif_t *lif = dsmp->dsm_lif;
dhcp_pif_t *pif = lif->lif_pif;
+ uint_t mtu = lif->lif_max;
uint32_t xid;
boolean_t isv6;
- mtu = dsmp->dsm_using_dlpi ? pif->pif_max : lif->lif_max;
dpkt->pkt_isv6 = isv6 = pif->pif_isv6;
/*
- * since multiple dhcp leases may be maintained over the same dlpi
- * device (e.g. "hme0" and "hme0:1"), make sure the xid is unique.
+ * Since multiple dhcp leases may be maintained over the same pif
+ * (e.g. "hme0" and "hme0:1"), make sure the xid is unique.
*
* Note that transaction ID zero is intentionally never assigned.
* That's used to represent "no ID." Also note that transaction IDs
@@ -250,14 +248,12 @@
* thus server can not unicast the reply. Per
* RFC 2131 4.4.1, client can set this bit in
* DISCOVER/REQUEST. If the client is already
- * in BOUND/REBINDING/RENEWING state, do not set
- * this bit, as it can respond to unicast responses
- * from server using the 'ciaddr' address.
+ * in a bound state, do not set this bit, as it
+ * can respond to unicast responses from server
+ * using the 'ciaddr' address.
*/
- if (type == DISCOVER ||
- (type == REQUEST && dsmp->dsm_state != RENEWING &&
- dsmp->dsm_state != REBINDING &&
- dsmp->dsm_state != BOUND))
+ if (type == DISCOVER || (type == REQUEST &&
+ !is_bound_state(dsmp->dsm_state)))
v4->flags = htons(BCAST_MASK);
}
@@ -804,7 +800,6 @@
{
ssize_t n_bytes;
dhcp_lif_t *lif = dsmp->dsm_lif;
- dhcp_pif_t *pif = lif->lif_pif;
dhcp_pkt_t *dpkt = &dsmp->dsm_send_pkt;
uchar_t ptype = pkt_send_type(dpkt);
const char *pkt_name;
@@ -813,6 +808,7 @@
struct cmsghdr *cmsg;
struct in6_pktinfo *ipi6;
boolean_t ismcast;
+ int msgtype;
/*
* Timer should not be running at the point we go to send a packet.
@@ -985,27 +981,19 @@
n_bytes = sendmsg(v6_sock_fd, &msg, 0);
} else {
- if (dsmp->dsm_using_dlpi) {
- n_bytes = dlpi_sendto(pif->pif_dlpi_hd, dpkt->pkt,
- dpkt->pkt_cur_len, &dsmp->dsm_send_dest.v4,
- pif->pif_daddr, pif->pif_dlen);
- /* dlpi_sendto calls putmsg */
- if (n_bytes == 0)
- n_bytes = dpkt->pkt_cur_len;
- } else {
- n_bytes = sendto(lif->lif_sock_ip_fd, dpkt->pkt,
- dpkt->pkt_cur_len, 0,
- (struct sockaddr *)&dsmp->dsm_send_dest.v4,
- sizeof (struct sockaddr_in));
- }
+ n_bytes = sendto(lif->lif_sock_ip_fd, dpkt->pkt,
+ dpkt->pkt_cur_len, 0,
+ (struct sockaddr *)&dsmp->dsm_send_dest.v4,
+ sizeof (struct sockaddr_in));
}
if (n_bytes != dpkt->pkt_cur_len) {
+ msgtype = (n_bytes == -1) ? MSG_ERR : MSG_WARNING;
if (dsmp->dsm_retrans_timer == -1)
- dhcpmsg(MSG_WARNING, "send_pkt_internal: cannot send "
+ dhcpmsg(msgtype, "send_pkt_internal: cannot send "
"%s packet to server", pkt_name);
else
- dhcpmsg(MSG_WARNING, "send_pkt_internal: cannot send "
+ dhcpmsg(msgtype, "send_pkt_internal: cannot send "
"%s packet to server (will retry in %u seconds)",
pkt_name, dsmp->dsm_send_timeout / MILLISEC);
return (B_FALSE);
@@ -1319,16 +1307,14 @@
/*
* recv_pkt(): receives a single DHCP packet on a given file descriptor.
*
- * input: int: if not using dlpi, the file descriptor to receive the packet
+ * input: int: the file descriptor to receive the packet from
* int: the maximum packet size to allow
* boolean_t: B_TRUE for IPv6
- * boolean_t: B_TRUE if using DLPI
- * void *: if using DLPI, structure that has DLPI handle
* output: PKT_LIST *: the received packet
*/
PKT_LIST *
-recv_pkt(int fd, int mtu, boolean_t isv6, boolean_t isdlpi, dhcp_pif_t *arg)
+recv_pkt(int fd, int mtu, boolean_t isv6)
{
PKT_LIST *plp;
ssize_t retval;
@@ -1339,41 +1325,21 @@
return (NULL);
}
- if (isv6) {
- retval = sock_recvpkt(fd, plp);
+ retval = sock_recvpkt(fd, plp);
+ if (retval == -1) {
+ dhcpmsg(MSG_ERR, "recv_pkt: recvfrom v%d failed, dropped",
+ isv6 ? 6 : 4);
+ goto failure;
+ }
- if (retval == -1) {
- dhcpmsg(MSG_ERR,
- "recv_pkt: recvfrom v6 failed, dropped");
- goto failure;
- }
+ plp->len = retval;
- plp->len = retval;
-
+ if (isv6) {
if (retval < sizeof (dhcpv6_message_t)) {
dhcpmsg(MSG_WARNING, "recv_pkt: runt message");
goto failure;
}
} else {
- if (isdlpi) {
- dhcp_pif_t *pif = arg;
-
- retval = dlpi_recvfrom(pif->pif_dlpi_hd, plp->pkt, mtu,
- (struct sockaddr_in *)&plp->pktfrom,
- (struct sockaddr_in *)&plp->pktto);
- } else {
- retval = sock_recvpkt(fd, plp);
- }
-
- if (retval == -1) {
- dhcpmsg(MSG_ERR,
- "recv_pkt: %srecvfrom v4 failed, dropped",
- isdlpi ? "dlpi_" : "");
- goto failure;
- }
-
- plp->len = retval;
-
switch (dhcp_options_scan(plp, B_TRUE)) {
case DHCP_WRONG_MSG_TYPE:
@@ -1576,7 +1542,7 @@
return (B_FALSE);
}
- if (iu_register_event(eh, v4_sock_fd, POLLIN, dhcp_acknak_common,
+ if (iu_register_event(eh, v4_sock_fd, POLLIN, dhcp_acknak_global,
NULL) == -1) {
dhcpmsg(MSG_WARNING, "dhcp_ip_default: cannot register to "
"receive IPv4 broadcasts");
@@ -1603,7 +1569,7 @@
return (B_FALSE);
}
- if (iu_register_event(eh, v6_sock_fd, POLLIN, dhcp_acknak_common,
+ if (iu_register_event(eh, v6_sock_fd, POLLIN, dhcp_acknak_global,
NULL) == -1) {
dhcpmsg(MSG_WARNING, "dhcp_ip_default: cannot register to "
"receive IPv6 packets");
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h Tue Oct 30 11:15:43 2007 -0700
@@ -130,7 +130,7 @@
boolean_t add_pkt_lif(dhcp_pkt_t *, dhcp_lif_t *, int, const char *);
void stop_pkt_retransmission(dhcp_smach_t *);
void retransmit_now(dhcp_smach_t *);
-PKT_LIST *recv_pkt(int, int, boolean_t, boolean_t, dhcp_pif_t *);
+PKT_LIST *recv_pkt(int, int, boolean_t);
boolean_t pkt_v4_match(uchar_t, dhcp_message_type_t);
void pkt_smach_enqueue(dhcp_smach_t *, PKT_LIST *);
boolean_t send_pkt(dhcp_smach_t *, dhcp_pkt_t *, in_addr_t,
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c Tue Oct 30 11:15:43 2007 -0700
@@ -372,7 +372,7 @@
/*
* Look through the packet contents. Valid packets must have our
* client ID and a server ID, which has already been checked by
- * dhcp_acknak_lif. Bonus points for each option.
+ * dhcp_packet_lif. Bonus points for each option.
*/
/* One point for having a valid message. */
@@ -959,7 +959,7 @@
}
/*
- * dhcp_acknak_common(): Processes reception of an ACK or NAK packet on the
+ * dhcp_acknak_global(): Processes reception of an ACK or NAK packet on the
* global socket -- broadcast packets for IPv4, all
* packets for DHCPv6.
*
@@ -973,7 +973,7 @@
/* ARGSUSED */
void
-dhcp_acknak_common(iu_eh_t *ehp, int fd, short events, iu_event_id_t id,
+dhcp_acknak_global(iu_eh_t *ehp, int fd, short events, iu_event_id_t id,
void *arg)
{
PKT_LIST *plp;
@@ -983,14 +983,18 @@
uint_t xid;
dhcp_smach_t *dsmp;
boolean_t isv6 = (fd == v6_sock_fd);
+ struct sockaddr_in sin;
+ const char *reason;
+ size_t sinlen = sizeof (sin);
+ int sock;
- plp = recv_pkt(fd, get_max_mtu(isv6), isv6, B_FALSE, NULL);
+ plp = recv_pkt(fd, get_max_mtu(isv6), isv6);
if (plp == NULL)
return;
pif = lookup_pif_by_index(plp->ifindex, isv6);
if (pif == NULL) {
- dhcpmsg(MSG_VERBOSE, "dhcp_acknak_common: ignored packet "
+ dhcpmsg(MSG_VERBOSE, "dhcp_acknak_global: ignored packet "
"received on v%d ifIndex %d", isv6 ? 6 : 4, plp->ifindex);
free_pkt_entry(plp);
return;
@@ -998,33 +1002,45 @@
recv_type = pkt_recv_type(plp);
pname = pkt_type_to_string(recv_type, isv6);
- if (!isv6 && !pkt_v4_match(recv_type, DHCP_PACK|DHCP_PNAK)) {
- dhcpmsg(MSG_VERBOSE, "dhcp_acknak_common: ignored %s packet "
- "received via broadcast on %s", pname, pif->pif_name);
- free_pkt_entry(plp);
- return;
- }
/*
- * Find the corresponding state machine not using DLPI.
+ * Find the corresponding state machine.
*
* Note that DHCPv6 Reconfigure would be special: it's not the reply to
* any transaction, and thus we would need to search on transaction ID
- * zero (all state machines) to find the match. However, Reconfigure
+ * zero (all state machines) to find the match. However, Reconfigure
* is not yet supported.
*/
xid = pkt_get_xid(plp->pkt, isv6);
+ if (!isv6 && !pkt_v4_match(recv_type, DHCP_PACK|DHCP_PNAK)) {
+ reason = "not ACK or NAK";
+ goto drop;
+ }
+
for (dsmp = lookup_smach_by_xid(xid, NULL, isv6); dsmp != NULL;
dsmp = lookup_smach_by_xid(xid, dsmp, isv6)) {
if (dsmp->dsm_lif->lif_pif == pif)
break;
}
- if (dsmp == NULL || dsmp->dsm_using_dlpi) {
- dhcpmsg(MSG_VERBOSE, "dhcp_acknak_common: ignored %s packet "
- "received via broadcast %s; %s", pname, pif->pif_name,
- dsmp == NULL ? "unknown state machine" : "not using DLPI");
- free_pkt_entry(plp);
- return;
+
+ if (dsmp == NULL) {
+ reason = "unknown state machine";
+ goto drop;
+ }
+
+ /*
+ * For IPv4, most packets will be handled by dhcp_packet_lif(). The
+ * only exceptions are broadcast packets sent when lif_sock_ip_fd has
+ * bound to something other than INADDR_ANY.
+ */
+ if (!isv6) {
+ sock = dsmp->dsm_lif->lif_sock_ip_fd;
+
+ if (getsockname(sock, (struct sockaddr *)&sin, &sinlen) != -1 &&
+ sin.sin_addr.s_addr == INADDR_ANY) {
+ reason = "handled by lif_sock_ip_fd";
+ goto drop;
+ }
}
/*
@@ -1035,6 +1051,12 @@
accept_v6_message(dsmp, plp, pname, recv_type);
else
accept_v4_acknak(dsmp, plp);
+ return;
+drop:
+ dhcpmsg(MSG_VERBOSE, "dhcp_acknak_global: ignored v%d %s packet for %s "
+ "received on global socket: %s", isv6 ? 6 : 4, pname, pif->pif_name,
+ reason);
+ free_pkt_entry(plp);
}
/*
@@ -1062,11 +1084,11 @@
}
/*
- * dhcp_acknak_lif(): Processes reception of an ACK or NAK packet on a given
- * logical interface for IPv4 (only).
+ * dhcp_packet_lif(): Processes reception of an ACK, NAK, or OFFER packet on
+ * a given logical interface for IPv4 (only).
*
* input: iu_eh_t *: unused
- * int: the global file descriptor the ACK/NAK arrived on
+ * int: the file descriptor the packet arrived on
* short: unused
* iu_event_id_t: the id of this event callback with the handler
* void *: pointer to logical interface receiving message
@@ -1075,7 +1097,7 @@
/* ARGSUSED */
void
-dhcp_acknak_lif(iu_eh_t *ehp, int fd, short events, iu_event_id_t id,
+dhcp_packet_lif(iu_eh_t *ehp, int fd, short events, iu_event_id_t id,
void *arg)
{
dhcp_lif_t *lif = arg;
@@ -1085,21 +1107,22 @@
uint_t xid;
dhcp_smach_t *dsmp;
- if ((plp = recv_pkt(fd, lif->lif_max, B_FALSE, B_FALSE, NULL)) == NULL)
+ if ((plp = recv_pkt(fd, lif->lif_max, B_FALSE)) == NULL)
return;
recv_type = pkt_recv_type(plp);
pname = pkt_type_to_string(recv_type, B_FALSE);
- if (!pkt_v4_match(recv_type, DHCP_PACK | DHCP_PNAK)) {
- dhcpmsg(MSG_VERBOSE, "dhcp_acknak_lif: ignored v4 %s packet "
+ if (!pkt_v4_match(recv_type,
+ DHCP_PACK | DHCP_PNAK | DHCP_PUNTYPED | DHCP_POFFER)) {
+ dhcpmsg(MSG_VERBOSE, "dhcp_packet_lif: ignored v4 %s packet "
"received via LIF %s", pname, lif->lif_name);
free_pkt_entry(plp);
return;
}
/*
- * Find the corresponding state machine not using DLPI.
+ * Find the corresponding state machine.
*/
xid = pkt_get_xid(plp->pkt, B_FALSE);
for (dsmp = lookup_smach_by_xid(xid, NULL, B_FALSE); dsmp != NULL;
@@ -1107,19 +1130,31 @@
if (dsmp->dsm_lif == lif)
break;
}
- if (dsmp == NULL || dsmp->dsm_using_dlpi) {
- dhcpmsg(MSG_VERBOSE, "dhcp_acknak_lif: ignored %s packet xid "
- "%x received via LIF %s; %s", pname, xid, lif->lif_name,
- dsmp == NULL ? "unknown state machine" : "not using DLPI");
- free_pkt_entry(plp);
- return;
+
+ if (dsmp == NULL)
+ goto drop;
+
+ if (pkt_v4_match(recv_type, DHCP_PACK|DHCP_PNAK)) {
+ /*
+ * We've got an ACK/NAK; make sure it's acceptable and cancel
+ * the REQUEST retransmissions.
+ */
+ accept_v4_acknak(dsmp, plp);
+ } else {
+ if (is_bound_state(dsmp->dsm_state))
+ goto drop;
+ /*
+ * Must be an OFFER or a BOOTP message: enqueue it for later
+ * processing by select_best().
+ */
+ pkt_smach_enqueue(dsmp, plp);
}
-
- /*
- * We've got a packet; make sure it's acceptable and cancel the REQUEST
- * retransmissions.
- */
- accept_v4_acknak(dsmp, plp);
+ return;
+drop:
+ dhcpmsg(MSG_VERBOSE, "dhcp_packet_lif: ignored %s packet xid "
+ "%x received via LIF %s; %s", pname, xid, lif->lif_name,
+ dsmp == NULL ? "unknown state machine" : "bound");
+ free_pkt_entry(plp);
}
/*
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c Tue Oct 30 11:15:43 2007 -0700
@@ -235,102 +235,6 @@
}
/*
- * dhcp_collect_dlpi(): collects incoming OFFERs, ACKs, and NAKs via DLPI.
- *
- * input: iu_eh_t *: unused
- * int: unused
- * short: unused
- * iu_event_id_t: the id of this event callback with the handler
- * void *: the physical interface that received the message
- * output: void
- */
-
-/* ARGSUSED */
-void
-dhcp_collect_dlpi(iu_eh_t *eh, int fd, short events, iu_event_id_t id,
- void *arg)
-{
- dhcp_pif_t *pif = arg;
- PKT_LIST *plp;
- uchar_t recv_type;
- const char *pname;
- dhcp_smach_t *dsmp;
- uint_t xid;
-
- if ((plp = recv_pkt(fd, pif->pif_max, B_FALSE, B_TRUE, pif)) == NULL)
- return;
-
- recv_type = pkt_recv_type(plp);
- pname = pkt_type_to_string(recv_type, B_FALSE);
-
- /*
- * DHCP_PUNTYPED messages are BOOTP server responses.
- */
- if (!pkt_v4_match(recv_type,
- DHCP_PACK | DHCP_PNAK | DHCP_POFFER | DHCP_PUNTYPED)) {
- dhcpmsg(MSG_VERBOSE, "dhcp_collect_dlpi: ignored %s packet "
- "received via DLPI on %s", pname, pif->pif_name);
- free_pkt_entry(plp);
- return;
- }
-
- /*
- * Loop through the state machines that match on XID to find one that's
- * interested in this offer. If there are none, then discard.
- */
- xid = pkt_get_xid(plp->pkt, B_FALSE);
- for (dsmp = lookup_smach_by_xid(xid, NULL, B_FALSE); dsmp != NULL;
- dsmp = lookup_smach_by_xid(xid, dsmp, B_FALSE)) {
-
- /*
- * Find state machine on correct interface.
- */
- if (dsmp->dsm_lif->lif_pif == pif)
- break;
- }
-
- if (dsmp == NULL) {
- dhcpmsg(MSG_VERBOSE, "dhcp_collect_dlpi: no matching state "
- "machine for %s packet XID %#x received via DLPI on %s",
- pname, xid, pif->pif_name);
- free_pkt_entry(plp);
- return;
- }
-
- /*
- * Ignore state machines that aren't looking for DLPI messages.
- */
- if (!dsmp->dsm_using_dlpi) {
- dhcpmsg(MSG_VERBOSE, "dhcp_collect_dlpi: ignore state "
- "machine for %s packet XID %#x received via DLPI on %s",
- pname, xid, pif->pif_name);
- free_pkt_entry(plp);
- return;
- }
-
- /* See also accept_v[46]_message; account for processed packets. */
- dsmp->dsm_received++;
-
- if (pkt_v4_match(recv_type, DHCP_PACK)) {
- if (!dhcp_bound(dsmp, plp)) {
- dhcpmsg(MSG_WARNING, "dhcp_collect_dlpi: dhcp_bound "
- "failed for %s", dsmp->dsm_name);
- dhcp_restart(dsmp);
- return;
- }
- dhcpmsg(MSG_VERBOSE, "dhcp_collect_dlpi: %s on %s",
- pname, dsmp->dsm_name);
- } else if (pkt_v4_match(recv_type, DHCP_PNAK)) {
- dhcpmsg(MSG_VERBOSE, "dhcp_collect_dlpi: %s on %s",
- pname, dsmp->dsm_name);
- free_pkt_entry(plp);
- dhcp_restart(dsmp);
- } else {
- pkt_smach_enqueue(dsmp, plp);
- }
-}
-
-/*
* stop_selecting(): decides when to stop retransmitting DISCOVERs -- only when
* abandoning the state machine. For DHCPv6, this timer may
* go off before the offer wait timer. If so, then this is a
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c Tue Oct 30 11:15:43 2007 -0700
@@ -149,18 +149,16 @@
&dsmp->dsm_server);
/*
- * With IPv4 DHCP, we start off doing our I/O via DLPI, so open
- * that up now.
+ * With IPv4 DHCP, we use a socket per lif.
*/
- if (!open_dlpi_pif(lif->lif_pif)) {
- dhcpmsg(MSG_ERR, "unable to open DLPI for %s",
+ if (!open_ip_lif(lif, INADDR_ANY)) {
+ dhcpmsg(MSG_ERR, "unable to open socket for %s",
lif->lif_name);
/* This will also dispose of the LIF */
release_smach(dsmp);
*error = DHCP_IPC_E_SOCKET;
return (NULL);
}
- dsmp->dsm_using_dlpi = B_TRUE;
}
dsmp->dsm_retrans_timer = -1;
dsmp->dsm_offer_timer = -1;
@@ -657,6 +655,20 @@
}
/*
+ * is_bound_state(): checks if a state indicates the client is bound
+ *
+ * input: DHCPSTATE: the state to check
+ * output: boolean_t: B_TRUE if the state is bound, B_FALSE if not
+ */
+
+boolean_t
+is_bound_state(DHCPSTATE state)
+{
+ return (state == BOUND || state == REBINDING || state == INFORMATION ||
+ state == RELEASING || state == INFORM_SENT || state == RENEWING);
+}
+
+/*
* set_smach_state(): changes state and updates I/O
*
* input: dhcp_smach_t *: the state machine to change
@@ -667,35 +679,33 @@
boolean_t
set_smach_state(dhcp_smach_t *dsmp, DHCPSTATE state)
{
+ dhcp_lif_t *lif = dsmp->dsm_lif;
+
if (dsmp->dsm_state != state) {
- boolean_t is_bound;
-
dhcpmsg(MSG_DEBUG,
"set_smach_state: changing from %s to %s on %s",
dhcp_state_to_string(dsmp->dsm_state),
dhcp_state_to_string(state), dsmp->dsm_name);
+ /*
+ * For IPv4, when we're in a bound state our socket must be
+ * bound to our address. Otherwise, our socket must be bound
+ * to INADDR_ANY. For IPv6, no such change is necessary.
+ */
if (!dsmp->dsm_isv6) {
- /*
- * When we're in a bound state for IPv4, we receive our
- * packets through our LIF. Otherwise, we receive them
- * through DLPI. Make sure the right one is connected.
- * For IPv6, no such change is necessary.
- */
- is_bound = (state == BOUND || state == REBINDING ||
- state == RENEWING || state == RELEASING ||
- state == INFORM_SENT || state == INFORMATION);
- if (dsmp->dsm_using_dlpi && is_bound) {
- if (!open_ip_lif(dsmp->dsm_lif))
- return (B_FALSE);
- dsmp->dsm_using_dlpi = B_FALSE;
- close_dlpi_pif(dsmp->dsm_lif->lif_pif);
- }
- if (!dsmp->dsm_using_dlpi && !is_bound) {
- if (!open_dlpi_pif(dsmp->dsm_lif->lif_pif))
- return (B_FALSE);
- dsmp->dsm_using_dlpi = B_TRUE;
- close_ip_lif(dsmp->dsm_lif);
+ if (is_bound_state(dsmp->dsm_state)) {
+ if (!is_bound_state(state)) {
+ close_ip_lif(lif);
+ if (!open_ip_lif(lif, INADDR_ANY))
+ return (B_FALSE);
+ }
+ } else {
+ if (is_bound_state(state)) {
+ close_ip_lif(lif);
+ if (!open_ip_lif(lif,
+ ntohl(lif->lif_addr)))
+ return (B_FALSE);
+ }
}
}
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h Tue Oct 30 11:15:43 2007 -0700
@@ -72,8 +72,6 @@
uint_t dsm_lif_wait; /* LIFs waiting on DAD */
uint_t dsm_lif_down; /* LIFs failed */
- boolean_t dsm_using_dlpi;
-
/*
* each state machine can have at most one pending asynchronous
* action, which is represented in a `struct async_action'.
@@ -258,9 +256,8 @@
};
/* The IU event callback functions */
-iu_eh_callback_t dhcp_acknak_common;
-iu_eh_callback_t dhcp_acknak_lif;
-iu_eh_callback_t dhcp_collect_dlpi;
+iu_eh_callback_t dhcp_acknak_global;
+iu_eh_callback_t dhcp_packet_lif;
/* Common state-machine related routines throughout dhcpagent */
boolean_t dhcp_adopt(void);
@@ -311,6 +308,7 @@
void cancel_offer_timer(dhcp_smach_t *);
void discard_default_routes(dhcp_smach_t *);
void remove_default_routes(dhcp_smach_t *);
+boolean_t is_bound_state(DHCPSTATE);
/* Lease-related support functions in states.c */
dhcp_lease_t *insert_lease(dhcp_smach_t *);
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/defs.h Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/defs.h Tue Oct 30 11:15:43 2007 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 1983, 1988, 1993
@@ -801,6 +801,8 @@
extern void rip_mcast_on(struct interface *);
extern void rip_mcast_off(struct interface *);
extern void trace_dump();
+extern int sendtoif(int, const void *, uint_t, uint_t, struct sockaddr_in *,
+ uint_t);
#ifdef __cplusplus
}
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/output.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/output.c Tue Oct 30 11:15:43 2007 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 1983, 1988, 1993
@@ -40,6 +40,7 @@
#include "defs.h"
#include <md5.h>
+#include <alloca.h>
uint_t update_seqno;
@@ -109,7 +110,6 @@
int res;
int ifindex;
struct in_addr addr;
- static int rip_sock_ifindex;
sin = *dst;
if (sin.sin_port == 0)
@@ -148,22 +148,12 @@
}
/*
- * Note that we intentionally reset IP_XMIT_IF to zero if
- * we're doing multicast. The kernel ignores IP_MULTICAST_IF
- * if IP_XMIT_IF is set, and we can't deal with alias source
- * addresses without it.
+ * IP_PKTINFO overrides IP_MULTICAST_IF, so we don't set ifindex
+ * for multicast traffic.
*/
ifindex = (type != OUT_MULTICAST && type != OUT_QUERY &&
ifp != NULL && ifp->int_phys != NULL) ?
ifp->int_phys->phyi_index : 0;
- if (rip_sock_ifindex != ifindex) {
- if (setsockopt(rip_sock, IPPROTO_IP, IP_XMIT_IF, &ifindex,
- sizeof (ifindex)) == -1) {
- LOGERR("setsockopt(rip_sock, IP_XMIT_IF)");
- return (-1);
- }
- rip_sock_ifindex = ifindex;
- }
if (rip_sock_interface != ifp) {
/*
@@ -186,10 +176,8 @@
trace_rip(msg, "to", &sin, ifp, buf, size);
- res = sendto(rip_sock, buf, size, flags,
- (struct sockaddr *)&sin, sizeof (sin));
- if (res < 0 &&
- (ifp == NULL || !(ifp->int_state & IS_BROKE))) {
+ res = sendtoif(rip_sock, buf, size, flags, &sin, ifindex);
+ if (res < 0 && (ifp == NULL || !(ifp->int_state & IS_BROKE))) {
writelog(LOG_WARNING, "%s sendto(%s%s%s.%d): %s", msg,
ifp != NULL ? ifp->int_name : "",
ifp != NULL ? ", " : "",
@@ -201,6 +189,55 @@
return (res);
}
+/*
+ * Semantically identical to sendto(), but sends the message through a
+ * specific interface (if ifindex is non-zero) using IP_PKTINFO.
+ */
+int
+sendtoif(int fd, const void *buf, uint_t bufsize, uint_t flags,
+ struct sockaddr_in *sinp, uint_t ifindex)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ struct cmsghdr *cmsgp;
+ struct in_pktinfo *ipip;
+
+ iov.iov_base = (void *)buf;
+ iov.iov_len = bufsize;
+
+ (void) memset(&msg, 0, sizeof (struct msghdr));
+ msg.msg_name = (struct sockaddr *)sinp;
+ msg.msg_namelen = sizeof (struct sockaddr_in);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ if (ifindex != 0) {
+ /*
+ * We can't precisely predict the alignment padding we'll
+ * need, so we allocate the maximum alignment and then
+ * use CMSG_NXTHDR() to fix it up at the end.
+ */
+ msg.msg_controllen = sizeof (*cmsgp) + _MAX_ALIGNMENT +
+ sizeof (*ipip) + _MAX_ALIGNMENT + sizeof (*cmsgp);
+ msg.msg_control = alloca(msg.msg_controllen);
+
+ cmsgp = CMSG_FIRSTHDR(&msg);
+ ipip = (void *)CMSG_DATA(cmsgp);
+ (void) memset(ipip, 0, sizeof (struct in_pktinfo));
+ ipip->ipi_ifindex = ifindex;
+ cmsgp->cmsg_len = (caddr_t)(ipip + 1) - (caddr_t)cmsgp;
+ cmsgp->cmsg_type = IP_PKTINFO;
+ cmsgp->cmsg_level = IPPROTO_IP;
+
+ /*
+ * Correct the control message length.
+ */
+ cmsgp = CMSG_NXTHDR(&msg, cmsgp);
+ msg.msg_controllen = (caddr_t)cmsgp - (caddr_t)msg.msg_control;
+ }
+
+ return (sendmsg(fd, &msg, flags));
+}
/*
* Find the first key for a packet to send.
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/rdisc.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/rdisc.c Tue Oct 30 11:15:43 2007 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 1995
@@ -663,9 +663,9 @@
new_drp->dr_life > drp->dr_life))))) ||
((new_st & IS_SICK) &&
!(drp->dr_ifp->int_state & IS_SICK))) {
- new_drp = drp;
- new_st = drp->dr_ifp->int_state;
- new_pref = drp->dr_pref;
+ new_drp = drp;
+ new_st = drp->dr_ifp->int_state;
+ new_pref = drp->dr_pref;
}
}
@@ -1010,7 +1010,7 @@
struct sockaddr_in sin;
int flags = 0;
const char *msg;
- int ifindex;
+ int ifindex = 0;
struct in_addr addr;
/*
@@ -1052,15 +1052,11 @@
if (rdisc_sock < 0)
get_rdisc_sock();
+ /* select the right interface. */
+ ifindex = (type != mcast && ifp->int_phys != NULL) ?
+ ifp->int_phys->phyi_index : 0;
+
if (rdisc_sock_interface != ifp) {
- /* select the right interface. */
- ifindex = (type != mcast && ifp->int_phys != NULL) ?
- ifp->int_phys->phyi_index : 0;
- if (setsockopt(rdisc_sock, IPPROTO_IP, IP_XMIT_IF, &ifindex,
- sizeof (ifindex)) == -1) {
- LOGERR("setsockopt(rdisc_sock, IP_XMIT_IF)");
- return;
- }
/*
* For multicast, we have to choose the source
* address. This is either the local address
@@ -1070,7 +1066,7 @@
ifp->int_dstaddr : ifp->int_addr;
if (type == mcast &&
setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_IF, &addr,
- sizeof (addr)) == -1) {
+ sizeof (addr)) == -1) {
LOGERR("setsockopt(rdisc_sock, IP_MULTICAST_IF)");
return;
}
@@ -1079,8 +1075,7 @@
trace_rdisc(msg, ifp->int_addr, sin.sin_addr.s_addr, ifp, p, p_size);
- if (0 > sendto(rdisc_sock, p, p_size, flags,
- (struct sockaddr *)&sin, sizeof (sin))) {
+ if (0 > sendtoif(rdisc_sock, p, p_size, flags, &sin, ifindex)) {
if (!(ifp->int_state & IS_BROKE))
writelog(LOG_WARNING, "sendto(%s%s%s): %s",
ifp->int_name, ", ",
@@ -1294,7 +1289,7 @@
cc = recvmsg(rdisc_sock, &msg, 0);
if (cc <= 0) {
if (cc < 0 && errno != EWOULDBLOCK)
- LOGERR("recvmsg(rdisc_sock)");
+ LOGERR("recvmsg(rdisc_sock)");
break;
}
--- a/usr/src/uts/common/inet/ip.h Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/ip.h Tue Oct 30 11:15:43 2007 -0700
@@ -622,9 +622,9 @@
#define IRE_MARK_HIDDEN 0x0004 /* Typically Used by in.mpathd */
/*
- * ire with IRE_MARK_NOADD is created in ip_newroute_ipif, when outgoing
- * interface is specified by IP_XMIT_IF socket option. This ire is not
- * added in IRE_CACHE.
+ * An IRE with IRE_MARK_NOADD is created in ip_newroute_ipif when the outgoing
+ * interface is specified by e.g. IP_PKTINFO. The IRE is not added to the IRE
+ * cache table.
*/
#define IRE_MARK_NOADD 0x0008 /* Mark not to add ire in cache */
@@ -1031,7 +1031,6 @@
* ipc_acking_unbind conn_acking_unbind
* ipc_pad_to_bit_31 conn_pad_to_bit_31
*
- * ipc_xmit_if_ill conn_xmit_if_ill
* ipc_nofailover_ill conn_nofailover_ill
*
* ipc_proto conn_proto
@@ -1048,7 +1047,6 @@
* ipc_multicast_ill conn_multicast_ill
* ipc_orig_bound_ifindex conn_orig_bound_ifindex
* ipc_orig_multicast_ifindex conn_orig_multicast_ifindex
- * ipc_orig_xmit_ifindex conn_orig_xmit_ifindex
* ipc_drain_next conn_drain_next
* ipc_drain_prev conn_drain_prev
* ipc_idl conn_idl
@@ -1842,7 +1840,7 @@
ill_arp_closing : 1,
ill_arp_bringup_pending : 1,
- ill_mtu_userspecified : 1, /* SIOCSLNKINFO has set the mtu */
+ ill_mtu_userspecified : 1, /* SIOCSLIFLNKINFO has set the mtu */
ill_arp_extend : 1, /* ARP has DAD extensions */
ill_pad_bit_31 : 25;
@@ -1962,6 +1960,7 @@
boolean_t ill_trace_disable; /* True when alloc fails */
zoneid_t ill_zoneid;
ip_stack_t *ill_ipst; /* Corresponds to a netstack_hold */
+ uint32_t ill_dhcpinit; /* IP_DHCPINIT_IFs for ill */
} ill_t;
/*
@@ -2063,6 +2062,7 @@
* ill_nce_cnt ill_lock ill_lock
* ill_trace ill_lock ill_lock
* ill_usesrc_grp_next ill_g_usesrc_lock ill_g_usesrc_lock
+ * ill_dhcpinit atomics atomics
*/
/*
--- a/usr/src/uts/common/inet/ip/icmp.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/ip/icmp.c Tue Oct 30 11:15:43 2007 -0700
@@ -1766,9 +1766,6 @@
case IP_UNSPEC_SRC:
*ptr = icmp->icmp_unspec_source;
break; /* goto sizeof (int) option return */
- case IP_XMIT_IF:
- *i1 = icmp->icmp_xmit_if;
- break; /* goto sizeof (int) option return */
case IP_RECVIF:
*ptr = icmp->icmp_recvif;
break; /* goto sizeof (int) option return */
@@ -1956,8 +1953,7 @@
return (0);
return (ip_fill_mtuinfo(&icmp->icmp_v6dst, 0,
- (struct ip6_mtuinfo *)ptr,
- is->is_netstack));
+ (struct ip6_mtuinfo *)ptr, is->is_netstack));
case IPV6_TCLASS:
if (ipp->ipp_fields & IPPF_TCLASS)
*i1 = ipp->ipp_tclass;
@@ -2317,10 +2313,6 @@
if (!checkonly)
icmp->icmp_unspec_source = onoff;
break;
- case IP_XMIT_IF:
- if (!checkonly)
- icmp->icmp_xmit_if = *i1;
- break;
case IP_RECVIF:
if (!checkonly)
icmp->icmp_recvif = onoff;
@@ -5539,8 +5531,7 @@
void
icmp_ddi_init(void)
{
- icmp_max_optsize =
- optcom_max_optsize(icmp_opt_obj.odb_opt_des_arr,
+ icmp_max_optsize = optcom_max_optsize(icmp_opt_obj.odb_opt_des_arr,
icmp_opt_obj.odb_opt_arr_cnt);
/*
--- a/usr/src/uts/common/inet/ip/icmp_opt_data.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/ip/icmp_opt_data.c Tue Oct 30 11:15:43 2007 -0700
@@ -140,9 +140,6 @@
{ IP_BOUND_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_PASSNEXT,
sizeof (int), 0 /* no ifindex */ },
-{ IP_XMIT_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_PASSNEXT,
- sizeof (int), 0 /* no ifindex */ },
-
{ IP_DONTFAILOVER_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_PASSNEXT,
sizeof (struct in_addr), 0 /* not initialized */ },
--- a/usr/src/uts/common/inet/ip/ip.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/ip/ip.c Tue Oct 30 11:15:43 2007 -0700
@@ -1294,7 +1294,9 @@
/* 181 */ { SIOCSIPMSFILTER, sizeof (struct ip_msfilter), IPI_WR,
MSFILT_CMD, ip_sioctl_msfilter, NULL },
/* 182 */ { SIOCSIPMPFAILBACK, sizeof (int), IPI_PRIV, MISC_CMD,
- ip_sioctl_set_ipmpfailback, NULL }
+ ip_sioctl_set_ipmpfailback, NULL },
+ /* SIOCSENABLESDP is handled by SDP */
+ /* 183 */ { IPI_DONTCARE /* SIOCSENABLESDP */, 0, 0, 0, NULL, NULL },
};
int ip_ndx_ioctl_count = sizeof (ip_ndx_ioctl_table) / sizeof (ip_ioctl_cmd_t);
@@ -5526,6 +5528,11 @@
drain_cleanup_reqd = B_TRUE;
if (connp->conn_oper_pending_ill != NULL)
conn_ioctl_cleanup_reqd = B_TRUE;
+ if (connp->conn_dhcpinit_ill != NULL) {
+ ASSERT(connp->conn_dhcpinit_ill->ill_dhcpinit != 0);
+ atomic_dec_32(&connp->conn_dhcpinit_ill->ill_dhcpinit);
+ connp->conn_dhcpinit_ill = NULL;
+ }
if (connp->conn_ilg_inuse != 0)
ilg_cleanup_reqd = B_TRUE;
mutex_exit(&connp->conn_lock);
@@ -7792,6 +7799,7 @@
MULTIRT_CACHEGW | MULTIRT_USESTAMP | MULTIRT_SETSTAMP;
boolean_t multirt_is_resolvable;
boolean_t multirt_resolve_next;
+ boolean_t unspec_src;
boolean_t do_attach_ill = B_FALSE;
boolean_t ip_nexthop = B_FALSE;
tsol_ire_gw_secattr_t *attrp = NULL;
@@ -8200,7 +8208,11 @@
src_ipif = ipif_lookup_addr(sire->ire_src_addr, NULL,
zoneid, NULL, NULL, NULL, NULL, ipst);
}
- if (src_ipif == NULL) {
+
+ unspec_src = (connp != NULL && connp->conn_unspec_src);
+
+ if (src_ipif == NULL &&
+ (!unspec_src || ipha->ipha_src != INADDR_ANY)) {
ire_marks |= IRE_MARK_USESRC_CHECK;
if ((dst_ill->ill_group != NULL) ||
(ire->ire_ipif->ipif_flags & IPIF_DEPRECATED) ||
@@ -8257,10 +8269,9 @@
* NOTE : ip_newroute_v6 does not have this piece of code as
* it uses ip6i to store this information.
*/
- if (ipha->ipha_src == INADDR_ANY &&
- (connp == NULL || !connp->conn_unspec_src)) {
+ if (ipha->ipha_src == INADDR_ANY && !unspec_src)
ipha->ipha_src = src_ipif->ipif_src_addr;
- }
+
if (ip_debug > 3) {
/* ip2dbg */
pr_addr_dbg("ip_newroute: first hop %s\n",
@@ -8963,7 +8974,7 @@
* ip_rput_forward_multicast whenever we need to send
* out a packet to a destination address for which we do not have specific
* routing information. It is used when the packet will be sent out
- * on a specific interface. It is also called by ip_wput() when IP_XMIT_IF
+ * on a specific interface. It is also called by ip_wput() when IP_BOUND_IF
* socket option is set or icmp error message wants to go out on a particular
* interface for a unicast packet.
*
@@ -9005,6 +9016,7 @@
ire_t *fire = NULL;
mblk_t *copy_mp = NULL;
boolean_t multirt_resolve_next;
+ boolean_t unspec_src;
ipaddr_t ipha_dst;
ip_stack_t *ipst = ipif->ipif_ill->ill_ipst;
@@ -9105,14 +9117,6 @@
ASSERT(dst_ill == attach_ill);
} else {
/*
- * If this is set by IP_XMIT_IF, then make sure that
- * ipif is pointing to the same ill as the IP_XMIT_IF
- * specified ill.
- */
- ASSERT((connp == NULL) ||
- (connp->conn_xmit_if_ill == NULL) ||
- (connp->conn_xmit_if_ill == ipif->ipif_ill));
- /*
* If the interface belongs to an interface group,
* make sure the next possible interface in the group
* is used. This encourages load spreading among
@@ -9163,10 +9167,15 @@
src_ipif = ipif_lookup_addr(fire->ire_src_addr, NULL,
zoneid, NULL, NULL, NULL, NULL, ipst);
}
- if (((ipif->ipif_flags & IPIF_DEPRECATED) ||
+
+ unspec_src = (connp != NULL && connp->conn_unspec_src);
+
+ if (((!ipif->ipif_isv6 && ipif->ipif_lcl_addr == INADDR_ANY) ||
+ (ipif->ipif_flags & (IPIF_DEPRECATED|IPIF_UP)) != IPIF_UP ||
(connp != NULL && ipif->ipif_zoneid != zoneid &&
ipif->ipif_zoneid != ALL_ZONES)) &&
- (src_ipif == NULL)) {
+ (src_ipif == NULL) &&
+ (!unspec_src || ipha->ipha_src != INADDR_ANY)) {
src_ipif = ipif_select_source(dst_ill, dst, zoneid);
if (src_ipif == NULL) {
if (ip_debug > 2) {
@@ -9192,19 +9201,17 @@
* Assign a source address while we have the conn.
* We can't have ip_wput_ire pick a source address when the
* packet returns from arp since conn_unspec_src might be set
- * and we loose the conn when going through arp.
- */
- if (ipha->ipha_src == INADDR_ANY &&
- (connp == NULL || !connp->conn_unspec_src)) {
+ * and we lose the conn when going through arp.
+ */
+ if (ipha->ipha_src == INADDR_ANY && !unspec_src)
ipha->ipha_src = src_ipif->ipif_src_addr;
- }
-
- /*
- * In the case of IP_XMIT_IF, it is possible that the
- * outgoing interface does not have an interface ire.
+
+ /*
+ * In the case of IP_BOUND_IF and IP_PKTINFO, it is possible
+ * that the outgoing interface does not have an interface ire.
*/
if (CLASSD(ipha_dst) && (connp == NULL ||
- connp->conn_xmit_if_ill == NULL) &&
+ connp->conn_outgoing_ill == NULL) &&
infop->ip_opt_ill_index == 0) {
/* ipif_to_ire returns an held ire */
ire = ipif_to_ire(ipif);
@@ -9250,12 +9257,12 @@
}
} else {
ASSERT((connp == NULL) ||
- (connp->conn_xmit_if_ill != NULL) ||
+ (connp->conn_outgoing_ill != NULL) ||
(connp->conn_dontroute) ||
infop->ip_opt_ill_index != 0);
/*
* The only ways we can come here are:
- * 1) IP_XMIT_IF socket option is set
+ * 1) IP_BOUND_IF socket option is set
* 2) SO_DONTROUTE socket option is set
* 3) IP_PKTINFO option is passed in as ancillary data.
* In all cases, the new ire will not be added
@@ -10493,19 +10500,6 @@
0 : ifindex;
break;
- case IP_XMIT_IF:
- /*
- * Similar to IP_BOUND_IF, but this only
- * determines the outgoing interface for
- * unicast packets. Also no IRE_CACHE entry
- * is added for the destination of the
- * outgoing packets.
- */
- connp->conn_xmit_if_ill = ill;
- connp->conn_orig_xmit_ifindex = (ill == NULL) ?
- 0 : ifindex;
- break;
-
case IP_MULTICAST_IF:
/*
* This option is an internal special. The socket
@@ -10530,6 +10524,26 @@
}
}
break;
+
+ case IP_DHCPINIT_IF:
+ if (connp->conn_dhcpinit_ill != NULL) {
+ /*
+ * We've locked the conn so conn_cleanup_ill()
+ * cannot clear conn_dhcpinit_ill -- so it's
+ * safe to access the ill.
+ */
+ ill_t *oill = connp->conn_dhcpinit_ill;
+
+ ASSERT(oill->ill_dhcpinit != 0);
+ atomic_dec_32(&oill->ill_dhcpinit);
+ connp->conn_dhcpinit_ill = NULL;
+ }
+
+ if (ill != NULL) {
+ connp->conn_dhcpinit_ill = ill;
+ atomic_inc_32(&ill->ill_dhcpinit);
+ }
+ break;
}
} else {
switch (option) {
@@ -11048,7 +11062,7 @@
*outlenp = inlen;
return (0);
case IP_BOUND_IF:
- case IP_XMIT_IF:
+ case IP_DHCPINIT_IF:
error = ip_opt_set_ill(connp, *i1, B_FALSE, checkonly,
level, name, first_mp);
if (error != 0)
@@ -15003,11 +15017,12 @@
* o no options in the packet
* o not a RSVP packet
* o not a multicast packet
+ * o ill not in IP_DHCPINIT_IF mode
*/
if (!is_system_labeled() &&
!ipst->ips_ip_cgtp_filter && ipp_action_count == 0 &&
opt_len == 0 && ipha->ipha_protocol != IPPROTO_RSVP &&
- !ll_multicast && !CLASSD(dst)) {
+ !ll_multicast && !CLASSD(dst) && ill->ill_dhcpinit == 0) {
if (ire == NULL)
ire = ire_cache_lookup(dst, ALL_ZONES, NULL,
ipst);
@@ -15031,6 +15046,31 @@
ire = NULL;
}
+ /*
+ * Brutal hack for DHCPv4 unicast: RFC2131 allows a DHCP
+ * server to unicast DHCP packets to a DHCP client using the
+ * IP address it is offering to the client. This can be
+ * disabled through the "broadcast bit", but not all DHCP
+ * servers honor that bit. Therefore, to interoperate with as
+ * many DHCP servers as possible, the DHCP client allows the
+ * server to unicast, but we treat those packets as broadcast
+ * here. Note that we don't rewrite the packet itself since
+ * (a) that would mess up the checksums and (b) the DHCP
+ * client conn is bound to INADDR_ANY so ip_fanout_udp() will
+ * hand it the packet regardless.
+ */
+ if (ill->ill_dhcpinit != 0 &&
+ IS_SIMPLE_IPH(ipha) && ipha->ipha_protocol == IPPROTO_UDP &&
+ MBLKL(mp) > sizeof (ipha_t) + sizeof (udpha_t)) {
+ udpha_t *udpha = (udpha_t *)&ipha[1];
+
+ if (ntohs(udpha->uha_dst_port) == IPPORT_BOOTPC) {
+ DTRACE_PROBE2(ip4__dhcpinit__pkt, ill_t *, ill,
+ mblk_t *, mp);
+ dst = INADDR_BROADCAST;
+ }
+ }
+
/* Full-blown slow path */
if (opt_len != 0) {
if (len != 0)
@@ -19988,7 +20028,7 @@
int match_flags;
ill_t *attach_ill = NULL;
/* Bind to IPIF_NOFAILOVER ill etc. */
- ill_t *xmit_ill = NULL; /* IP_XMIT_IF etc. */
+ ill_t *xmit_ill = NULL; /* IP_PKTINFO etc. */
ipif_t *dst_ipif;
boolean_t multirt_need_resolve = B_FALSE;
mblk_t *copy_mp = NULL;
@@ -20109,11 +20149,11 @@
}
/*
- * IP_DONTFAILOVER_IF and IP_XMIT_IF have precedence over
- * ill index passed in IP_PKTINFO.
+ * IP_DONTFAILOVER_IF and IP_BOUND_IF have precedence over ill index
+ * passed in IP_PKTINFO.
*/
if (infop->ip_opt_ill_index != 0 &&
- connp->conn_xmit_if_ill == NULL &&
+ connp->conn_outgoing_ill == NULL &&
connp->conn_nofailover_ill == NULL) {
xmit_ill = ill_lookup_on_ifindex(
@@ -20178,6 +20218,15 @@
}
}
+ /* If IP_BOUND_IF has been set, use that ill. */
+ if (connp->conn_outgoing_ill != NULL) {
+ xmit_ill = conn_get_held_ill(connp,
+ &connp->conn_outgoing_ill, &err);
+ if (err == ILL_LOOKUP_FAILED)
+ goto drop_pkt;
+
+ goto send_from_ill;
+ }
/* is packet multicast? */
if (CLASSD(dst))
@@ -20187,74 +20236,39 @@
* If xmit_ill is set above due to index passed in ip_pkt_info. It
* takes precedence over conn_dontroute and conn_nexthop_set
*/
- if (xmit_ill != NULL) {
+ if (xmit_ill != NULL)
goto send_from_ill;
- }
-
- if ((connp->conn_dontroute) || (connp->conn_xmit_if_ill != NULL) ||
- (connp->conn_nexthop_set)) {
- /*
- * If the destination is a broadcast or a loopback
- * address, SO_DONTROUTE, IP_XMIT_IF and IP_NEXTHOP go
- * through the standard path. But in the case of local
- * destination only SO_DONTROUTE and IP_NEXTHOP go through
- * the standard path not IP_XMIT_IF.
+
+ if (connp->conn_dontroute || connp->conn_nexthop_set) {
+ /*
+ * If the destination is a broadcast, local, or loopback
+ * address, SO_DONTROUTE and IP_NEXTHOP go through the
+ * standard path.
*/
ire = ire_cache_lookup(dst, zoneid, MBLK_GETLABEL(mp), ipst);
- if ((ire == NULL) || ((ire->ire_type != IRE_BROADCAST) &&
- (ire->ire_type != IRE_LOOPBACK))) {
- if ((connp->conn_dontroute ||
- connp->conn_nexthop_set) && (ire != NULL) &&
- (ire->ire_type == IRE_LOCAL))
- goto standard_path;
-
+ if ((ire == NULL) || (ire->ire_type &
+ (IRE_BROADCAST | IRE_LOCAL | IRE_LOOPBACK)) == 0) {
if (ire != NULL) {
ire_refrele(ire);
/* No more access to ire */
ire = NULL;
}
/*
- * bypass routing checks and go directly to
- * interface.
- */
- if (connp->conn_dontroute) {
+ * bypass routing checks and go directly to interface.
+ */
+ if (connp->conn_dontroute)
goto dontroute;
- } else if (connp->conn_nexthop_set) {
- ip_nexthop = B_TRUE;
- nexthop_addr = connp->conn_nexthop_v4;
- goto send_from_ill;
- }
-
- /*
- * If IP_XMIT_IF socket option is set,
- * then we allow unicast and multicast
- * packets to go through the ill. It is
- * quite possible that the destination
- * is not in the ire cache table and we
- * do not want to go to ip_newroute()
- * instead we call ip_newroute_ipif.
- */
- xmit_ill = conn_get_held_ill(connp,
- &connp->conn_xmit_if_ill, &err);
- if (err == ILL_LOOKUP_FAILED) {
- BUMP_MIB(&ipst->ips_ip_mib,
- ipIfStatsOutDiscards);
- if (attach_ill != NULL)
- ill_refrele(attach_ill);
- if (need_decref)
- CONN_DEC_REF(connp);
- freemsg(first_mp);
- return;
- }
+
+ ASSERT(connp->conn_nexthop_set);
+ ip_nexthop = B_TRUE;
+ nexthop_addr = connp->conn_nexthop_v4;
goto send_from_ill;
}
-standard_path:
+
/* Must be a broadcast, a loopback or a local ire */
- if (ire != NULL) {
- ire_refrele(ire);
- /* No more access to ire */
- ire = NULL;
- }
+ ire_refrele(ire);
+ /* No more access to ire */
+ ire = NULL;
}
if (attach_ill != NULL)
@@ -20819,17 +20833,16 @@
ntohl(dst), ill->ill_name));
} else {
/*
- * The order of precedence is IP_XMIT_IF, IP_PKTINFO
- * and IP_MULTICAST_IF.
- * Block comment above this function explains the
- * locking mechanism used here
+ * The order of precedence is IP_BOUND_IF, IP_PKTINFO
+ * and IP_MULTICAST_IF. The block comment above this
+ * function explains the locking mechanism used here.
*/
if (xmit_ill == NULL) {
xmit_ill = conn_get_held_ill(connp,
- &connp->conn_xmit_if_ill, &err);
+ &connp->conn_outgoing_ill, &err);
if (err == ILL_LOOKUP_FAILED) {
ip1dbg(("ip_wput: No ill for "
- "IP_XMIT_IF\n"));
+ "IP_BOUND_IF\n"));
BUMP_MIB(&ipst->ips_ip_mib,
ipIfStatsOutNoRoutes);
goto drop_pkt;
@@ -20851,7 +20864,7 @@
ipif = ipif_get_next_ipif(NULL, xmit_ill);
if (ipif == NULL) {
ip1dbg(("ip_wput: No ipif for "
- "IP_XMIT_IF\n"));
+ "xmit_ill\n"));
BUMP_MIB(&ipst->ips_ip_mib,
ipIfStatsOutNoRoutes);
goto drop_pkt;
@@ -20994,7 +21007,7 @@
dst = ipif->ipif_lcl_addr;
/*
- * If IP_XMIT_IF is set, we branch out to ip_newroute_ipif.
+ * If xmit_ill is set, we branch out to ip_newroute_ipif.
* We don't need to lookup ire in ctable as the packet
* needs to be sent to the destination through the specified
* ill irrespective of ires in the cache table.
@@ -21095,54 +21108,39 @@
* connectivity.
*/
ipha->ipha_ttl = 1;
- /*
- * If IP_XMIT_IF is also set (conn_xmit_if_ill != NULL)
- * along with SO_DONTROUTE, higher precedence is
- * given to IP_XMIT_IF and the IP_XMIT_IF ipif is used.
- */
- if (connp->conn_xmit_if_ill == NULL) {
- /* If suitable ipif not found, drop packet */
- dst_ipif = ipif_lookup_onlink_addr(dst, zoneid,
- ipst);
- if (dst_ipif == NULL) {
- ip1dbg(("ip_wput: no route for "
- "dst using SO_DONTROUTE\n"));
- BUMP_MIB(&ipst->ips_ip_mib,
- ipIfStatsOutNoRoutes);
- mp->b_prev = mp->b_next = NULL;
- if (first_mp == NULL)
- first_mp = mp;
- goto drop_pkt;
- } else {
- /*
- * If suitable ipif has been found, set
- * xmit_ill to the corresponding
- * ipif_ill because we'll be following
- * the IP_XMIT_IF logic.
- */
- ASSERT(xmit_ill == NULL);
- xmit_ill = dst_ipif->ipif_ill;
- mutex_enter(&xmit_ill->ill_lock);
- if (!ILL_CAN_LOOKUP(xmit_ill)) {
- mutex_exit(&xmit_ill->ill_lock);
- xmit_ill = NULL;
- ipif_refrele(dst_ipif);
- ip1dbg(("ip_wput: no route for"
- " dst using"
- " SO_DONTROUTE\n"));
- BUMP_MIB(&ipst->ips_ip_mib,
- ipIfStatsOutNoRoutes);
- mp->b_prev = mp->b_next = NULL;
- if (first_mp == NULL)
- first_mp = mp;
- goto drop_pkt;
- }
- ill_refhold_locked(xmit_ill);
+
+ /* If suitable ipif not found, drop packet */
+ dst_ipif = ipif_lookup_onlink_addr(dst, zoneid, ipst);
+ if (dst_ipif == NULL) {
+noroute:
+ ip1dbg(("ip_wput: no route for dst using"
+ " SO_DONTROUTE\n"));
+ BUMP_MIB(&ipst->ips_ip_mib,
+ ipIfStatsOutNoRoutes);
+ mp->b_prev = mp->b_next = NULL;
+ if (first_mp == NULL)
+ first_mp = mp;
+ goto drop_pkt;
+ } else {
+ /*
+ * If suitable ipif has been found, set
+ * xmit_ill to the corresponding
+ * ipif_ill because we'll be using the
+ * send_from_ill logic below.
+ */
+ ASSERT(xmit_ill == NULL);
+ xmit_ill = dst_ipif->ipif_ill;
+ mutex_enter(&xmit_ill->ill_lock);
+ if (!ILL_CAN_LOOKUP(xmit_ill)) {
mutex_exit(&xmit_ill->ill_lock);
+ xmit_ill = NULL;
ipif_refrele(dst_ipif);
- }
- }
-
+ goto noroute;
+ }
+ ill_refhold_locked(xmit_ill);
+ mutex_exit(&xmit_ill->ill_lock);
+ ipif_refrele(dst_ipif);
+ }
}
/*
* If we are bound to IPIF_NOFAILOVER address, look for
@@ -21170,84 +21168,64 @@
ire = ire_ctable_lookup(dst, 0, 0, attach_ipif,
zoneid, MBLK_GETLABEL(mp), match_flags, ipst);
ipif_refrele(attach_ipif);
- } else if (xmit_ill != NULL || (connp != NULL &&
- connp->conn_xmit_if_ill != NULL)) {
+ } else if (xmit_ill != NULL) {
+ ipif_t *ipif;
+
/*
* Mark this packet as originated locally
*/
mp->b_prev = mp->b_next = NULL;
- /*
- * xmit_ill could be NULL if SO_DONTROUTE
- * is also set.
- */
- if (xmit_ill == NULL) {
- xmit_ill = conn_get_held_ill(connp,
- &connp->conn_xmit_if_ill, &err);
- if (err == ILL_LOOKUP_FAILED) {
- BUMP_MIB(&ipst->ips_ip_mib,
- ipIfStatsOutDiscards);
- if (need_decref)
- CONN_DEC_REF(connp);
- freemsg(first_mp);
- return;
- }
- if (xmit_ill == NULL) {
- if (connp->conn_dontroute)
- goto dontroute;
- goto send_from_ill;
- }
- }
+
/*
* Could be SO_DONTROUTE case also.
- * check at least one interface is UP as
- * specified by this ILL
- */
- if (xmit_ill->ill_ipif_up_count > 0) {
- ipif_t *ipif;
-
- ipif = ipif_get_next_ipif(NULL, xmit_ill);
- if (ipif == NULL) {
- ip1dbg(("ip_output: "
- "xmit_ill NULL ipif\n"));
- goto drop_pkt;
- }
- /*
- * Look for a ire that is part of the group,
- * if found use it else call ip_newroute_ipif.
- * IPCL_ZONEID is not used for matching because
- * IP_ALLZONES option is valid only when the
- * ill is accessible from all zones i.e has a
- * valid ipif in all zones.
- */
- match_flags = MATCH_IRE_ILL_GROUP |
- MATCH_IRE_SECATTR;
- ire = ire_ctable_lookup(dst, 0, 0, ipif, zoneid,
- MBLK_GETLABEL(mp), match_flags, ipst);
- /*
- * If an ire exists use it or else create
- * an ire but don't add it to the cache.
- * Adding an ire may cause issues with
- * asymmetric routing.
- * In case of multiroute always act as if
- * ire does not exist.
- */
- if (ire == NULL ||
- ire->ire_flags & RTF_MULTIRT) {
- if (ire != NULL)
- ire_refrele(ire);
- ip_newroute_ipif(q, first_mp, ipif,
- dst, connp, 0, zoneid, infop);
- ipif_refrele(ipif);
- ip1dbg(("ip_wput: ip_unicast_if\n"));
- ill_refrele(xmit_ill);
- if (need_decref)
- CONN_DEC_REF(connp);
- return;
- }
+ * Verify that at least one ipif is up on the ill.
+ */
+ if (xmit_ill->ill_ipif_up_count == 0) {
+ ip1dbg(("ip_output: xmit_ill %s is down\n",
+ xmit_ill->ill_name));
+ goto drop_pkt;
+ }
+
+ ipif = ipif_get_next_ipif(NULL, xmit_ill);
+ if (ipif == NULL) {
+ ip1dbg(("ip_output: xmit_ill %s NULL ipif\n",
+ xmit_ill->ill_name));
+ goto drop_pkt;
+ }
+
+ /*
+ * Look for a ire that is part of the group,
+ * if found use it else call ip_newroute_ipif.
+ * IPCL_ZONEID is not used for matching because
+ * IP_ALLZONES option is valid only when the
+ * ill is accessible from all zones i.e has a
+ * valid ipif in all zones.
+ */
+ match_flags = MATCH_IRE_ILL_GROUP | MATCH_IRE_SECATTR;
+ ire = ire_ctable_lookup(dst, 0, 0, ipif, zoneid,
+ MBLK_GETLABEL(mp), match_flags, ipst);
+ /*
+ * If an ire exists use it or else create
+ * an ire but don't add it to the cache.
+ * Adding an ire may cause issues with
+ * asymmetric routing.
+ * In case of multiroute always act as if
+ * ire does not exist.
+ */
+ if (ire == NULL || ire->ire_flags & RTF_MULTIRT) {
+ if (ire != NULL)
+ ire_refrele(ire);
+ ip_newroute_ipif(q, first_mp, ipif,
+ dst, connp, 0, zoneid, infop);
ipif_refrele(ipif);
- } else {
- goto drop_pkt;
- }
+ ip1dbg(("ip_output: xmit_ill via %s\n",
+ xmit_ill->ill_name));
+ ill_refrele(xmit_ill);
+ if (need_decref)
+ CONN_DEC_REF(connp);
+ return;
+ }
+ ipif_refrele(ipif);
} else if (ip_nexthop || (connp != NULL &&
(connp->conn_nexthop_set)) && !ignore_nexthop) {
if (!ip_nexthop) {
@@ -21458,7 +21436,7 @@
*
* The following rules must be observed when accessing any ipif or ill
* that has been cached in the conn. Typically conn_nofailover_ill,
- * conn_xmit_if_ill, conn_multicast_ipif and conn_multicast_ill.
+ * conn_outgoing_ill, conn_multicast_ipif and conn_multicast_ill.
*
* Access: The ipif or ill pointed to from the conn can be accessed under
* the protection of the conn_lock or after it has been refheld under the
@@ -22020,11 +21998,10 @@
}
/*
- * conn_outgoing_ill is used only in the broadcast loop.
+ * conn_outgoing_ill variable is used only in the broadcast loop.
* for performance we don't grab the mutexs in the fastpath
*/
if ((connp != NULL) &&
- (connp->conn_xmit_if_ill == NULL) &&
(ire->ire_type == IRE_BROADCAST) &&
((connp->conn_nofailover_ill != NULL) ||
(connp->conn_outgoing_ill != NULL))) {
@@ -22611,8 +22588,8 @@
rw_exit(&ire->ire_bucket->irb_lock);
/* Did not find a matching ill */
ip1dbg(("ip_wput_ire: broadcast with no "
- "matching IP_BOUND_IF ill %s\n",
- conn_outgoing_ill->ill_name));
+ "matching IP_BOUND_IF ill %s dst %x\n",
+ conn_outgoing_ill->ill_name, dst));
freemsg(first_mp);
if (ire != NULL)
ire_refrele(ire);
--- a/usr/src/uts/common/inet/ip/ip_if.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/ip/ip_if.c Tue Oct 30 11:15:43 2007 -0700
@@ -1526,8 +1526,11 @@
connp->conn_outgoing_pill = NULL;
if (connp->conn_nofailover_ill == ill)
connp->conn_nofailover_ill = NULL;
- if (connp->conn_xmit_if_ill == ill)
- connp->conn_xmit_if_ill = NULL;
+ if (connp->conn_dhcpinit_ill == ill) {
+ connp->conn_dhcpinit_ill = NULL;
+ ASSERT(ill->ill_dhcpinit != 0);
+ atomic_dec_32(&ill->ill_dhcpinit);
+ }
if (connp->conn_ire_cache != NULL) {
ire = connp->conn_ire_cache;
/*
@@ -16610,11 +16613,6 @@
connp->conn_multicast_ill = connm->cm_to_ill;
}
- /* Change IP_XMIT_IF associations */
- if ((connp->conn_xmit_if_ill == from_ill) &&
- (ifindex == 0 || connp->conn_orig_xmit_ifindex == ifindex)) {
- connp->conn_xmit_if_ill = to_ill;
- }
/*
* Change the ilg_ill to point to the new one. This assumes
* ilm_move_v6 has moved the ilms to new_ill and the driver
@@ -20216,8 +20214,7 @@
/*
* Create any necessary broadcast IREs.
*/
- if ((ipif->ipif_subnet != INADDR_ANY) &&
- (ipif->ipif_flags & IPIF_BROADCAST))
+ if (ipif->ipif_flags & IPIF_BROADCAST)
irep = ipif_create_bcast_ires(ipif, irep);
ASSERT(!MUTEX_HELD(&ipif->ipif_ill->ill_lock));
@@ -21712,9 +21709,6 @@
if (connp->conn_orig_multicast_ifindex == old_ifindex)
connp->conn_orig_multicast_ifindex = new_ifindex;
- if (connp->conn_orig_xmit_ifindex == old_ifindex)
- connp->conn_orig_xmit_ifindex = new_ifindex;
-
for (i = connp->conn_ilg_inuse - 1; i >= 0; i--) {
ilg = &connp->conn_ilg[i];
if (ilg->ilg_orig_ifindex == old_ifindex)
--- a/usr/src/uts/common/inet/ip/ip_opt_data.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/ip/ip_opt_data.c Tue Oct 30 11:15:43 2007 -0700
@@ -119,12 +119,12 @@
{ IP_BOUND_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0,
sizeof (int), 0 /* no ifindex */ },
-{ IP_XMIT_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0,
- sizeof (int), 0 /* no ifindex */ },
-
{ IP_DONTFAILOVER_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, 0,
sizeof (struct in_addr), 0 /* not initialized */ },
+{ IP_DHCPINIT_IF, IPPROTO_IP, OA_R, OA_RW, OP_CONFIG, 0,
+ sizeof (int), 0 },
+
{ IP_UNSPEC_SRC, IPPROTO_IP, OA_R, OA_RW, OP_RAW, 0,
sizeof (int), 0 },
--- a/usr/src/uts/common/inet/ip_impl.h Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/ip_impl.h Tue Oct 30 11:15:43 2007 -0700
@@ -395,7 +395,6 @@
((connp)->conn_dontroute == 0 && /* SO_DONTROUTE */ \
!((connp)->conn_nexthop_set) && /* IP_NEXTHOP */ \
(connp)->conn_nofailover_ill == NULL && /* IPIF_NOFAILOVER */ \
- (connp)->conn_xmit_if_ill == NULL && /* IP_XMIT_IF */ \
(connp)->conn_outgoing_pill == NULL && /* IP{V6}_BOUND_PIF */ \
(connp)->conn_outgoing_ill == NULL) /* IP{V6}_BOUND_IF */
--- a/usr/src/uts/common/inet/ipclassifier.h Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/ipclassifier.h Tue Oct 30 11:15:43 2007 -0700
@@ -226,8 +226,8 @@
conn_lso_ok : 1; /* LSO is usable */
- ill_t *conn_xmit_if_ill; /* Outbound ill */
ill_t *conn_nofailover_ill; /* Failover ill */
+ ill_t *conn_dhcpinit_ill; /* IP_DHCPINIT_IF */
ipsec_latch_t *conn_latch; /* latched state */
ill_t *conn_outgoing_ill; /* IP{,V6}_BOUND_IF */
edesc_spf conn_send; /* Pointer to send routine */
@@ -285,7 +285,6 @@
int conn_orig_bound_ifindex; /* BOUND_IF before MOVE */
int conn_orig_multicast_ifindex;
/* IPv6 MC IF before MOVE */
- int conn_orig_xmit_ifindex; /* IP_XMIT_IF before move */
struct conn_s *conn_drain_next; /* Next conn in drain list */
struct conn_s *conn_drain_prev; /* Prev conn in drain list */
idl_t *conn_idl; /* Ptr to the drain list head */
--- a/usr/src/uts/common/inet/rawip_impl.h Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/rawip_impl.h Tue Oct 30 11:15:43 2007 -0700
@@ -95,7 +95,6 @@
uint8_t icmp_multicast_ttl; /* IP*_MULTICAST_TTL/HOPS */
ipaddr_t icmp_multicast_if_addr; /* IP_MULTICAST_IF option */
uint_t icmp_multicast_if_index; /* IPV6_MULTICAST_IF option */
- int icmp_xmit_if; /* IP_XMIT_IF option */
int icmp_bound_if; /* IP*_BOUND_IF option */
/* Written to only once at the time of opening the endpoint */
--- a/usr/src/uts/common/inet/tcp/tcp.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/tcp/tcp.c Tue Oct 30 11:15:43 2007 -0700
@@ -18622,7 +18622,7 @@
(connp->conn_flags & IPCL_CHECK_POLICY) == 0 &&
connp->conn_dontroute == 0 &&
!connp->conn_nexthop_set &&
- connp->conn_xmit_if_ill == NULL &&
+ connp->conn_outgoing_ill == NULL &&
connp->conn_nofailover_ill == NULL &&
do_tcpzcopy == 1) {
/*
--- a/usr/src/uts/common/inet/udp/udp.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/udp/udp.c Tue Oct 30 11:15:43 2007 -0700
@@ -2666,6 +2666,8 @@
case IP_TTL:
*i1 = (int)udp->udp_ttl;
break; /* goto sizeof (int) option return */
+ case IP_DHCPINIT_IF:
+ return (-EINVAL);
case IP_NEXTHOP:
case IP_RECVPKTINFO:
/*
@@ -2725,9 +2727,6 @@
case IP_UNSPEC_SRC:
*i1 = udp->udp_unspec_source;
break; /* goto sizeof (int) option return */
- case IP_XMIT_IF:
- *i1 = udp->udp_xmit_if;
- break; /* goto sizeof (int) option return */
default:
return (-1);
}
@@ -3259,6 +3258,7 @@
case MCAST_LEAVE_SOURCE_GROUP:
case IP_SEC_OPT:
case IP_NEXTHOP:
+ case IP_DHCPINIT_IF:
/*
* "soft" error (negative)
* option not handled at this level
@@ -3273,10 +3273,6 @@
if (!checkonly)
udp->udp_unspec_source = onoff;
break;
- case IP_XMIT_IF:
- if (!checkonly)
- udp->udp_xmit_if = *i1;
- break;
default:
*outlenp = 0;
return (EINVAL);
@@ -5994,7 +5990,7 @@
if ((connp->conn_flags & IPCL_CHECK_POLICY) != 0 ||
CONN_OUTBOUND_POLICY_PRESENT(connp, ipss) ||
- connp->conn_dontroute || connp->conn_xmit_if_ill != NULL ||
+ connp->conn_dontroute ||
connp->conn_nofailover_ill != NULL ||
connp->conn_outgoing_ill != NULL || optinfo.ip_opt_flags != 0 ||
optinfo.ip_opt_ill_index != 0 ||
--- a/usr/src/uts/common/inet/udp/udp_opt_data.c Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/udp/udp_opt_data.c Tue Oct 30 11:15:43 2007 -0700
@@ -131,12 +131,13 @@
{ IP_BOUND_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_PASSNEXT,
sizeof (int), 0 /* no ifindex */ },
-{ IP_XMIT_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_PASSNEXT,
- sizeof (int), 0 /* no ifindex */ },
{ IP_DONTFAILOVER_IF, IPPROTO_IP, OA_RW, OA_RW, OP_NP, OP_PASSNEXT,
sizeof (struct in_addr), 0 /* not initialized */ },
+{ IP_DHCPINIT_IF, IPPROTO_IP, OA_R, OA_RW, OP_CONFIG, OP_PASSNEXT,
+ sizeof (int), 0 },
+
{ IP_UNSPEC_SRC, IPPROTO_IP, OA_R, OA_RW, OP_RAW, OP_PASSNEXT,
sizeof (int), 0 },
--- a/usr/src/uts/common/inet/udp_impl.h Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/inet/udp_impl.h Tue Oct 30 11:15:43 2007 -0700
@@ -296,7 +296,6 @@
ipaddr_t udp_multicast_if_addr; /* IP_MULTICAST_IF option */
uint_t udp_multicast_if_index; /* IPV6_MULTICAST_IF option */
int udp_bound_if; /* IP*_BOUND_IF option */
- int udp_xmit_if; /* IP_XMIT_IF option */
/* Written to only once at the time of opening the endpoint */
conn_t *udp_connp;
--- a/usr/src/uts/common/netinet/in.h Tue Oct 30 09:32:44 2007 -0700
+++ b/usr/src/uts/common/netinet/in.h Tue Oct 30 11:15:43 2007 -0700
@@ -910,13 +910,9 @@
* SunOS private (potentially not portable) IP_ option names
*/
#define IP_BOUND_IF 0x41 /* bind socket to an ifindex */
-#define IP_UNSPEC_SRC 0x42 /* use unspecified source address */
-/*
- * IP_XMIT_IF is used to send unicast/multicast packets through the specified
- * interface without looking at the routing table entries.
- * This is a Sun private interface.
- */
-#define IP_XMIT_IF 0x43 /* use specified outgoing interface */
+#define IP_UNSPEC_SRC 0x42 /* use unspecified source address */
+/* UNUSED 0x43 was IP_XMIT_IF -- can be reused */
+
/*
* IP_DONTFAILOVER_IF option is used to indicate that outbound unicast and
* multicast packets go through the specified interface, no load spreading,
@@ -925,6 +921,8 @@
*/
#define IP_DONTFAILOVER_IF 0x44
+#define IP_DHCPINIT_IF 0x45 /* accept all unicast DHCP traffic */
+
/*
* Option values and names (when !_XPG5) shared with <xti_inet.h>
*/