summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorSowmini Varadhan <Sowmini.Varadhan@Sun.COM>2009-05-19 15:07:44 -0400
committerSowmini Varadhan <Sowmini.Varadhan@Sun.COM>2009-05-19 15:07:44 -0400
commitee07f6e76390e460e7a3065fe91b5ca23a0fe6a8 (patch)
treeef4e30721303fb5bf11d591d82d11759d3952db0 /usr
parenteb42280b2139f489ab9ba5890cd6208cf3e58b38 (diff)
downloadillumos-gate-ee07f6e76390e460e7a3065fe91b5ca23a0fe6a8.tar.gz
6835200 IPv6 nce can be created in STALE state with bad link-layer info
6809387 BAD TRAP type=e in module "ip" due to NULL pointer under ipv6 6243060 SIOCSLIFNAME might be too liberal in the flags it allows to be modified
Diffstat (limited to 'usr')
-rw-r--r--usr/src/uts/common/inet/ip.h3
-rw-r--r--usr/src/uts/common/inet/ip/ip6_if.c2
-rw-r--r--usr/src/uts/common/inet/ip/ip_if.c89
-rw-r--r--usr/src/uts/common/inet/ip/ip_mroute.c1
-rw-r--r--usr/src/uts/common/inet/ip/ip_ndp.c7
5 files changed, 47 insertions, 55 deletions
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index d688615806..d587fa77fc 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -2893,9 +2893,6 @@ typedef struct ip_pktinfo {
#define ILL_CAN_WAIT(ill, q) \
(((q) != NULL) && !((ill)->ill_state_flags & (ILL_CONDEMNED)))
-#define ILL_CAN_LOOKUP_WALKER(ill) \
- (!((ill)->ill_state_flags & ILL_CONDEMNED))
-
#define IPIF_CAN_LOOKUP(ipif) \
(!((ipif)->ipif_state_flags & (IPIF_CONDEMNED | IPIF_CHANGING)) || \
IAM_WRITER_IPIF(ipif))
diff --git a/usr/src/uts/common/inet/ip/ip6_if.c b/usr/src/uts/common/inet/ip/ip6_if.c
index b592fc0cd1..e43ec55519 100644
--- a/usr/src/uts/common/inet/ip/ip6_if.c
+++ b/usr/src/uts/common/inet/ip/ip6_if.c
@@ -2448,6 +2448,8 @@ ipif_select_source_v6(ill_t *dstill, const in6_addr_t *dst,
if (IS_UNDER_IPMP(ill))
continue;
+ if (ill->ill_ipif == NULL)
+ continue;
/*
* For source address selection, we treat the ipif list as
* circular and continue until we get back to where we
diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c
index e6e9030f36..67eff68c28 100644
--- a/usr/src/uts/common/inet/ip/ip_if.c
+++ b/usr/src/uts/common/inet/ip/ip_if.c
@@ -3728,7 +3728,8 @@ ill_forward_set_on_ill(ill_t *ill, boolean_t enable)
if (ill->ill_isv6)
ill_set_nce_router_flags(ill, enable);
/* Notify routing socket listeners of this change. */
- ip_rts_ifmsg(ill->ill_ipif, RTSQ_DEFAULT);
+ if (ill->ill_ipif != NULL)
+ ip_rts_ifmsg(ill->ill_ipif, RTSQ_DEFAULT);
}
/*
@@ -17501,6 +17502,7 @@ ip_sioctl_slifname(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
phyint_t *phyi;
ip_stack_t *ipst;
struct lifreq *lifr = if_req;
+ uint64_t new_flags;
ASSERT(ipif != NULL);
ip1dbg(("ip_sioctl_slifname %s\n", lifr->lifr_name));
@@ -17522,18 +17524,6 @@ ip_sioctl_slifname(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
return (EALREADY);
/*
- * Set all the flags. Allows all kinds of override. Provide some
- * sanity checking by not allowing IFF_BROADCAST and IFF_MULTICAST
- * unless there is either multicast/broadcast support in the driver
- * or it is a pt-pt link.
- */
- if (lifr->lifr_flags & (IFF_PROMISC|IFF_ALLMULTI)) {
- /* Meaningless to IP thus don't allow them to be set. */
- ip1dbg(("ip_setname: EINVAL 1\n"));
- return (EINVAL);
- }
-
- /*
* If there's another ill already with the requested name, ensure
* that it's of the same type. Otherwise, ill_phyint_reinit() will
* fuse together two unrelated ills, which will cause chaos.
@@ -17557,59 +17547,60 @@ ip_sioctl_slifname(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
}
/*
- * For a DL_STYLE2 driver (ill_needs_attach), we would not have the
- * ill_bcast_addr_length info.
+ * We start off as IFF_IPV4 in ipif_allocate and become
+ * IFF_IPV4 or IFF_IPV6 here depending on lifr_flags value.
+ * The only flags that we read from user space are IFF_IPV4,
+ * IFF_IPV6, IFF_XRESOLV and IFF_BROADCAST.
+ *
+ * This ill has not been inserted into the global list.
+ * So we are still single threaded and don't need any lock
+ *
+ * Saniy check the flags.
*/
- if (!ill->ill_needs_attach &&
- ((lifr->lifr_flags & IFF_MULTICAST) &&
- !(lifr->lifr_flags & IFF_POINTOPOINT) &&
- ill->ill_bcast_addr_length == 0)) {
- /* Link not broadcast/pt-pt capable i.e. no multicast */
- ip1dbg(("ip_setname: EINVAL 2\n"));
- return (EINVAL);
- }
+
if ((lifr->lifr_flags & IFF_BROADCAST) &&
((lifr->lifr_flags & IFF_IPV6) ||
(!ill->ill_needs_attach && ill->ill_bcast_addr_length == 0))) {
- /* Link not broadcast capable or IPv6 i.e. no broadcast */
- ip1dbg(("ip_setname: EINVAL 3\n"));
- return (EINVAL);
- }
- if (lifr->lifr_flags & IFF_UP) {
- /* Can only be set with SIOCSLIFFLAGS */
- ip1dbg(("ip_setname: EINVAL 4\n"));
+ ip1dbg(("ip_sioctl_slifname: link not broadcast capable "
+ "or IPv6 i.e., no broadcast \n"));
return (EINVAL);
}
- if ((lifr->lifr_flags & (IFF_IPV6|IFF_IPV4)) != IFF_IPV6 &&
- (lifr->lifr_flags & (IFF_IPV6|IFF_IPV4)) != IFF_IPV4) {
- ip1dbg(("ip_setname: EINVAL 5\n"));
+
+ new_flags =
+ lifr->lifr_flags & (IFF_IPV6|IFF_IPV4|IFF_XRESOLV|IFF_BROADCAST);
+
+ if ((new_flags ^ (IFF_IPV6|IFF_IPV4)) == 0) {
+ ip1dbg(("ip_sioctl_slifname: flags must be exactly one of "
+ "IFF_IPV4 or IFF_IPV6\n"));
return (EINVAL);
}
/*
* Only allow the IFF_XRESOLV flag to be set on IPv6 interfaces.
*/
- if ((lifr->lifr_flags & IFF_XRESOLV) &&
- !(lifr->lifr_flags & IFF_IPV6) &&
+ if ((new_flags & IFF_XRESOLV) && !(new_flags & IFF_IPV6) &&
!(ipif->ipif_isv6)) {
- ip1dbg(("ip_setname: EINVAL 6\n"));
+ ip1dbg(("ip_sioctl_slifname: XRESOLV only allowed on "
+ "IPv6 interface\n"));
return (EINVAL);
}
/*
- * The user has done SIOCGLIFFLAGS prior to this ioctl and hence
- * we have all the flags here. So, we assign rather than we OR.
- * We can't OR the flags here because we don't want to set
- * both IFF_IPV4 and IFF_IPV6. We start off as IFF_IPV4 in
- * ipif_allocate and become IFF_IPV4 or IFF_IPV6 here depending
- * on lifr_flags value here.
- */
- /*
- * This ill has not been inserted into the global list.
- * So we are still single threaded and don't need any lock
+ * We always start off as IPv4, so only need to check for IPv6.
*/
- ipif->ipif_flags = lifr->lifr_flags & IFF_LOGINT_FLAGS & ~IFF_DUPLICATE;
- ill->ill_flags = lifr->lifr_flags & IFF_PHYINTINST_FLAGS;
- ill->ill_phyint->phyint_flags = lifr->lifr_flags & IFF_PHYINT_FLAGS;
+ if ((new_flags & IFF_IPV6) != 0) {
+ ill->ill_flags |= ILLF_IPV6;
+ ill->ill_flags &= ~ILLF_IPV4;
+ }
+
+ if ((new_flags & IFF_BROADCAST) != 0)
+ ipif->ipif_flags |= IPIF_BROADCAST;
+ else
+ ipif->ipif_flags &= ~IPIF_BROADCAST;
+
+ if ((new_flags & IFF_XRESOLV) != 0)
+ ill->ill_flags |= ILLF_XRESOLV;
+ else
+ ill->ill_flags &= ~ILLF_XRESOLV;
/* We started off as V4. */
if (ill->ill_flags & ILLF_IPV6) {
diff --git a/usr/src/uts/common/inet/ip/ip_mroute.c b/usr/src/uts/common/inet/ip/ip_mroute.c
index 1a3df02418..82d9083488 100644
--- a/usr/src/uts/common/inet/ip/ip_mroute.c
+++ b/usr/src/uts/common/inet/ip/ip_mroute.c
@@ -3232,6 +3232,7 @@ ip_mroute_vif(mblk_t *mp, ip_stack_t *ipst)
if (!snmp_append_data(mp, (char *)&vi, sizeof (vi))) {
ip0dbg(("ip_mroute_vif: failed %ld bytes\n",
(size_t)sizeof (vi)));
+ mutex_exit(&ipst->ips_numvifs_mutex);
return (0);
}
}
diff --git a/usr/src/uts/common/inet/ip/ip_ndp.c b/usr/src/uts/common/inet/ip/ip_ndp.c
index fe6c0c585d..51f1487847 100644
--- a/usr/src/uts/common/inet/ip/ip_ndp.c
+++ b/usr/src/uts/common/inet/ip/ip_ndp.c
@@ -1355,8 +1355,10 @@ ndp_query(ill_t *ill, struct lif_nd_req *lnr)
if (nce == NULL)
return (ESRCH);
/* If in INCOMPLETE state, no link layer address is available yet */
- if (nce->nce_state == ND_INCOMPLETE)
- goto done;
+ if (!NCE_ISREACHABLE(nce)) {
+ NCE_REFRELE(nce);
+ return (ESRCH);
+ }
dl = (dl_unitdata_req_t *)nce->nce_res_mp->b_rptr;
if (ill->ill_flags & ILLF_XRESOLV)
lnr->lnr_hdw_len = dl->dl_dest_addr_length;
@@ -1370,7 +1372,6 @@ ndp_query(ill_t *ill, struct lif_nd_req *lnr)
lnr->lnr_flags = NDF_ISROUTER_ON;
if (nce->nce_flags & NCE_F_ANYCAST)
lnr->lnr_flags |= NDF_ANYCAST_ON;
-done:
NCE_REFRELE(nce);
return (0);
}