diff options
Diffstat (limited to 'usr/src/uts/common/inet')
-rw-r--r-- | usr/src/uts/common/inet/ip.h | 14 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip.c | 72 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip_if.c | 164 |
3 files changed, 125 insertions, 125 deletions
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index 748d9f26e7..401599cc80 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -22,7 +22,7 @@ /* * Copyright (c) 1990 Mentat Inc. * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, Joyent, Inc. All rights reserved. + * Copyright (c) 2016, Joyent, Inc. All rights reserved. * Copyright 2014 Nexenta Systems, Inc. All rights reserved. * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. */ @@ -1415,6 +1415,7 @@ typedef union ill_g_head_u { #define ILL_CAPAB_DLD 0x20 /* DLD capabilities */ #define ILL_CAPAB_DLD_POLL 0x40 /* Polling */ #define ILL_CAPAB_DLD_DIRECT 0x80 /* Direct function call */ +#define ILL_CAPAB_DLD_IPCHECK 0x100 /* Check if IPs are permitted */ /* * Per-ill Hardware Checksumming capbilities. @@ -1728,6 +1729,8 @@ typedef struct ill_s { * Capabilities related fields. */ uint_t ill_dlpi_capab_state; /* State of capability query, IDCS_* */ + kcondvar_t ill_dlpi_capab_cv; /* CV for broadcasting state changes */ + kmutex_t ill_dlpi_capab_lock; /* Lock for accessing above Cond Var */ uint_t ill_capab_pending_cnt; uint64_t ill_capabilities; /* Enabled capabilities, ILL_CAPAB_* */ ill_hcksum_capab_t *ill_hcksum_capab; /* H/W cksumming capabilities */ @@ -3575,6 +3578,8 @@ typedef void (*ip_flow_enable_t)(void *, ip_mac_tx_cookie_t); typedef void *(*ip_dld_callb_t)(void *, ip_flow_enable_t, void *); typedef boolean_t (*ip_dld_fctl_t)(void *, ip_mac_tx_cookie_t); +typedef boolean_t (*ip_mac_ipcheck_t)(void *, boolean_t, + in6_addr_t *); typedef int (*ip_capab_func_t)(void *, uint_t, void *, uint_t); @@ -3627,6 +3632,12 @@ typedef struct ill_dld_direct_s { /* DLD provided driver Tx */ void *idd_tx_fctl_dh; /* mac_client_handle */ } ill_dld_direct_t; +typedef struct ill_dld_ipcheck_s { + ip_mac_ipcheck_t idi_allowed_df; + void *idi_allowed_dh; +} ill_dld_ipcheck_t; + + /* IP - DLD polling capability */ typedef struct ill_dld_poll_s { ill_rx_ring_t idp_ring_tbl[ILL_MAX_RINGS]; @@ -3638,6 +3649,7 @@ struct ill_dld_capab_s { void *idc_capab_dh; /* dld_str_t *dsp */ ill_dld_direct_t idc_direct; ill_dld_poll_t idc_poll; + ill_dld_ipcheck_t idc_ipcheck; }; /* diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c index 73081b9c1c..ce9fcf7de1 100644 --- a/usr/src/uts/common/inet/ip/ip.c +++ b/usr/src/uts/common/inet/ip/ip.c @@ -4130,6 +4130,8 @@ ip_modclose(ill_t *ill) rw_destroy(&ill->ill_mcast_lock); mutex_destroy(&ill->ill_mcast_serializer); list_destroy(&ill->ill_nce); + cv_destroy(&ill->ill_dlpi_capab_cv); + mutex_destroy(&ill->ill_dlpi_capab_lock); /* * Now we are done with the module close pieces that @@ -8201,7 +8203,6 @@ ip_rput_dlpi_writer(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *dummy_arg) conn_t *connp = NULL; t_uscalar_t paddrreq; mblk_t *mp_hw; - boolean_t success; boolean_t ioctl_aborted = B_FALSE; boolean_t log = B_TRUE; @@ -8441,55 +8442,7 @@ ip_rput_dlpi_writer(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *dummy_arg) DTRACE_PROBE1(ip__rput__dlpi__bind__ack, ill_t *, ill); ill_nic_event_dispatch(ill, 0, NE_UP, NULL, 0); - /* - * Now bring up the resolver; when that is complete, we'll - * create IREs. Note that we intentionally mirror what - * ipif_up() would have done, because we got here by way of - * ill_dl_up(), which stopped ipif_up()'s processing. - */ - if (ill->ill_isv6) { - /* - * v6 interfaces. - * Unlike ARP which has to do another bind - * and attach, once we get here we are - * done with NDP - */ - (void) ipif_resolver_up(ipif, Res_act_initial); - if ((err = ipif_ndp_up(ipif, B_TRUE)) == 0) - err = ipif_up_done_v6(ipif); - } else if (ill->ill_net_type == IRE_IF_RESOLVER) { - /* - * ARP and other v4 external resolvers. - * Leave the pending mblk intact so that - * the ioctl completes in ip_rput(). - */ - if (connp != NULL) - mutex_enter(&connp->conn_lock); - mutex_enter(&ill->ill_lock); - success = ipsq_pending_mp_add(connp, ipif, q, mp1, 0); - mutex_exit(&ill->ill_lock); - if (connp != NULL) - mutex_exit(&connp->conn_lock); - if (success) { - err = ipif_resolver_up(ipif, Res_act_initial); - if (err == EINPROGRESS) { - freemsg(mp); - return; - } - mp1 = ipsq_pending_mp_get(ipsq, &connp); - } else { - /* The conn has started closing */ - err = EINTR; - } - } else { - /* - * This one is complete. Reply to pending ioctl. - */ - (void) ipif_resolver_up(ipif, Res_act_initial); - err = ipif_up_done(ipif); - } - - if ((err == 0) && (ill->ill_up_ipifs)) { + if (ill->ill_up_ipifs) { err = ill_up_ipifs(ill, q, mp1); if (err == EINPROGRESS) { freemsg(mp); @@ -8497,25 +8450,6 @@ ip_rput_dlpi_writer(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *dummy_arg) } } - /* - * If we have a moved ipif to bring up, and everything has - * succeeded to this point, bring it up on the IPMP ill. - * Otherwise, leave it down -- the admin can try to bring it - * up by hand if need be. - */ - if (ill->ill_move_ipif != NULL) { - if (err != 0) { - ill->ill_move_ipif = NULL; - } else { - ipif = ill->ill_move_ipif; - ill->ill_move_ipif = NULL; - err = ipif_up(ipif, q, mp1); - if (err == EINPROGRESS) { - freemsg(mp); - return; - } - } - } break; case DL_NOTIFY_IND: { diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c index 9a2da47620..38edc0304f 100644 --- a/usr/src/uts/common/inet/ip/ip_if.c +++ b/usr/src/uts/common/inet/ip/ip_if.c @@ -22,7 +22,7 @@ * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1990 Mentat Inc. * Copyright (c) 2013 by Delphix. All rights reserved. - * Copyright 2013 Joyent, Inc. + * Copyright 2016 Joyent, Inc. * Copyright (c) 2014, OmniTI Computer Consulting, Inc. All rights reserved. */ /* @@ -177,7 +177,7 @@ static ipif_t *ipif_lookup_on_name_async(char *name, size_t namelen, static int ill_alloc_ppa(ill_if_t *, ill_t *); static void ill_delete_interface_type(ill_if_t *); -static int ill_dl_up(ill_t *ill, ipif_t *ipif, mblk_t *mp, queue_t *q); +static int ill_dl_up(ill_t *ill, ipif_t *ipif); static void ill_dl_down(ill_t *ill); static void ill_down(ill_t *ill); static void ill_down_ipifs(ill_t *, boolean_t); @@ -721,7 +721,7 @@ ill_dlur_copy_address(uchar_t *phys_src, uint_t phys_length, */ mblk_t * ill_dlur_gen(uchar_t *addr, uint_t addr_length, t_uscalar_t sap, - t_scalar_t sap_length) + t_scalar_t sap_length) { dl_unitdata_req_t *dlur; mblk_t *mp; @@ -1383,6 +1383,18 @@ ill_capability_probe(ill_t *ill) ill->ill_dlpi_capab_state = IDCS_PROBE_SENT; } +static void +ill_capability_wait(ill_t *ill) +{ + while (ill->ill_capab_pending_cnt != 0) { + mutex_enter(&ill->ill_dlpi_capab_lock); + ipsq_exit(ill->ill_phyint->phyint_ipsq); + cv_wait(&ill->ill_dlpi_capab_cv, &ill->ill_dlpi_capab_lock); + mutex_exit(&ill->ill_dlpi_capab_lock); + VERIFY(ipsq_enter(ill, B_FALSE, CUR_OP) == B_TRUE); + } +} + void ill_capability_reset(ill_t *ill, boolean_t reneg) { @@ -1393,6 +1405,8 @@ ill_capability_reset(ill_t *ill, boolean_t reneg) ill->ill_dlpi_capab_state = reneg ? IDCS_RENEG : IDCS_RESET_SENT; + ASSERT(ill->ill_capab_reset_mp != NULL); + ill_capability_send(ill, ill->ill_capab_reset_mp); ill->ill_capab_reset_mp = NULL; /* @@ -2111,6 +2125,47 @@ ill_capability_lso_enable(ill_t *ill) } } +/* + * Check whether or not MAC will prevent us from sending with a given IP + * address. We fail open if we don't have the IPCHECK capability, since + * mac is responsible for actual enforcement, and ip is just performing + * a courtesy check to help prevent someone from unwittingly setting and + * attempting to use a bad address. + */ +static boolean_t +ill_ipcheck_addr(ill_t *ill, in6_addr_t *v6addr) +{ + if ((ill->ill_capabilities & ILL_CAPAB_DLD_IPCHECK) == 0) + return (B_TRUE); + + ill_dld_ipcheck_t *idi = &ill->ill_dld_capab->idc_ipcheck; + ip_mac_ipcheck_t ipcheck = idi->idi_allowed_df; + return (ipcheck(idi->idi_allowed_dh, ill->ill_isv6, v6addr)); +} + +static void +ill_capability_ipcheck_enable(ill_t *ill) +{ + ill_dld_capab_t *idc = ill->ill_dld_capab; + ill_dld_ipcheck_t *idi = &idc->idc_ipcheck; + dld_capab_ipcheck_t spoof; + int rc; + + ASSERT(IAM_WRITER_ILL(ill)); + + bzero(&spoof, sizeof (spoof)); + if ((rc = idc->idc_capab_df(idc->idc_capab_dh, DLD_CAPAB_IPCHECK, + &spoof, DLD_ENABLE)) == 0) { + idi->idi_allowed_df = (ip_mac_ipcheck_t)spoof.ipc_allowed_df; + idi->idi_allowed_dh = spoof.ipc_allowed_dh; + ill->ill_capabilities |= ILL_CAPAB_DLD_IPCHECK; + } else { + cmn_err(CE_WARN, "warning: could not enable IPCHECK " + "capability, rc = %d\n", rc); + DTRACE_PROBE2(ipcheck__off, (ill_t *), ill, (int), rc); + } +} + static void ill_capability_dld_enable(ill_t *ill) { @@ -2118,15 +2173,15 @@ ill_capability_dld_enable(ill_t *ill) ASSERT(IAM_WRITER_ILL(ill)); - if (ill->ill_isv6) - return; - ill_mac_perim_enter(ill, &mph); if (!ill->ill_isv6) { ill_capability_direct_enable(ill); ill_capability_poll_enable(ill); ill_capability_lso_enable(ill); } + + ill_capability_ipcheck_enable(ill); + ill->ill_capabilities |= ILL_CAPAB_DLD; ill_mac_perim_exit(ill, mph); } @@ -2191,6 +2246,15 @@ ill_capability_dld_disable(ill_t *ill) NULL, DLD_DISABLE); } + if ((ill->ill_capabilities & ILL_CAPAB_DLD_IPCHECK) != 0) { + ASSERT(ill->ill_dld_capab->idc_ipcheck.idi_allowed_df != NULL); + ASSERT(ill->ill_dld_capab->idc_ipcheck.idi_allowed_dh != NULL); + + ill->ill_capabilities &= ~ILL_CAPAB_DLD_IPCHECK; + (void) idc->idc_capab_df(idc->idc_capab_dh, DLD_CAPAB_IPCHECK, + NULL, DLD_DISABLE); + } + ill->ill_capabilities &= ~ILL_CAPAB_DLD; ill_mac_perim_exit(ill, mph); } @@ -3432,6 +3496,9 @@ ill_init_common(ill_t *ill, queue_t *q, boolean_t isv6, boolean_t is_loopback, ill->ill_max_buf = ND_MAX_Q; ill->ill_refcnt = 0; + cv_init(&ill->ill_dlpi_capab_cv, NULL, NULL, NULL); + mutex_init(&ill->ill_dlpi_capab_lock, NULL, MUTEX_DEFAULT, NULL); + return (0); } @@ -9676,7 +9743,6 @@ ip_sioctl_addr(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, in6_addr_t v6addr; boolean_t need_up = B_FALSE; ill_t *ill; - int i; ip1dbg(("ip_sioctl_addr(%s:%u %p)\n", ipif->ipif_ill->ill_name, ipif->ipif_id, (void *)ipif)); @@ -9751,20 +9817,9 @@ ip_sioctl_addr(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, IN6_IPADDR_TO_V4MAPPED(addr, &v6addr); } - /* - * verify that the address being configured is permitted by the - * ill_allowed_ips[] for the interface. - */ - if (ill->ill_allowed_ips_cnt > 0) { - for (i = 0; i < ill->ill_allowed_ips_cnt; i++) { - if (IN6_ARE_ADDR_EQUAL(&ill->ill_allowed_ips[i], - &v6addr)) - break; - } - if (i == ill->ill_allowed_ips_cnt) { - pr_addr_dbg("!allowed addr %s\n", AF_INET6, &v6addr); - return (EPERM); - } + /* verify that the address being configured is permitted by mac */ + if (!ill_ipcheck_addr(ill, &v6addr)) { + return (EPERM); } /* * Even if there is no change we redo things just to rerun @@ -10831,7 +10886,7 @@ ip_sioctl_mtu(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, /* ARGSUSED */ int ip_sioctl_get_mtu(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, - ip_ioctl_cmd_t *ipip, void *if_req) + ip_ioctl_cmd_t *ipip, void *if_req) { struct ifreq *ifr; struct lifreq *lifr; @@ -10857,7 +10912,7 @@ ip_sioctl_get_mtu(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, /* ARGSUSED2 */ int ip_sioctl_brdaddr(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, - ip_ioctl_cmd_t *ipip, void *if_req) + ip_ioctl_cmd_t *ipip, void *if_req) { ipaddr_t addr; ire_t *ire; @@ -12704,6 +12759,12 @@ ill_dl_down(ill_t *ill) } ill->ill_unbind_mp = NULL; + + mutex_enter(&ill->ill_lock); + ill->ill_dl_up = 0; + ill_nic_event_dispatch(ill, 0, NE_DOWN, NULL, 0); + mutex_exit(&ill->ill_lock); + if (mp != NULL) { ip1dbg(("ill_dl_down: %s (%u) for %s\n", dl_primstr(*(int *)mp->b_rptr), *(int *)mp->b_rptr, @@ -12726,11 +12787,10 @@ ill_dl_down(ill_t *ill) ill_capability_dld_disable(ill); ill_capability_reset(ill, B_FALSE); ill_dlpi_send(ill, mp); + + /* Wait for the capability reset to finish */ + ill_capability_wait(ill); } - mutex_enter(&ill->ill_lock); - ill->ill_dl_up = 0; - ill_nic_event_dispatch(ill, 0, NE_DOWN, NULL, 0); - mutex_exit(&ill->ill_lock); } void @@ -12859,6 +12919,10 @@ ill_capability_done(ill_t *ill) if (ill->ill_capab_pending_cnt == 0 && ill->ill_dlpi_capab_state == IDCS_OK) ill_capability_reset_alloc(ill); + + mutex_enter(&ill->ill_dlpi_capab_lock); + cv_broadcast(&ill->ill_dlpi_capab_cv); + mutex_exit(&ill->ill_dlpi_capab_lock); } /* @@ -14480,7 +14544,14 @@ ipif_up(ipif_t *ipif, queue_t *q, mblk_t *mp) * address/netmask etc cause a down/up dance, but * does not cause an unbind (DL_UNBIND) with the driver */ - return (ill_dl_up(ill, ipif, mp, q)); + if ((err = ill_dl_up(ill, ipif)) != 0) { + return (err); + } + } + + /* Reject bringing up interfaces with unusable IP addresses */ + if (!ill_ipcheck_addr(ill, &ipif->ipif_v6lcl_addr)) { + return (EPERM); } /* @@ -14593,24 +14664,22 @@ ill_delete_ires(ill_t *ill) /* * Perform a bind for the physical device. - * When the routine returns EINPROGRESS then mp has been consumed and - * the ioctl will be acked from ip_rput_dlpi. - * Allocate an unbind message and save it until ipif_down. + * + * When the routine returns successfully then dlpi has been bound and + * capabilities negotiated. An unbind message will have been allocated + * for later use in ipif_down. */ static int -ill_dl_up(ill_t *ill, ipif_t *ipif, mblk_t *mp, queue_t *q) +ill_dl_up(ill_t *ill, ipif_t *ipif) { mblk_t *bind_mp = NULL; mblk_t *unbind_mp = NULL; - conn_t *connp; - boolean_t success; int err; DTRACE_PROBE2(ill__downup, char *, "ill_dl_up", ill_t *, ill); ip1dbg(("ill_dl_up(%s)\n", ill->ill_name)); ASSERT(IAM_WRITER_ILL(ill)); - ASSERT(mp != NULL); /* * Make sure we have an IRE_MULTICAST in case we immediately @@ -14645,19 +14714,6 @@ ill_dl_up(ill_t *ill, ipif_t *ipif, mblk_t *mp, queue_t *q) if (unbind_mp == NULL) goto bad; } - /* - * Record state needed to complete this operation when the - * DL_BIND_ACK shows up. Also remember the pre-allocated mblks. - */ - connp = CONN_Q(q) ? Q_TO_CONN(q) : NULL; - ASSERT(connp != NULL || !CONN_Q(q)); - GRAB_CONN_LOCK(q); - mutex_enter(&ipif->ipif_ill->ill_lock); - success = ipsq_pending_mp_add(connp, ipif, q, mp, 0); - mutex_exit(&ipif->ipif_ill->ill_lock); - RELEASE_CONN_LOCK(q); - if (!success) - goto bad; /* * Save the unbind message for ill_dl_down(); it will be consumed when @@ -14669,6 +14725,8 @@ ill_dl_up(ill_t *ill, ipif_t *ipif, mblk_t *mp, queue_t *q) ill_dlpi_send(ill, bind_mp); /* Send down link-layer capabilities probe if not already done. */ ill_capability_probe(ill); + /* Wait for DLPI to be bound and the capability probe to finish */ + ill_capability_wait(ill); /* * Sysid used to rely on the fact that netboots set domainname @@ -14686,11 +14744,7 @@ ill_dl_up(ill_t *ill, ipif_t *ipif, mblk_t *mp, queue_t *q) cmn_err(CE_WARN, "no cached dhcp response"); } - /* - * This operation will complete in ip_rput_dlpi with either - * a DL_BIND_ACK or DL_ERROR_ACK. - */ - return (EINPROGRESS); + return (0); bad: ip1dbg(("ill_dl_up(%s) FAILED\n", ill->ill_name)); @@ -15593,7 +15647,7 @@ ip_select_source_v4(ill_t *ill, ipaddr_t setsrc, ipaddr_t dst, /* ARGSUSED */ int if_unitsel_restart(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp, - ip_ioctl_cmd_t *ipip, void *dummy_ifreq) + ip_ioctl_cmd_t *ipip, void *dummy_ifreq) { /* * ill_phyint_reinit merged the v4 and v6 into a single @@ -16250,7 +16304,7 @@ ill_ptpaddr_cnt(const ill_t *ill) /* ARGSUSED */ int ip_sioctl_get_lifusesrc(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, - ip_ioctl_cmd_t *ipip, void *ifreq) + ip_ioctl_cmd_t *ipip, void *ifreq) { struct lifreq *lifr = ifreq; |