summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_usrreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctp_usrreq.c')
-rw-r--r--sys/netinet/sctp_usrreq.c184
1 files changed, 90 insertions, 94 deletions
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index bf11663..77f15ae 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -223,7 +223,7 @@ sctp_notify_mbuf(struct sctp_inpcb *inp,
void
sctp_notify(struct sctp_inpcb *inp,
- int error,
+ struct ip *ip,
struct sctphdr *sh,
struct sockaddr *to,
struct sctp_tcb *stcb,
@@ -234,110 +234,103 @@ sctp_notify(struct sctp_inpcb *inp,
#endif
/* protection */
+ int reason;
+ struct icmp *icmph;
+
+
if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
(sh == NULL) || (to == NULL)) {
+ if (stcb)
+ SCTP_TCB_UNLOCK(stcb);
return;
}
/* First job is to verify the vtag matches what I would send */
if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
+ SCTP_TCB_UNLOCK(stcb);
return;
}
- /* FIX ME FIX ME PROTOPT i.e. no SCTP should ALWAYS be an ABORT */
+ icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
+ sizeof(struct ip)));
+ if (icmph->icmp_type != ICMP_UNREACH) {
+ /* We only care about unreachable */
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ if ((icmph->icmp_code == ICMP_UNREACH_NET) ||
+ (icmph->icmp_code == ICMP_UNREACH_HOST) ||
+ (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
+ (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
+ (icmph->icmp_code == ICMP_UNREACH_ISOLATED) ||
+ (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) ||
+ (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
+ (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
- if ((error == EHOSTUNREACH) || /* Host is not reachable */
- (error == EHOSTDOWN) || /* Host is down */
- (error == ECONNREFUSED) || /* Host refused the connection, (not
- * an abort?) */
- (error == ENOPROTOOPT) /* SCTP is not present on host */
- ) {
/*
* Hmm reachablity problems we must examine closely. If its
* not reachable, we may have lost a network. Or if there is
* NO protocol at the other end named SCTP. well we consider
* it a OOTB abort.
*/
- if ((error == EHOSTUNREACH) || (error == EHOSTDOWN)) {
- if (net->dest_state & SCTP_ADDR_REACHABLE) {
- /* Ok that destination is NOT reachable */
- SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
- net->error_count,
- net->failure_threshold,
- net);
-
- net->dest_state &= ~SCTP_ADDR_REACHABLE;
- net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
- /*
- * JRS 5/14/07 - If a destination is
- * unreachable, the PF bit is turned off.
- * This allows an unambiguous use of the PF
- * bit for destinations that are reachable
- * but potentially failed. If the
- * destination is set to the unreachable
- * state, also set the destination to the PF
- * state.
- */
- /*
- * Add debug message here if destination is
- * not in PF state.
- */
- /* Stop any running T3 timers here? */
- if (sctp_cmt_on_off && sctp_cmt_pf) {
- net->dest_state &= ~SCTP_ADDR_PF;
- SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
- net);
- }
- net->error_count = net->failure_threshold + 1;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
- stcb, SCTP_FAILED_THRESHOLD,
- (void *)net, SCTP_SO_NOT_LOCKED);
- }
- if (stcb) {
- SCTP_TCB_UNLOCK(stcb);
- }
- } else {
+ if (net->dest_state & SCTP_ADDR_REACHABLE) {
+ /* Ok that destination is NOT reachable */
+ SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
+ net->error_count,
+ net->failure_threshold,
+ net);
+
+ net->dest_state &= ~SCTP_ADDR_REACHABLE;
+ net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
/*
- * Here the peer is either playing tricks on us,
- * including an address that belongs to someone who
- * does not support SCTP OR was a userland
- * implementation that shutdown and now is dead. In
- * either case treat it like a OOTB abort with no
- * TCB
+ * JRS 5/14/07 - If a destination is unreachable,
+ * the PF bit is turned off. This allows an
+ * unambiguous use of the PF bit for destinations
+ * that are reachable but potentially failed. If the
+ * destination is set to the unreachable state, also
+ * set the destination to the PF state.
*/
- sctp_abort_notification(stcb, SCTP_PEER_FAULTY, SCTP_SO_NOT_LOCKED);
+ /*
+ * Add debug message here if destination is not in
+ * PF state.
+ */
+ /* Stop any running T3 timers here? */
+ if (sctp_cmt_on_off && sctp_cmt_pf) {
+ net->dest_state &= ~SCTP_ADDR_PF;
+ SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
+ net);
+ }
+ net->error_count = net->failure_threshold + 1;
+ sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
+ stcb, SCTP_FAILED_THRESHOLD,
+ (void *)net, SCTP_SO_NOT_LOCKED);
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) ||
+ (icmph->icmp_code == ICMP_UNREACH_PORT)) {
+ /*
+ * Here the peer is either playing tricks on us, including
+ * an address that belongs to someone who does not support
+ * SCTP OR was a userland implementation that shutdown and
+ * now is dead. In either case treat it like a OOTB abort
+ * with no TCB
+ */
+ reason = SCTP_PEER_FAULTY;
+ sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED);
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- so = SCTP_INP_SO(inp);
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
- SCTP_SOCKET_LOCK(so, 1);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ so = SCTP_INP_SO(inp);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
- SCTP_SOCKET_UNLOCK(so, 1);
- /*
- * SCTP_TCB_UNLOCK(stcb); MT: I think this is not
- * needed.
- */
+ SCTP_SOCKET_UNLOCK(so, 1);
+ /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
#endif
- /* no need to unlock here, since the TCB is gone */
- }
+ /* no need to unlock here, since the TCB is gone */
} else {
- /* Send all others to the app */
- if (stcb) {
- SCTP_TCB_UNLOCK(stcb);
- }
- if (inp->sctp_socket) {
-#ifdef SCTP_LOCK_LOGGING
- if (sctp_logging_level & SCTP_LOCK_LOGGING_ENABLE) {
- sctp_log_lock(inp, stcb, SCTP_LOG_LOCK_SOCK);
- }
-#endif
- SOCK_LOCK(inp->sctp_socket);
- inp->sctp_socket->so_error = error;
- sctp_sowwakeup(inp, inp->sctp_socket);
- SOCK_UNLOCK(inp->sctp_socket);
- }
+ SCTP_TCB_UNLOCK(stcb);
}
}
@@ -388,14 +381,7 @@ sctp_ctlinput(cmd, sa, vip)
&inp, &net, 1, vrf_id);
if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
if (cmd != PRC_MSGSIZE) {
- int cm;
-
- if (cmd == PRC_HOSTDEAD) {
- cm = EHOSTUNREACH;
- } else {
- cm = inetctlerrmap[cmd];
- }
- sctp_notify(inp, cm, sh,
+ sctp_notify(inp, ip, sh,
(struct sockaddr *)&to, stcb,
net);
} else {
@@ -1070,6 +1056,9 @@ sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
+/*
+ * NOTE: assumes addr lock is held
+ */
static size_t
sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
@@ -1235,12 +1224,17 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp,
{
size_t size = 0;
+ SCTP_IPI_ADDR_LOCK();
/* fill up addresses for the endpoint's default vrf */
size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
inp->def_vrf_id);
+ SCTP_IPI_ADDR_UNLOCK();
return (size);
}
+/*
+ * NOTE: assumes addr lock is held
+ */
static int
sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
{
@@ -1297,8 +1291,10 @@ sctp_count_max_addresses(struct sctp_inpcb *inp)
{
int cnt = 0;
+ SCTP_IPI_ADDR_LOCK();
/* count addresses for the endpoint's default VRF */
cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id);
+ SCTP_IPI_ADDR_UNLOCK();
return (cnt);
}
@@ -1655,9 +1651,9 @@ flags_out:
error = 0;
}
#endif
- if (error)
+ if (error) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
-
+ }
*optsize = sizeof(*av);
}
break;
@@ -3785,7 +3781,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
struct sctp_ifa *ifa;
ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr,
- stcb->asoc.vrf_id, 0);
+ stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
if (ifa == NULL) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
OpenPOWER on IntegriCloud