diff options
33 files changed, 609 insertions, 770 deletions
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c b/deleted_files/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c index 0099600ec3..0099600ec3 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c +++ b/deleted_files/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.h b/deleted_files/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.h index cb8276c204..cb8276c204 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.h +++ b/deleted_files/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.h diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/inc.flg b/deleted_files/usr/src/cmd/cmd-inet/sbin/dhcpagent/inc.flg index a456cbaede..a456cbaede 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/inc.flg +++ b/deleted_files/usr/src/cmd/cmd-inet/sbin/dhcpagent/inc.flg diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile b/usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile index 24f8535619..5bc7b56a2b 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/Makefile @@ -29,26 +29,21 @@ PROG = dhcpagent 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 @@ $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) -%.o: $(COMDIR)/%.c - $(COMPILE.c) $(OUTPUT_OPTION) $< - $(POST_PROCESS_O) - $(POFILE): $(POFILES) $(RM) $@; $(CAT) $(POFILES) > $@; $(RM) $(POFILES) diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/README b/usr/src/cmd/cmd-inet/sbin/dhcpagent/README index 92794d0ca3..749ec9a665 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/README +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/README @@ -81,8 +81,8 @@ up into three groups: 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 @@ init_pkt(), the add_pkt_opt*() functions are used to add options to 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 @@ action. 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 ---- diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/README.v6 b/usr/src/cmd/cmd-inet/sbin/dhcpagent/README.v6 index 72c3490bd9..a52fe3e6b9 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/README.v6 +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/README.v6 @@ -22,6 +22,15 @@ Use is subject to license terms. 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 diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c index 12fda6da80..d1d4756867 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/agent.c @@ -1163,6 +1163,7 @@ check_lif(dhcp_lif_t *lif, const struct ifa_msghdr *ifam, int msglen) 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 @@ rtsock_event(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg) * 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++; diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c index 26dd80d2c4..0de123a571 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/bound.c @@ -337,7 +337,7 @@ dhcp_bound_complete(dhcp_smach_t *dsmp) */ 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 @@ dhcp_bound_complete(dhcp_smach_t *dsmp) 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 @@ dhcp_bound_complete(dhcp_smach_t *dsmp) 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 @@ dhcp_bound_complete(dhcp_smach_t *dsmp) 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 diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.c index 0dd2893cf7..fb706c77e1 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.c +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.c @@ -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 @@ insert_pif(const char *pname, boolean_t isv6, int *error) { 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 @@ insert_pif(const char *pname, boolean_t isv6, int *error) } 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 @@ insert_pif(const char *pname, boolean_t isv6, int *error) /* 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 @@ insert_pif(const char *pname, boolean_t isv6, int *error) *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 @@ insert_pif(const char *pname, boolean_t isv6, int *error) } /* 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 @@ insert_pif(const char *pname, boolean_t isv6, int *error) 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 @@ insert_pif(const char *pname, boolean_t isv6, int *error) *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 @@ insert_pif(const char *pname, boolean_t isv6, int *error) (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 @@ release_pif(dhcp_pif_t *pif) 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 @@ lookup_pif_by_name(const char *pname, boolean_t isv6) } /* - * 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 @@ insert_lif(dhcp_pif_t *pif, const char *lname, int *error) } 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 @@ checkaddr(const dhcp_lif_t *lif, int ioccmd, const in6_addr_t *addr, 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 @@ checkaddr(const dhcp_lif_t *lif, int ioccmd, const in6_addr_t *addr, } 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 @@ verify_lif(const dhcp_lif_t *lif) * 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 @@ canonize_lif(dhcp_lif_t *lif) 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 @@ unplumb_lif(dhcp_lif_t *lif) * 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 @@ clear_lif_deprecated(dhcp_lif_t *lif) * 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 @@ open_ip_lif(dhcp_lif_t *lif) 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, - ntohl(lif->lif_addr))) { - dhcpmsg(MSG_ERR, "open_ip_lif: cannot bind v4 socket on %s", - lif->lif_name); - return (B_FALSE); + if (!bind_sock(lif->lif_sock_ip_fd, IPPORT_BOOTPC, addr_hbo)) { + errmsg = "cannot bind v4 socket"; + 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 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; + } + + /* + * 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; + } + + 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 @@ open_ip_lif(dhcp_lif_t *lif) 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); diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.h b/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.h index 585ff7d41e..f68e849ec9 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.h +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/interface.h @@ -47,7 +47,6 @@ extern "C" { #include <netinet/dhcp.h> #include <dhcpagent_ipc.h> #include <libinetutil.h> -#include <libdlpi.h> #include "common.h" #include "util.h" @@ -65,14 +64,7 @@ struct dhcp_pif_s { 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 @@ struct dhcp_lif_s { 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 @@ void release_pif(dhcp_pif_t *); 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 @@ dhcp_lif_t *attach_lif(const char *, boolean_t, int *); 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 *, diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c index 071fc6566d..8a32b55ea5 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.c @@ -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 @@ pkt_get_xid(const PKT *pkt, boolean_t isv6) 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 @@ init_pkt(dhcp_smach_t *dsmp, uchar_t type) * 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 @@ send_pkt_internal(dhcp_smach_t *dsmp) { 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 @@ send_pkt_internal(dhcp_smach_t *dsmp) 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 @@ send_pkt_internal(dhcp_smach_t *dsmp) 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 @@ sock_recvpkt(int fd, PKT_LIST *plp) /* * 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 @@ recv_pkt(int fd, int mtu, boolean_t isv6, boolean_t isdlpi, dhcp_pif_t *arg) return (NULL); } - if (isv6) { - retval = sock_recvpkt(fd, plp); - - if (retval == -1) { - dhcpmsg(MSG_ERR, - "recv_pkt: recvfrom v6 failed, dropped"); - goto failure; - } + retval = sock_recvpkt(fd, plp); + if (retval == -1) { + dhcpmsg(MSG_ERR, "recv_pkt: recvfrom v%d failed, dropped", + isv6 ? 6 : 4); + 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 @@ dhcp_ip_default(void) 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 @@ dhcp_ip_default(void) 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"); diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h b/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h index 1556dced35..0ec64c4117 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/packet.h @@ -130,7 +130,7 @@ void *add_pkt_prl(dhcp_pkt_t *, dhcp_smach_t *); 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, diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c index 2206ca4b23..9782d1480c 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/request.c @@ -372,7 +372,7 @@ compute_points_v6(const PKT_LIST *pkt, const dhcp_smach_t *dsmp) /* * 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 @@ accept_v6_message(dhcp_smach_t *dsmp, PKT_LIST *plp, const char *pname, } /* - * 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 @@ accept_v6_message(dhcp_smach_t *dsmp, PKT_LIST *plp, const char *pname, /* 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 @@ dhcp_acknak_common(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, 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 @@ dhcp_acknak_common(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, 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 @@ dhcp_acknak_common(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, 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 @@ request_failed(dhcp_smach_t *dsmp) } /* - * 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 @@ request_failed(dhcp_smach_t *dsmp) /* 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 @@ dhcp_acknak_lif(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, 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 @@ dhcp_acknak_lif(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, 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; - } - /* - * We've got a packet; make sure it's acceptable and cancel the REQUEST - * retransmissions. - */ - accept_v4_acknak(dsmp, plp); + 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); + } + 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); } /* diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c index d0ebdb0a6e..de3a21e8f8 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/select.c @@ -235,102 +235,6 @@ failed: } /* - * 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 diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c index c26e6c07b2..63e134fc8f 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.c @@ -149,18 +149,16 @@ insert_smach(dhcp_lif_t *lif, int *error) &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 @@ finished_smach(dhcp_smach_t *dsmp, int error) } /* + * 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 @@ finished_smach(dhcp_smach_t *dsmp, int error) boolean_t set_smach_state(dhcp_smach_t *dsmp, DHCPSTATE state) { - if (dsmp->dsm_state != state) { - boolean_t is_bound; + dhcp_lif_t *lif = dsmp->dsm_lif; + if (dsmp->dsm_state != state) { 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); + } } } diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h b/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h index 02209ce243..c36232264e 100644 --- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h +++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/states.h @@ -72,8 +72,6 @@ struct dhcp_smach_s { 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 @@ struct dhcp_lease_s { }; /* 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 @@ boolean_t schedule_smach_timer(dhcp_smach_t *, int, uint32_t, 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 *); diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/defs.h b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/defs.h index 5b3ba902cd..2467b7cd58 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/defs.h +++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/defs.h @@ -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 end_md5_auth(struct ws_buf *, struct auth *); 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 } diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/output.c b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/output.c index ae212db11b..c4dd637efd 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/output.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/output.c @@ -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 @@ output(enum output_type type, int res; int ifindex; struct in_addr addr; - static int rip_sock_ifindex; sin = *dst; if (sin.sin_port == 0) @@ -148,22 +148,12 @@ output(enum output_type type, } /* - * 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 @@ output(enum output_type type, 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 @@ output(enum output_type type, 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. diff --git a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/rdisc.c b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/rdisc.c index 6e572ccc41..d7325b3393 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/in.routed/rdisc.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/in.routed/rdisc.c @@ -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 @@ rdisc_sort(void) 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 @@ send_rdisc(union ad_u *p, struct sockaddr_in sin; int flags = 0; const char *msg; - int ifindex; + int ifindex = 0; struct in_addr addr; /* @@ -1052,15 +1052,11 @@ send_rdisc(union ad_u *p, 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 @@ send_rdisc(union ad_u *p, 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 @@ send_rdisc(union ad_u *p, 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 @@ read_d(void) cc = recvmsg(rdisc_sock, &msg, 0); if (cc <= 0) { if (cc < 0 && errno != EWOULDBLOCK) - LOGERR("recvmsg(rdisc_sock)"); + LOGERR("recvmsg(rdisc_sock)"); break; } diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index 9e828964a4..05e121a37c 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -622,9 +622,9 @@ typedef struct ip_m_s { #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 @@ typedef struct conn_s conn_t; * 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 @@ typedef struct conn_s conn_t; * 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 @@ typedef struct ill_s { 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 @@ typedef struct ill_s { 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 @@ typedef struct ill_s { * 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 */ /* diff --git a/usr/src/uts/common/inet/ip/icmp.c b/usr/src/uts/common/inet/ip/icmp.c index e8e8c0a7c5..8cf74a2366 100644 --- a/usr/src/uts/common/inet/ip/icmp.c +++ b/usr/src/uts/common/inet/ip/icmp.c @@ -1766,9 +1766,6 @@ icmp_opt_get_locked(queue_t *q, int level, int name, uchar_t *ptr) 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 @@ icmp_opt_get_locked(queue_t *q, int level, int name, uchar_t *ptr) 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 @@ icmp_opt_set_locked(queue_t *q, uint_t optset_context, int level, int name, 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 @@ icmp_unitdata_opt_process(queue_t *q, mblk_t *mp, int *errorp, 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); /* diff --git a/usr/src/uts/common/inet/ip/icmp_opt_data.c b/usr/src/uts/common/inet/ip/icmp_opt_data.c index b4a20417ad..49952d9166 100644 --- a/usr/src/uts/common/inet/ip/icmp_opt_data.c +++ b/usr/src/uts/common/inet/ip/icmp_opt_data.c @@ -140,9 +140,6 @@ opdes_t icmp_opt_arr[] = { { 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 */ }, diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c index 05b22eacf3..5eee449379 100644 --- a/usr/src/uts/common/inet/ip/ip.c +++ b/usr/src/uts/common/inet/ip/ip.c @@ -1294,7 +1294,9 @@ ip_ioctl_cmd_t ip_ndx_ioctl_table[] = { /* 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 @@ ip_quiesce_conn(conn_t *connp) 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, conn_t *connp, 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, conn_t *connp, 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 @@ ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, conn_t *connp, * 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_opt_info_t zero_info; * 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 @@ ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, 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 @@ ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, 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 @@ ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, 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 @@ ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, * 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. + * and we lose the conn when going through arp. */ - 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; - } /* - * 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 @@ ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, } } 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 @@ setit: 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 @@ setit: } } 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 @@ ip_opt_set(queue_t *q, uint_t optset_context, int level, int name, *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 @@ ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, * 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 @@ ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, 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 @@ ip_output_options(void *arg, mblk_t *mp, void *arg2, int caller, 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_output_options(void *arg, mblk_t *mp, void *arg2, int caller, } /* - * 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 @@ ip_output_options(void *arg, mblk_t *mp, void *arg2, int caller, } } + /* 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 @@ ip_output_options(void *arg, mblk_t *mp, void *arg2, int caller, * 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 (connp->conn_dontroute || 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 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. + * bypass routing checks and go directly to interface. */ - if (connp->conn_dontroute) { + 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 @@ multicast: 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 @@ multicast: 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 @@ multicast: 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 @@ dontroute: * 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 @@ send_from_ill: 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. + * Could be SO_DONTROUTE case also. + * Verify that at least one ipif is up on the ill. */ - 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; - } + 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; + } + /* - * Could be SO_DONTROUTE case also. - * check at least one interface is UP as - * specified by this ILL + * 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. */ - 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; - } + 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 @@ ip_wput(queue_t *q, mblk_t *mp) * * 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 @@ ip_wput_ire(queue_t *q, mblk_t *mp, ire_t *ire, conn_t *connp, int caller, } /* - * 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 @@ broadcast: 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); diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c index 4673bde903..c9703c3664 100644 --- a/usr/src/uts/common/inet/ip/ip_if.c +++ b/usr/src/uts/common/inet/ip/ip_if.c @@ -1526,8 +1526,11 @@ conn_cleanup_ill(conn_t *connp, caddr_t arg) 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 @@ conn_move(conn_t *connp, caddr_t arg) 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 @@ ipif_up_done(ipif_t *ipif) /* * 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 @@ conn_change_ifindex(conn_t *connp, caddr_t arg) 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) diff --git a/usr/src/uts/common/inet/ip/ip_opt_data.c b/usr/src/uts/common/inet/ip/ip_opt_data.c index 5bdea67f2a..3df66ece60 100644 --- a/usr/src/uts/common/inet/ip/ip_opt_data.c +++ b/usr/src/uts/common/inet/ip/ip_opt_data.c @@ -119,12 +119,12 @@ opdes_t ip_opt_arr[] = { { 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 }, diff --git a/usr/src/uts/common/inet/ip_impl.h b/usr/src/uts/common/inet/ip_impl.h index 8cb4bc9b3c..6c4d5f41aa 100644 --- a/usr/src/uts/common/inet/ip_impl.h +++ b/usr/src/uts/common/inet/ip_impl.h @@ -395,7 +395,6 @@ typedef struct ip_lso_info_s { ((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 */ diff --git a/usr/src/uts/common/inet/ipclassifier.h b/usr/src/uts/common/inet/ipclassifier.h index 3a6a15cf6f..a80d8077b0 100644 --- a/usr/src/uts/common/inet/ipclassifier.h +++ b/usr/src/uts/common/inet/ipclassifier.h @@ -226,8 +226,8 @@ struct conn_s { 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 @@ struct conn_s { 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 */ diff --git a/usr/src/uts/common/inet/rawip_impl.h b/usr/src/uts/common/inet/rawip_impl.h index 58f29e8a3c..20c316123b 100644 --- a/usr/src/uts/common/inet/rawip_impl.h +++ b/usr/src/uts/common/inet/rawip_impl.h @@ -95,7 +95,6 @@ typedef struct icmp_s { 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 */ diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c index 2d77bd0033..fe38e6b31f 100644 --- a/usr/src/uts/common/inet/tcp/tcp.c +++ b/usr/src/uts/common/inet/tcp/tcp.c @@ -18622,7 +18622,7 @@ tcp_zcopy_check(tcp_t *tcp) (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) { /* diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c index 5347af5826..f7a8dc26d8 100644 --- a/usr/src/uts/common/inet/udp/udp.c +++ b/usr/src/uts/common/inet/udp/udp.c @@ -2666,6 +2666,8 @@ udp_opt_get_locked(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 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 @@ udp_opt_get_locked(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 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 @@ udp_opt_set_locked(queue_t *q, uint_t optset_context, int level, 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 @@ udp_opt_set_locked(queue_t *q, uint_t optset_context, int level, 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 @@ udp_output_v4(conn_t *connp, mblk_t *mp, ipaddr_t v4dst, uint16_t port, 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 || diff --git a/usr/src/uts/common/inet/udp/udp_opt_data.c b/usr/src/uts/common/inet/udp/udp_opt_data.c index 07cc9e638f..9c7121fba6 100644 --- a/usr/src/uts/common/inet/udp/udp_opt_data.c +++ b/usr/src/uts/common/inet/udp/udp_opt_data.c @@ -131,12 +131,13 @@ opdes_t udp_opt_arr[] = { { 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 }, diff --git a/usr/src/uts/common/inet/udp_impl.h b/usr/src/uts/common/inet/udp_impl.h index a77b605088..131bf3ed81 100644 --- a/usr/src/uts/common/inet/udp_impl.h +++ b/usr/src/uts/common/inet/udp_impl.h @@ -296,7 +296,6 @@ typedef struct udp_s { 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; diff --git a/usr/src/uts/common/netinet/in.h b/usr/src/uts/common/netinet/in.h index f46c9753d2..122b19b2c9 100644 --- a/usr/src/uts/common/netinet/in.h +++ b/usr/src/uts/common/netinet/in.h @@ -910,13 +910,9 @@ typedef struct ipsec_req { * 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 @@ typedef struct ipsec_req { */ #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> */ |