diff options
author | rrs <rrs@FreeBSD.org> | 2007-05-02 12:50:13 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-05-02 12:50:13 +0000 |
commit | 803b9be8be0827d6f2fde839f6dcd9225a2609be (patch) | |
tree | 93ea4f957056813b10463b788259dc0304a365e3 /sys/netinet | |
parent | 78898ea5a86dc4f5a06f63d1f2c50c2c6497bef9 (diff) | |
download | FreeBSD-src-803b9be8be0827d6f2fde839f6dcd9225a2609be.zip FreeBSD-src-803b9be8be0827d6f2fde839f6dcd9225a2609be.tar.gz |
- Somehow the disable fragment option got lost. We could
set/clear it but would not do it. Now we will.
- Moved to latest socket api for extended sndrcv info struct.
- Moved to support all new levels of fragment interleave (0-2).
- Codenomicon security test updates - length checks and such.
- Bug in stream reset (2 actually).
- setpeerprimary could unlock a null pointer, fixed.
- Added a flag in the pcb so netstat can see if we are listening easier.
Obtained from: (some of the Listen changes from Weongyo Jeong)
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/sctp.h | 1 | ||||
-rw-r--r-- | sys/netinet/sctp_auth.c | 10 | ||||
-rw-r--r-- | sys/netinet/sctp_bsd_addr.c | 88 | ||||
-rw-r--r-- | sys/netinet/sctp_constants.h | 5 | ||||
-rw-r--r-- | sys/netinet/sctp_header.h | 11 | ||||
-rw-r--r-- | sys/netinet/sctp_indata.c | 76 | ||||
-rw-r--r-- | sys/netinet/sctp_indata.h | 5 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 121 | ||||
-rw-r--r-- | sys/netinet/sctp_os_bsd.h | 7 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 338 | ||||
-rw-r--r-- | sys/netinet/sctp_output.h | 5 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.c | 163 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.h | 4 | ||||
-rw-r--r-- | sys/netinet/sctp_peeloff.c | 4 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 8 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 57 | ||||
-rw-r--r-- | sys/netinet/sctputil.h | 13 |
17 files changed, 562 insertions, 354 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h index e0d7b0b..c89d1c8 100644 --- a/sys/netinet/sctp.h +++ b/sys/netinet/sctp.h @@ -400,6 +400,7 @@ struct sctp_error_unrecognized_chunk { #define SCTP_PCB_FLAGS_BOUNDALL 0x00000004 #define SCTP_PCB_FLAGS_ACCEPTING 0x00000008 #define SCTP_PCB_FLAGS_UNBOUND 0x00000010 +#define SCTP_PCB_FLAGS_LISTENING 0x00000020 #define SCTP_PCB_FLAGS_CLOSE_IP 0x00040000 #define SCTP_PCB_FLAGS_WAS_CONNECTED 0x00080000 #define SCTP_PCB_FLAGS_WAS_ABORTED 0x00100000 diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c index 999e877..2086342 100644 --- a/sys/netinet/sctp_auth.c +++ b/sys/netinet/sctp_auth.c @@ -1440,7 +1440,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, if (plen > sizeof(random_store)) break; phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)random_store, plen); + (struct sctp_paramhdr *)random_store, min(plen, sizeof(random_store))); if (phdr == NULL) return; /* save the random and length for the key */ @@ -1453,7 +1453,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, if (plen > sizeof(hmacs_store)) break; phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)hmacs_store, plen); + (struct sctp_paramhdr *)hmacs_store, min(plen, sizeof(hmacs_store))); if (phdr == NULL) return; /* save the hmacs list and num for the key */ @@ -1475,7 +1475,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m, if (plen > sizeof(chunks_store)) break; phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)chunks_store, plen); + (struct sctp_paramhdr *)chunks_store, min(plen, sizeof(chunks_store))); if (phdr == NULL) return; chunks = (struct sctp_auth_chunk_list *)phdr; @@ -1850,7 +1850,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit) int num_ent, i; phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&local_store, plen); + (struct sctp_paramhdr *)&local_store, min(plen, sizeof(local_store))); if (phdr == NULL) { return (-1); } @@ -1889,7 +1889,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit) if (plen > sizeof(store)) break; phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)store, plen); + (struct sctp_paramhdr *)store, min(plen, sizeof(store))); if (phdr == NULL) return (-1); hmacs = (struct sctp_auth_hmac_algo *)phdr; diff --git a/sys/netinet/sctp_bsd_addr.c b/sys/netinet/sctp_bsd_addr.c index 4f83668..2ad0899 100644 --- a/sys/netinet/sctp_bsd_addr.c +++ b/sys/netinet/sctp_bsd_addr.c @@ -44,14 +44,10 @@ __FBSDID("$FreeBSD$"); #include <netinet/sctputil.h> #include <netinet/sctp_timer.h> #include <netinet/sctp_asconf.h> +#include <netinet/sctp_sysctl.h> #include <netinet/sctp_indata.h> #include <sys/unistd.h> -#ifdef SCTP_DEBUG -extern uint32_t sctp_debug_on; - -#endif - #if defined(SCTP_USE_THREAD_BASED_ITERATOR) void @@ -211,7 +207,7 @@ sctp_init_ifns_for_vrf(int vrfid) ifn->if_xname, (void *)ifa, ifa->ifa_addr, - ifa_flags + ifa_flags, 0 ); if (sctp_ifa) { sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE; @@ -245,7 +241,6 @@ static uint8_t first_time = 0; void sctp_addr_change(struct ifaddr *ifa, int cmd) { - struct sctp_laddr *wi; struct sctp_ifa *ifap = NULL; uint32_t ifa_flags = 0; struct in6_ifaddr *ifa6; @@ -293,58 +288,53 @@ sctp_addr_change(struct ifaddr *ifa, int cmd) ifap = sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp, ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type, ifa->ifa_ifp->if_xname, - (void *)ifa, ifa->ifa_addr, ifa_flags); - /* - * Bump up the refcount so that when the timer completes it - * will drop back down. - */ - if (ifap) - atomic_add_int(&ifap->refcount, 1); + (void *)ifa, ifa->ifa_addr, ifa_flags, 1); } else if (cmd == RTM_DELETE) { - ifap = sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, ifa->ifa_ifp->if_index); + sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, ifa->ifa_ifp->if_index); /* * We don't bump refcount here so when it completes the * final delete will happen. */ } - if (ifap == NULL) - return; +} - wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr); - if (wi == NULL) { - /* - * Gak, what can we do? We have lost an address change can - * you say HOSED? - */ -#ifdef SCTP_DEBUG - if (sctp_debug_on & SCTP_DEBUG_PCB1) { - printf("Lost and address change ???\n"); - } -#endif /* SCTP_DEBUG */ +struct mbuf * +sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, + int how, int allonebuf, int type) +{ + struct mbuf *m = NULL; - /* Opps, must decrement the count */ - sctp_free_ifa(ifap); - return; + m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0); + if (m == NULL) { + /* bad, no memory */ + return (m); } - SCTP_INCR_LADDR_COUNT(); - bzero(wi, sizeof(*wi)); - wi->ifa = ifap; - if (cmd == RTM_ADD) { - wi->action = SCTP_ADD_IP_ADDRESS; - } else if (cmd == RTM_DELETE) { - wi->action = SCTP_DEL_IP_ADDRESS; + if (allonebuf) { + int siz; + + if (SCTP_BUF_IS_EXTENDED(m)) { + siz = SCTP_BUF_EXTEND_SIZE(m); + } else { + if (want_header) + siz = MHLEN; + else + siz = MLEN; + } + if (siz < space_needed) { + m_freem(m); + return (NULL); + } } - SCTP_IPI_ITERATOR_WQ_LOCK(); - /* - * Should this really be a tailq? As it is we will process the - * newest first :-0 - */ - LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr); - sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, - (struct sctp_inpcb *)NULL, - (struct sctp_tcb *)NULL, - (struct sctp_nets *)NULL); - SCTP_IPI_ITERATOR_WQ_UNLOCK(); + if (SCTP_BUF_NEXT(m)) { + sctp_m_freem(SCTP_BUF_NEXT(m)); + SCTP_BUF_NEXT(m) = NULL; + } +#ifdef SCTP_MBUF_LOGGING + if (SCTP_BUF_IS_EXTENDED(m)) { + sctp_log_mb(m, SCTP_MBUF_IALLOC); + } +#endif + return (m); } diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index cf301a2..3922222 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -196,7 +196,10 @@ __FBSDID("$FreeBSD$"); #define SCTP_FLIGHT_LOG_UP_REVOKE 113 #define SCTP_FLIGHT_LOG_DOWN_PDRP 114 #define SCTP_FLIGHT_LOG_DOWN_PMTU 115 -#define SCTP_LOG_MAX_TYPES 116 +#define SCTP_SACK_LOG_NORMAL 116 +#define SCTP_SACK_LOG_EXPRESS 117 + +#define SCTP_LOG_MAX_TYPES 118 /* * To turn on various logging, you must first define SCTP_STAT_LOGGING. Then * to get something to log you define one of the logging defines i.e. diff --git a/sys/netinet/sctp_header.h b/sys/netinet/sctp_header.h index 4b2a758..d2013ff 100644 --- a/sys/netinet/sctp_header.h +++ b/sys/netinet/sctp_header.h @@ -64,13 +64,17 @@ struct sctp_cookie_perserve_param { }; #define SCTP_ARRAY_MIN_LEN 1 - /* Host Name Address */ struct sctp_host_name_param { struct sctp_paramhdr ph;/* type=SCTP_HOSTNAME_ADDRESS */ char name[SCTP_ARRAY_MIN_LEN]; /* host name */ }; +/* + * This is the maximum padded size of a s-a-p + * so paramheadr + 3 address types (6 bytes) + 2 byte pad = 12 + */ +#define SCTP_MAX_ADDR_PARAMS_SIZE 12 /* supported address type */ struct sctp_supported_addr_param { struct sctp_paramhdr ph;/* type=SCTP_SUPPORTED_ADDRTYPE */ @@ -121,6 +125,8 @@ struct sctp_asconf_addrv4_param { /* an ASCONF address (v4) parameter */ struct sctp_ipv4addr_param addrp; /* max storage size */ }; +#define SCTP_MAX_SUPPORTED_EXT 256 + struct sctp_supported_chunk_types_param { struct sctp_paramhdr ph;/* type = 0x8008 len = x */ uint8_t chunk_types[0]; @@ -490,6 +496,9 @@ struct sctp_stream_reset_resp_tsn { /* * Authenticated chunks support draft-ietf-tsvwg-sctp-auth */ + +/* Should we make the max be 32? */ +#define SCTP_RANDOM_MAX_SIZE 256 struct sctp_auth_random { struct sctp_paramhdr ph;/* type = 0x8002 */ uint8_t random_data[0]; diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index 2010d2a..bf5727a 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -1595,6 +1595,18 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, sctp_queue_op_err(stcb, mb); } SCTP_STAT_INCR(sctps_badsid); + SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap); + if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) { + /* we have a new high score */ + asoc->highest_tsn_inside_map = tsn; +#ifdef SCTP_MAP_LOGGING + sctp_log_map(0, 2, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT); +#endif + } + if (tsn == (asoc->cumulative_tsn + 1)) { + /* Update cum-ack */ + asoc->cumulative_tsn = tsn; + } return (0); } /* @@ -1631,10 +1643,6 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, asoc->strmin[strmno].last_sequence_delivered); } #endif - /* - * throw it in the stream so it gets cleaned up in - * association destruction - */ oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + 3 * sizeof(uint32_t)), 0, M_DONTWAIT, 1, MT_DATA); if (oper) { @@ -2014,7 +2022,7 @@ failed_pdapi_express_del: struct sctp_stream_reset_list *liste; if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) && - ((compare_with_wrap(tsn, liste->tsn, MAX_TSN)) || + ((compare_with_wrap(tsn, ntohl(liste->tsn), MAX_TSN)) || (tsn == ntohl(liste->tsn))) ) { /* @@ -2181,6 +2189,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort all_ones = 1; at = 0; for (i = 0; i < stcb->asoc.mapping_array_size; i++) { + if (asoc->mapping_array[i] == 0xff) { at += 8; last_all_ones = 1; @@ -2294,8 +2303,8 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort } /* check the special flag for stream resets */ if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) && - ((compare_with_wrap(asoc->cumulative_tsn, liste->tsn, MAX_TSN)) || - (asoc->cumulative_tsn == liste->tsn)) + ((compare_with_wrap(asoc->cumulative_tsn, ntohl(liste->tsn), MAX_TSN)) || + (asoc->cumulative_tsn == ntohl(liste->tsn))) ) { /* * we have finished working through the backlogged TSN's now @@ -2322,7 +2331,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort } } else if (ctl) { /* more than one in queue */ - while (!compare_with_wrap(ctl->sinfo_tsn, liste->tsn, MAX_TSN)) { + while (!compare_with_wrap(ctl->sinfo_tsn, ntohl(liste->tsn), MAX_TSN)) { /* * if ctl->sinfo_tsn is <= liste->tsn we can * process it which is the NOT of @@ -2522,12 +2531,13 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length, */ asoc->last_data_chunk_from = net; - /* + /*- * Now before we proceed we must figure out if this is a wasted * cluster... i.e. it is a small packet sent in and yet the driver * underneath allocated a full cluster for it. If so we must copy it * to a smaller mbuf and free up the cluster mbuf. This will help - * with cluster starvation. + * with cluster starvation. Note for __Panda__ we don't do this + * since it has clusters all the way down to 64 bytes. */ if (SCTP_BUF_LEN(m) < (long)MLEN && SCTP_BUF_NEXT(m) == NULL) { /* we only handle mbufs that are singletons.. not chains */ @@ -3082,6 +3092,11 @@ sctp_check_for_revoked(struct sctp_tcb *stcb, * time i.e. revoked. If it is MARKED it was ACK'ed * again. */ + if (compare_with_wrap(tp1->rec.data.TSN_seq, biggest_tsn_acked, + MAX_TSN)) + break; + + if (tp1->sent == SCTP_DATAGRAM_ACKED) { /* it has been revoked */ tp1->sent = SCTP_DATAGRAM_SENT; @@ -4148,13 +4163,32 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, uint32_t old_rwnd; int win_probe_recovery = 0; int win_probe_recovered = 0; - int j, done_once;; + int j, done_once = 0; + +#ifdef SCTP_LOG_SACK_ARRIVALS + sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack, + rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd); +#endif SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; + old_rwnd = asoc->peers_rwnd; if (compare_with_wrap(asoc->last_acked_seq, cumack, MAX_TSN)) { /* old ack */ return; + } else if (asoc->last_acked_seq == cumack) { + /* Window update sack */ + asoc->peers_rwnd = sctp_sbspace_sub(rwnd, + (uint32_t) (asoc->total_flight + (asoc->sent_queue_cnt * sctp_peer_chunk_oh))); + if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) { + /* SWS sender side engages */ + asoc->peers_rwnd = 0; + } + if (asoc->peers_rwnd > old_rwnd) { + goto again; + } + return; + } /* First setup for CC stuff */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { @@ -4210,7 +4244,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, #endif } } - old_rwnd = asoc->peers_rwnd; asoc->this_sack_highest_gap = cumack; stcb->asoc.overall_error_count = 0; if (compare_with_wrap(cumack, asoc->last_acked_seq, MAX_TSN)) { @@ -4411,7 +4444,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, win_probe_recovery = 1; } /* Now assure a timer where data is queued at */ - done_once = 0; again: j = 0; TAILQ_FOREACH(net, &asoc->nets, sctp_next) { @@ -4574,7 +4606,7 @@ again: void sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, - struct sctp_nets *net_from, int *abort_now) + struct sctp_nets *net_from, int *abort_now, int sack_len, uint32_t rwnd) { struct sctp_association *asoc; struct sctp_sack *sack; @@ -4624,22 +4656,18 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb, /* CMT DAC algo */ this_sack_lowest_newack = 0; j = 0; - sack_length = ntohs(ch->ch.chunk_length); - if (sack_length < sizeof(struct sctp_sack_chunk)) { -#ifdef SCTP_DEBUG - if (sctp_debug_on & SCTP_DEBUG_INDATA1) { - printf("Bad size on sack chunk .. to small\n"); - } -#endif - return; - } + sack_length = (unsigned int)sack_len; /* ECN Nonce */ SCTP_STAT_INCR(sctps_slowpath_sack); nonce_sum_flag = ch->ch.chunk_flags & SCTP_SACK_NONCE_SUM; cum_ack = last_tsn = ntohl(sack->cum_tsn_ack); num_seg = ntohs(sack->num_gap_ack_blks); - a_rwnd = (uint32_t) ntohl(sack->a_rwnd); + a_rwnd = rwnd; +#ifdef SCTP_LOG_SACK_ARRIVALS + sctp_misc_ints(SCTP_SACK_LOG_NORMAL, cum_ack, + rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd); +#endif /* CMT DAC algo */ cmt_dac_flag = ch->ch.chunk_flags & SCTP_SACK_CMT_DAC; num_dup = ntohs(sack->num_dup_tsns); diff --git a/sys/netinet/sctp_indata.h b/sys/netinet/sctp_indata.h index f1a9d41..70ba477 100644 --- a/sys/netinet/sctp_indata.h +++ b/sys/netinet/sctp_indata.h @@ -91,7 +91,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack, void sctp_handle_sack(struct sctp_sack_chunk *, struct sctp_tcb *, - struct sctp_nets *, int *); + struct sctp_nets *, int *, int, uint32_t); /* draft-ietf-tsvwg-usctp */ void @@ -109,7 +109,8 @@ sctp_update_acked(struct sctp_tcb *, struct sctp_shutdown_chunk *, int sctp_process_data(struct mbuf **, int, int *, int, struct sctphdr *, - struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, uint32_t *); + struct sctp_inpcb *, struct sctp_tcb *, + struct sctp_nets *, uint32_t *); void sctp_sack_check(struct sctp_tcb *, int, int, int *); diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 90de716..b41db74 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -2231,7 +2231,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, * another and get the tcb in the right place. */ sctp_move_pcb_and_assoc(*inp_p, inp, *stcb); - sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb); + sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb, M_NOWAIT); /* * now we must check to see if we were aborted while @@ -2798,9 +2798,11 @@ sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chu asoc = &stcb->asoc; if (TAILQ_EMPTY(&stcb->asoc.control_send_queue)) { + asoc->stream_reset_outstanding = 0; return (NULL); } if (stcb->asoc.str_reset == NULL) { + asoc->stream_reset_outstanding = 0; return (NULL); } chk = stcb->asoc.str_reset; @@ -3154,6 +3156,7 @@ sctp_handle_stream_reset(struct sctp_tcb *stcb, struct sctp_stream_reset_out_req return (ret_code); } chk->rec.chunk_id.id = SCTP_STREAM_RESET; + chk->rec.chunk_id.can_take_data = 0; chk->asoc = &stcb->asoc; chk->no_fr_allowed = 0; chk->book_size = chk->send_size = sizeof(struct sctp_chunkhdr); @@ -3181,7 +3184,6 @@ strres_nochunk: ch->chunk_flags = 0; ch->chunk_length = htons(chk->send_size); SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); - ph = (struct sctp_paramhdr *)&sr_req->sr_req; while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) { param_len = ntohs(ph->param_length); @@ -3726,7 +3728,8 @@ process_control_chunks: * because we don't have to process the peer's COOKIE. All * others get a complete chunk. */ - if (ch->chunk_type == SCTP_INITIATION_ACK) { + if ((ch->chunk_type == SCTP_INITIATION_ACK) || + (ch->chunk_type == SCTP_INITIATION)) { /* get an init-ack chunk */ ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, sizeof(struct sctp_init_ack_chunk), chunk_buf); @@ -3736,6 +3739,29 @@ process_control_chunks: SCTP_TCB_UNLOCK(locked_tcb); return (NULL); } + } else if (ch->chunk_type == SCTP_COOKIE_ECHO) { + if (chk_length > sizeof(chunk_buf)) { + /* + * use just the size of the chunk buffer so + * the front part of our cookie is intact. + * The rest of cookie processing should use + * the sctp_m_getptr() function to access + * the other parts. + */ + ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, + (sizeof(chunk_buf) - 4), + chunk_buf); + if (ch == NULL) { + *offset = length; + if (locked_tcb) + SCTP_TCB_UNLOCK(locked_tcb); + return (NULL); + } + } else { + /* We can fit it all */ + goto all_fits; + } + } else { /* get a complete chunk... */ if ((size_t)chk_length > sizeof(chunk_buf)) { @@ -3743,21 +3769,25 @@ process_control_chunks: struct sctp_paramhdr *phdr; oper = NULL; - oper = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), - 0, M_DONTWAIT, 1, MT_DATA); - if (oper) { - /* pre-reserve some space */ - SCTP_BUF_RESV_UF(oper, sizeof(struct sctp_chunkhdr)); - SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr); - phdr = mtod(oper, struct sctp_paramhdr *); - phdr->param_type = htons(SCTP_CAUSE_OUT_OF_RESC); - phdr->param_length = htons(sizeof(struct sctp_paramhdr)); - sctp_queue_op_err(stcb, oper); + if (stcb) { + oper = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), + 0, M_DONTWAIT, 1, MT_DATA); + + if (oper) { + /* pre-reserve some space */ + SCTP_BUF_RESV_UF(oper, sizeof(struct sctp_chunkhdr)); + SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr); + phdr = mtod(oper, struct sctp_paramhdr *); + phdr->param_type = htons(SCTP_CAUSE_OUT_OF_RESC); + phdr->param_length = htons(sizeof(struct sctp_paramhdr)); + sctp_queue_op_err(stcb, oper); + } } if (locked_tcb) SCTP_TCB_UNLOCK(locked_tcb); return (NULL); } + all_fits: ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, chk_length, chunk_buf); if (ch == NULL) { @@ -3902,8 +3932,16 @@ process_control_chunks: uint16_t num_seg; int nonce_sum_flag; + if (chk_length < sizeof(struct sctp_sack_chunk)) { +#ifdef SCTP_DEBUG + if (sctp_debug_on & SCTP_DEBUG_INDATA1) { + printf("Bad size on sack chunk .. to small\n"); + } +#endif + *offset = length; + return (NULL); + } sack = (struct sctp_sack_chunk *)ch; - nonce_sum_flag = ch->chunk_flags & SCTP_SACK_NONCE_SUM; cum_ack = ntohl(sack->sack.cum_tsn_ack); num_seg = ntohs(sack->sack.num_gap_ack_blks); @@ -3925,9 +3963,10 @@ process_control_chunks: * with no missing segments to go * this way too. */ - sctp_express_handle_sack(stcb, cum_ack, a_rwnd, nonce_sum_flag, &abort_now); + sctp_express_handle_sack(stcb, cum_ack, a_rwnd, nonce_sum_flag, + &abort_now); } else { - sctp_handle_sack(sack, stcb, *netp, &abort_now); + sctp_handle_sack(sack, stcb, *netp, &abort_now, chk_length, a_rwnd); } if (abort_now) { /* ABORT signal from sack processing */ @@ -3955,7 +3994,11 @@ process_control_chunks: printf("SCTP_HEARTBEAT-ACK\n"); } #endif /* SCTP_DEBUG */ - + if (chk_length != sizeof(struct sctp_heartbeat_chunk)) { + /* Its not ours */ + *offset = length; + return (NULL); + } /* He's alive so give him credit */ stcb->asoc.overall_error_count = 0; SCTP_STAT_INCR(sctps_recvheartbeatack); @@ -3979,7 +4022,11 @@ process_control_chunks: printf("SCTP_SHUTDOWN\n"); } #endif /* SCTP_DEBUG */ - { + if (chk_length != sizeof(struct sctp_shutdown_chunk)) { + *offset = length; + return (NULL); + + } { int abort_flag = 0; sctp_handle_shutdown((struct sctp_shutdown_chunk *)ch, @@ -4162,6 +4209,11 @@ process_control_chunks: } #endif /* SCTP_DEBUG */ /* He's alive so give him credit */ + if (chk_length != sizeof(struct sctp_ecne_chunk)) { + /* Its not ours */ + *offset = length; + return (NULL); + } stcb->asoc.overall_error_count = 0; sctp_handle_ecn_echo((struct sctp_ecne_chunk *)ch, stcb); @@ -4173,6 +4225,11 @@ process_control_chunks: } #endif /* SCTP_DEBUG */ /* He's alive so give him credit */ + if (chk_length != sizeof(struct sctp_cwr_chunk)) { + /* Its not ours */ + *offset = length; + return (NULL); + } stcb->asoc.overall_error_count = 0; sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb); @@ -4215,6 +4272,11 @@ process_control_chunks: printf("SCTP_ASCONF-ACK\n"); } #endif /* SCTP_DEBUG */ + if (chk_length < sizeof(struct sctp_asconf_ack_chunk)) { + /* Its not ours */ + *offset = length; + return (NULL); + } /* He's alive so give him credit */ stcb->asoc.overall_error_count = 0; @@ -4227,6 +4289,11 @@ process_control_chunks: printf("SCTP_FWD-TSN\n"); } #endif /* SCTP_DEBUG */ + if (chk_length < sizeof(struct sctp_forward_tsn_chunk)) { + /* Its not ours */ + *offset = length; + return (NULL); + } /* He's alive so give him credit */ { int abort_flag = 0; @@ -4258,6 +4325,11 @@ process_control_chunks: #endif /* SCTP_DEBUG */ ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, chk_length, chunk_buf); + if (chk_length < sizeof(struct sctp_stream_reset_tsn_req)) { + /* Its not ours */ + *offset = length; + return (NULL); + } if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { /* We are not interested anymore */ sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_29); @@ -4285,6 +4357,11 @@ process_control_chunks: } #endif /* SCTP_DEBUG */ /* re-get it all please */ + if (chk_length < sizeof(struct sctp_pktdrop_chunk)) { + /* Its not ours */ + *offset = length; + return (NULL); + } ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset, chk_length, chunk_buf); @@ -4312,6 +4389,12 @@ process_control_chunks: /* skip this chunk (temporarily) */ goto next_chunk; } + if ((chk_length < (sizeof(struct sctp_auth_chunk))) || + (chk_length > (sizeof(struct sctp_auth_chunk) + SCTP_AUTH_DIGEST_LEN_MAX))) { + /* Its not ours */ + *offset = length; + return (NULL); + } if (got_auth == 1) { /* skip this chunk... it's already auth'd */ goto next_chunk; @@ -4902,5 +4985,7 @@ bad: if (m) { sctp_m_freem(m); } + /* For BSD/MAC this does nothing */ + SCTP_RELEASE_PAK(i_pak); return; } diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h index 81e028c..b01287e 100644 --- a/sys/netinet/sctp_os_bsd.h +++ b/sys/netinet/sctp_os_bsd.h @@ -226,6 +226,7 @@ typedef struct callout sctp_os_timer_t; #define SCTP_HEADER_TO_CHAIN(m) (m) #define SCTP_HEADER_LEN(m) (m->m_pkthdr.len) #define SCTP_GET_HEADER_FOR_OUTPUT(len) sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA) +#define SCTP_RELEASE_PAK(i_pak) /* Attach the chain of data into the sendable packet. */ #define SCTP_ATTACH_CHAIN(pak, m, packet_length) do { \ @@ -242,7 +243,6 @@ typedef struct callout sctp_os_timer_t; * into the chain of data holders, for BSD * its a NOP. */ -#define SCTP_PAK_TO_BUF(i_pak) (i_pak) /* Macro's for getting length from V6/V4 header */ #define SCTP_GET_IPV4_LENGTH(iph) (iph->ip_len) @@ -273,6 +273,11 @@ typedef struct callout sctp_os_timer_t; typedef struct route sctp_route_t; +struct mbuf * +sctp_get_mbuf_for_msg(unsigned int space_needed, + int want_header, int how, int allonebuf, int type); + + /* * SCTP AUTH */ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 71ef568..96d9495 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3160,43 +3160,6 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, int cpsize) return (0); } - -struct mbuf * -sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, - int how, int allonebuf, int type) -{ - struct mbuf *m = NULL; - - m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0); - if (allonebuf) { - int siz; - - if (SCTP_BUF_IS_EXTENDED(m)) { - siz = SCTP_BUF_EXTEND_SIZE(m); - } else { - if (want_header) - siz = MHLEN; - else - siz = MLEN; - } - if (siz < space_needed) { - m_freem(m); - return (NULL); - } - } - if (SCTP_BUF_NEXT(m)) { - sctp_m_freem(SCTP_BUF_NEXT(m)); - SCTP_BUF_NEXT(m) = NULL; - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BUF_IS_EXTENDED(m)) { - sctp_log_mb(m, SCTP_MBUF_IALLOC); - } -#endif - return (m); -} - - static struct mbuf * sctp_add_cookie(struct sctp_inpcb *inp, struct mbuf *init, int init_offset, struct mbuf *initack, int initack_offset, struct sctp_state_cookie *stc_in) @@ -3569,10 +3532,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, printf("RTP route is %p through\n", ro->ro_rt); } #endif - +#ifdef _WHY_THIS_CODE if ((have_mtu) && (net) && (have_mtu > net->mtu)) { ro->ro_rt->rt_ifp->if_mtu = net->mtu; } +#endif if (ro != &iproute) { memcpy(&iproute, ro, sizeof(*ro)); } @@ -3580,9 +3544,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, ro, o_flgs, inp->ip_inp.inp.inp_moptions ,(struct inpcb *)NULL ); +#ifdef _WHY_THIS_CODE if ((ro->ro_rt) && (have_mtu) && (net) && (have_mtu > net->mtu)) { ro->ro_rt->rt_ifp->if_mtu = have_mtu; } +#endif SCTP_STAT_INCR(sctps_sendpackets); SCTP_STAT_INCR_COUNTER64(sctps_outpackets); if (ret) @@ -4150,9 +4116,9 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, struct sctp_paramhdr *phdr, params; struct mbuf *mat, *op_err; - char tempbuf[SCTP_CHUNK_BUFFER_SIZE]; + char tempbuf[SCTP_PARAM_BUFFER_SIZE]; int at, limit, pad_needed; - uint16_t ptype, plen; + uint16_t ptype, plen, padded_size; int err_at; *abort_processing = 0; @@ -4166,105 +4132,164 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, while ((phdr != NULL) && ((size_t)limit >= sizeof(struct sctp_paramhdr))) { ptype = ntohs(phdr->param_type); plen = ntohs(phdr->param_length); - limit -= SCTP_SIZE32(plen); - if (plen < sizeof(struct sctp_paramhdr)) { -#ifdef SCTP_DEBUG - if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { - printf("sctp_output.c:Impossible length in parameter < %d\n", plen); - } -#endif - *abort_processing = 1; - break; + if ((plen > limit) || (plen < sizeof(struct sctp_paramhdr))) { + /* wacked parameter */ + goto invalid_size; } - /* + limit -= SCTP_SIZE32(plen); + /*- * All parameters for all chunks that we know/understand are * listed here. We process them other places and make * appropriate stop actions per the upper bits. However this * is the generic routine processor's can call to get back * an operr.. to either incorporate (init-ack) or send. */ - if ((ptype == SCTP_HEARTBEAT_INFO) || - (ptype == SCTP_IPV4_ADDRESS) || - (ptype == SCTP_IPV6_ADDRESS) || - (ptype == SCTP_STATE_COOKIE) || - (ptype == SCTP_UNRECOG_PARAM) || - (ptype == SCTP_COOKIE_PRESERVE) || - (ptype == SCTP_SUPPORTED_ADDRTYPE) || - (ptype == SCTP_PRSCTP_SUPPORTED) || - (ptype == SCTP_ADD_IP_ADDRESS) || - (ptype == SCTP_DEL_IP_ADDRESS) || - (ptype == SCTP_ECN_CAPABLE) || - (ptype == SCTP_ULP_ADAPTATION) || - (ptype == SCTP_ERROR_CAUSE_IND) || - (ptype == SCTP_RANDOM) || - (ptype == SCTP_CHUNK_LIST) || - (ptype == SCTP_CHUNK_LIST) || - (ptype == SCTP_SET_PRIM_ADDR) || - (ptype == SCTP_SUCCESS_REPORT) || - (ptype == SCTP_ULP_ADAPTATION) || - (ptype == SCTP_SUPPORTED_CHUNK_EXT) || - (ptype == SCTP_ECN_NONCE_SUPPORTED) - ) { - /* no skip it */ - at += SCTP_SIZE32(plen); - } else if (ptype == SCTP_HOSTNAME_ADDRESS) { - /* We can NOT handle HOST NAME addresses!! */ - int l_len; + padded_size = SCTP_SIZE32(plen); + switch (ptype) { + /* Param's with variable size */ + case SCTP_HEARTBEAT_INFO: + case SCTP_STATE_COOKIE: + case SCTP_UNRECOG_PARAM: + case SCTP_ERROR_CAUSE_IND: + /* ok skip fwd */ + at += padded_size; + break; + /* Param's with variable size within a range */ + case SCTP_CHUNK_LIST: + case SCTP_SUPPORTED_CHUNK_EXT: + if (padded_size > (sizeof(struct sctp_supported_chunk_types_param) + (sizeof(uint8_t) * SCTP_MAX_SUPPORTED_EXT))) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_SUPPORTED_ADDRTYPE: + if (padded_size > SCTP_MAX_ADDR_PARAMS_SIZE) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_RANDOM: + if (padded_size > (sizeof(struct sctp_auth_random) + SCTP_RANDOM_MAX_SIZE)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_SET_PRIM_ADDR: + case SCTP_DEL_IP_ADDRESS: + case SCTP_ADD_IP_ADDRESS: + if ((padded_size != sizeof(struct sctp_asconf_addrv4_param)) && + (padded_size != sizeof(struct sctp_asconf_addr_param))) { + goto invalid_size; + } + at += padded_size; + break; + /* Param's with a fixed size */ + case SCTP_IPV4_ADDRESS: + if (padded_size != sizeof(struct sctp_ipv4addr_param)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_IPV6_ADDRESS: + if (padded_size != sizeof(struct sctp_ipv6addr_param)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_COOKIE_PRESERVE: + if (padded_size != sizeof(struct sctp_cookie_perserve_param)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_ECN_NONCE_SUPPORTED: + case SCTP_PRSCTP_SUPPORTED: + if (padded_size != sizeof(struct sctp_paramhdr)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_ECN_CAPABLE: + if (padded_size != sizeof(struct sctp_ecn_supported_param)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_ULP_ADAPTATION: + if (padded_size != sizeof(struct sctp_adaptation_layer_indication)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_SUCCESS_REPORT: + if (padded_size != sizeof(struct sctp_asconf_paramhdr)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_HOSTNAME_ADDRESS: + { + /* We can NOT handle HOST NAME addresses!! */ + int l_len; #ifdef SCTP_DEBUG - if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { - printf("Can't handle hostname addresses.. abort processing\n"); - } + if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { + printf("Can't handle hostname addresses.. abort processing\n"); + } #endif - *abort_processing = 1; - if (op_err == NULL) { - /* Ok need to try to get a mbuf */ - l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - l_len += plen; - l_len += sizeof(struct sctp_paramhdr); - op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA); - if (op_err) { - SCTP_BUF_LEN(op_err) = 0; - /* - * pre-reserve space for ip and sctp - * header and chunk hdr - */ - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); + *abort_processing = 1; + if (op_err == NULL) { + /* Ok need to try to get a mbuf */ + l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + l_len += plen; + l_len += sizeof(struct sctp_paramhdr); + op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA); + if (op_err) { + SCTP_BUF_LEN(op_err) = 0; + /* + * pre-reserve space for ip + * and sctp header and + * chunk hdr + */ + SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); + } } - } - if (op_err) { - /* If we have space */ - struct sctp_paramhdr s; + if (op_err) { + /* If we have space */ + struct sctp_paramhdr s; - if (err_at % 4) { - uint32_t cpthis = 0; + if (err_at % 4) { + uint32_t cpthis = 0; - pad_needed = 4 - (err_at % 4); - m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis); - err_at += pad_needed; - } - s.param_type = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR); - s.param_length = htons(sizeof(s) + plen); - m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s); - err_at += sizeof(s); - phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, plen); - if (phdr == NULL) { - sctp_m_freem(op_err); - /* - * we are out of memory but we still - * need to have a look at what to do - * (the system is in trouble - * though). - */ - return (NULL); + pad_needed = 4 - (err_at % 4); + m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis); + err_at += pad_needed; + } + s.param_type = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR); + s.param_length = htons(sizeof(s) + plen); + m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s); + err_at += sizeof(s); + phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf), plen)); + if (phdr == NULL) { + sctp_m_freem(op_err); + /* + * we are out of memory but + * we still need to have a + * look at what to do (the + * system is in trouble + * though). + */ + return (NULL); + } + m_copyback(op_err, err_at, plen, (caddr_t)phdr); + err_at += plen; } - m_copyback(op_err, err_at, plen, (caddr_t)phdr); - err_at += plen; + return (op_err); + break; } - return (op_err); - } else { + default: /* * we do not recognize the parameter figure out what * we do. @@ -4304,7 +4329,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, if (plen > sizeof(tempbuf)) { plen = sizeof(tempbuf); } - phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, plen); + phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf), plen)); if (phdr == NULL) { sctp_m_freem(op_err); /* @@ -4314,6 +4339,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, * system is in trouble * though). */ + op_err = NULL; goto more_processing; } m_copyback(op_err, err_at, plen, (caddr_t)phdr); @@ -4327,11 +4353,43 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, /* skip this chunk and continue processing */ at += SCTP_SIZE32(plen); } + break; } phdr = sctp_get_next_param(mat, at, ¶ms, sizeof(params)); } return (op_err); +invalid_size: + *abort_processing = 1; + if ((op_err == NULL) && phdr) { + int l_len; + + l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + l_len += (2 * sizeof(struct sctp_paramhdr)); + op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA); + SCTP_BUF_LEN(op_err) = 0; + SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); + } + if ((op_err) && phdr) { + struct sctp_paramhdr s; + + if (err_at % 4) { + uint32_t cpthis = 0; + + pad_needed = 4 - (err_at % 4); + m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis); + err_at += pad_needed; + } + s.param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); + s.param_length = htons(sizeof(s) + sizeof(struct sctp_paramhdr)); + m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s); + err_at += sizeof(s); + /* Only copy back the p-hdr that caused the issue */ + m_copyback(op_err, err_at, sizeof(struct sctp_paramhdr), (caddr_t)phdr); + } + return (op_err); } static int @@ -7976,6 +8034,9 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, #endif asoc->sent_queue_cnt = 0; asoc->sent_queue_cnt_removeable = 0; + /* send back 0/0 so we enter normal transmission */ + *cnt_out = 0; + return (0); } TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { if ((chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) || @@ -8444,13 +8505,16 @@ sctp_chunk_output(struct sctp_inpcb *inp, { /*- * Ok this is the generic chunk service queue. we must do the - * following: - See if there are retransmits pending, if so we must - * do these first and return. - Service the stream queue that is - * next, moving any message (note I must get a complete message i.e. - * FIRST/MIDDLE and LAST to the out queue in one pass) and assigning - * TSN's - Check to see if the cwnd/rwnd allows any output, if so we - * go ahead and fomulate and send the low level chunks. Making sure - * to combine any control in the control chunk queue also. + * following: + * - See if there are retransmits pending, if so we must + * do these first. + * - Service the stream queue that is next, moving any + * message (note I must get a complete message i.e. + * FIRST/MIDDLE and LAST to the out queue in one pass) and assigning + * TSN's + * - Check to see if the cwnd/rwnd allows any output, if so we + * go ahead and fomulate and send the low level chunks. Making sure + * to combine any control in the control chunk queue also. */ struct sctp_association *asoc; struct sctp_nets *net; @@ -8497,7 +8561,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, */ if (from_where == SCTP_OUTPUT_FROM_COOKIE_ACK) { /*- - *Special hook for handling cookiess discarded + * Special hook for handling cookiess discarded * by peer that carried data. Send cookie-ack only * and then the next call with get the retran's. */ @@ -9064,7 +9128,7 @@ sctp_send_sack(struct sctp_tcb *stcb) gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)sack + sizeof(struct sctp_sack_chunk)); siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; - if (asoc->cumulative_tsn < asoc->mapping_array_base_tsn) { + if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) { offset = 1; /*- * cum-ack behind the mapping array, so we start and use all @@ -9075,7 +9139,7 @@ sctp_send_sack(struct sctp_tcb *stcb) offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn; /*- * we skip the first one when the cum-ack is at or above the - * mapping array base. + * mapping array base. Note this only works if */ jstart = 1; } @@ -11142,11 +11206,15 @@ sctp_lower_sosend(struct socket *so, } initial_out = uio->uio_resid; + SCTP_TCB_SEND_LOCK(stcb); if ((asoc->stream_locked) && (asoc->stream_locked_on != srcv->sinfo_stream)) { + SCTP_TCB_SEND_UNLOCK(stcb); error = EAGAIN; goto out; } + SCTP_TCB_SEND_UNLOCK(stcb); + strm = &stcb->asoc.strmout[srcv->sinfo_stream]; user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); if (strm->last_msg_incomplete == 0) { diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h index bebce43..584252a 100644 --- a/sys/netinet/sctp_output.h +++ b/sys/netinet/sctp_output.h @@ -40,11 +40,6 @@ __FBSDID("$FreeBSD$"); #if defined(_KERNEL) -struct mbuf * -sctp_get_mbuf_for_msg(unsigned int space_needed, - int want_header, int how, int allonebuf, int type); - - struct mbuf * sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp, diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 376d511..de7e96e 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -234,7 +234,7 @@ sctp_free_ifa(struct sctp_ifa *sctp_ifap) struct sctp_ifa * sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index, uint32_t ifn_type, const char *if_name, - void *ifa, struct sockaddr *addr, uint32_t ifa_flags) + void *ifa, struct sockaddr *addr, uint32_t ifa_flags, int dynamic_add) { struct sctp_vrf *vrf; struct sctp_ifn *sctp_ifnp = NULL; @@ -364,16 +364,55 @@ sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index, sctp_ifap->in_ifa_list = 1; vrf->total_ifa_count++; SCTP_IPI_ADDR_UNLOCK(); + if (dynamic_add) { + /* + * Bump up the refcount so that when the timer completes it + * will drop back down. + */ + struct sctp_laddr *wi; + + atomic_add_int(&sctp_ifap->refcount, 1); + wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr); + if (wi == NULL) { + /* + * Gak, what can we do? We have lost an address + * change can you say HOSED? + */ +#ifdef SCTP_DEBUG + if (sctp_debug_on & SCTP_DEBUG_PCB1) { + printf("Lost and address change ???\n"); + } +#endif /* SCTP_DEBUG */ + + /* Opps, must decrement the count */ + sctp_free_ifa(sctp_ifap); + return (NULL); + } + SCTP_INCR_LADDR_COUNT(); + bzero(wi, sizeof(*wi)); + wi->ifa = sctp_ifap; + wi->action = SCTP_ADD_IP_ADDRESS; + SCTP_IPI_ITERATOR_WQ_LOCK(); + /* + * Should this really be a tailq? As it is we will process + * the newest first :-0 + */ + LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr); + sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, + (struct sctp_inpcb *)NULL, + (struct sctp_tcb *)NULL, + (struct sctp_nets *)NULL); + SCTP_IPI_ITERATOR_WQ_UNLOCK(); + } return (sctp_ifap); } -struct sctp_ifa * +void sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr, uint32_t ifn_index) { struct sctp_vrf *vrf; struct sctp_ifa *sctp_ifap = NULL; - struct sctp_ifn *sctp_ifnp = NULL; SCTP_IPI_ADDR_LOCK(); @@ -382,22 +421,16 @@ sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr, printf("Can't find vrfid:%d\n", vrfid); goto out_now; } - sctp_ifnp = sctp_find_ifn(vrf, (void *)NULL, ifn_index); - if (sctp_ifnp == NULL) { - sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1); - } else { - sctp_ifap = sctp_find_ifa_in_ifn(sctp_ifnp, addr, 1); - } - + sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1); if (sctp_ifap) { sctp_ifap->localifa_flags &= SCTP_ADDR_VALID; sctp_ifap->localifa_flags |= SCTP_BEING_DELETED; - sctp_ifnp->ifa_count--; + sctp_ifap->ifn_p->ifa_count--; vrf->total_ifa_count--; LIST_REMOVE(sctp_ifap, next_bucket); LIST_REMOVE(sctp_ifap, next_ifa); sctp_ifap->in_ifa_list = 0; - atomic_add_int(&sctp_ifnp->refcount, -1); + atomic_add_int(&sctp_ifap->ifn_p->refcount, -1); } else { printf("Del Addr-ifn:%d Could not find address:", ifn_index); @@ -405,37 +438,51 @@ sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr, } out_now: SCTP_IPI_ADDR_UNLOCK(); - return (sctp_ifap); -} + if (sctp_ifap) { + struct sctp_laddr *wi; -/* - * Notes on locks for FreeBSD 5 and up. All association lookups that have a - * definte ep, the INP structure is assumed to be locked for reading. If we - * need to go find the INP (ususally when a **inp is passed) then we must - * lock the INFO structure first and if needed lock the INP too. Note that if - * we lock it we must - * - */ + wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr); + if (wi == NULL) { + /* + * Gak, what can we do? We have lost an address + * change can you say HOSED? + */ +#ifdef SCTP_DEBUG + if (sctp_debug_on & SCTP_DEBUG_PCB1) { + printf("Lost and address change ???\n"); + } +#endif /* SCTP_DEBUG */ + + /* Opps, must decrement the count */ + sctp_free_ifa(sctp_ifap); + return; + } + SCTP_INCR_LADDR_COUNT(); + bzero(wi, sizeof(*wi)); + wi->ifa = sctp_ifap; + wi->action = SCTP_DEL_IP_ADDRESS; + SCTP_IPI_ITERATOR_WQ_LOCK(); + /* + * Should this really be a tailq? As it is we will process + * the newest first :-0 + */ + LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr); + sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, + (struct sctp_inpcb *)NULL, + (struct sctp_tcb *)NULL, + (struct sctp_nets *)NULL); + SCTP_IPI_ITERATOR_WQ_UNLOCK(); + } + return; +} -/* - * Given a endpoint, look and find in its association list any association - * with the "to" address given. This can be a "from" address, too, for - * inbound packets. For outbound packets it is a true "to" address. - */ static struct sctp_tcb * sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, struct sockaddr *to, struct sctp_nets **netp, uint32_t vrf_id) { /**** ASSUMSES THE CALLER holds the INP_INFO_RLOCK */ - - /* - * Note for this module care must be taken when observing what to is - * for. In most of the rest of the code the TO field represents my - * peer and the FROM field represents my address. For this module it - * is reversed of that. - */ /* * If we support the TCP model, then we must now dig through to see * if we can find our endpoint in the list of tcp ep's. @@ -468,14 +515,14 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from, * to this ep and return the tcb from it. */ LIST_FOREACH(inp, ephead, sctp_hash) { - if (lport != inp->sctp_lport) { - continue; - } SCTP_INP_RLOCK(inp); if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { SCTP_INP_RUNLOCK(inp); continue; } + if (lport != inp->sctp_lport) { + continue; + } if (inp->def_vrf_id != vrf_id) { SCTP_INP_RUNLOCK(inp); continue; @@ -1224,7 +1271,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset, struct sctp_ipv4addr_param ip4_parm, *p4; phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&ip4_parm, plen); + (struct sctp_paramhdr *)&ip4_parm, min(plen, sizeof(ip4_parm))); if (phdr == NULL) { return (NULL); } @@ -1242,7 +1289,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset, struct sctp_ipv6addr_param ip6_parm, *p6; phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&ip6_parm, plen); + (struct sctp_paramhdr *)&ip6_parm, min(plen, sizeof(ip6_parm))); if (phdr == NULL) { return (NULL); } @@ -1291,8 +1338,7 @@ sctp_findassoc_by_vtag(struct sockaddr *from, uint32_t vtag, SCTP_INP_RLOCK(stcb->sctp_ep); if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { SCTP_INP_RUNLOCK(stcb->sctp_ep); - SCTP_INP_INFO_RUNLOCK(); - return (NULL); + continue; } SCTP_TCB_LOCK(stcb); SCTP_INP_RUNLOCK(stcb->sctp_ep); @@ -1426,12 +1472,6 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset, sa6_embedscope(to6, ip6_use_defzone); } find_tcp_pool = 0; - /* - * FIX FIX?, I think we only need to look in the TCP pool if its an - * INIT or COOKIE-ECHO, We really don't need to find it that way if - * its a INIT-ACK or COOKIE_ACK since these in bot one-2-one and - * one-2-N would be in the main pool anyway. - */ if ((ch->chunk_type != SCTP_INITIATION) && (ch->chunk_type != SCTP_INITIATION_ACK) && (ch->chunk_type != SCTP_COOKIE_ACK) && @@ -1456,7 +1496,7 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset, /* Found a EP but not this address */ if ((ch->chunk_type == SCTP_INITIATION) || (ch->chunk_type == SCTP_INITIATION_ACK)) { - /* + /*- * special hook, we do NOT return linp or an * association that is linked to an existing * association that is under the TCP pool (i.e. no @@ -3584,6 +3624,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* Now the read queue needs to be cleaned up (only once) */ cnt = 0; if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) { + stcb->asoc.state |= SCTP_STATE_ABOUT_TO_BE_FREED; SCTP_INP_READ_LOCK(inp); TAILQ_FOREACH(sq, &inp->read_queue, next) { if (sq->stcb == stcb) { @@ -3627,7 +3668,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre stcb->block_entry = NULL; } } - stcb->asoc.state |= SCTP_STATE_ABOUT_TO_BE_FREED; if ((from_inpcbfree != SCTP_PCBFREE_FORCE) && (stcb->asoc.refcnt)) { /* * reader or writer in the way, we have hopefully given him @@ -4687,6 +4727,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } p4 = (struct sctp_ipv4addr_param *)phdr; sin.sin_addr.s_addr = p4->addr; + if (IN_MULTICAST(sin.sin_addr.s_addr)) { + /* Skip multi-cast addresses */ + goto next_param; + } sa = (struct sockaddr *)&sin; inp = stcb->sctp_ep; atomic_add_int(&stcb->asoc.refcnt, 1); @@ -4749,6 +4793,17 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, p6 = (struct sctp_ipv6addr_param *)phdr; memcpy((caddr_t)&sin6.sin6_addr, p6->addr, sizeof(p6->addr)); + if (IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr)) { + /* Skip multi-cast addresses */ + goto next_param; + } + if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) { + /* + * Link local make no sense without + * scope + */ + goto next_param; + } sa = (struct sockaddr *)&sin6; inp = stcb->sctp_ep; atomic_add_int(&stcb->asoc.refcnt, 1); @@ -4822,7 +4877,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, return (-23); } phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&lstore, plen); + (struct sctp_paramhdr *)&lstore, min(plen, sizeof(lstore))); if (phdr == NULL) { return (-24); } @@ -4865,7 +4920,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, int num_ent, i; phdr = sctp_get_next_param(m, offset, - (struct sctp_paramhdr *)&local_store, plen); + (struct sctp_paramhdr *)&local_store, min(sizeof(local_store), plen)); if (phdr == NULL) { return (-25); } @@ -4913,7 +4968,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } phdr = sctp_get_next_param(m, offset, (struct sctp_paramhdr *)random_store, - plen); + min(sizeof(random_store), plen)); if (phdr == NULL) return (-26); p_random = (struct sctp_auth_random *)phdr; @@ -4939,7 +4994,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } phdr = sctp_get_next_param(m, offset, (struct sctp_paramhdr *)hmacs_store, - plen); + min(plen, sizeof(hmacs_store))); if (phdr == NULL) return (-28); hmacs = (struct sctp_auth_hmac_algo *)phdr; @@ -4970,7 +5025,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } phdr = sctp_get_next_param(m, offset, (struct sctp_paramhdr *)chunks_store, - plen); + min(plen, sizeof(chunks_store))); if (phdr == NULL) return (-30); chunks = (struct sctp_auth_chunk_list *)phdr; diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index e8f1e12..85e5dc6 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -403,11 +403,11 @@ struct sctp_ifa * sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index, uint32_t ifn_type, const char *if_name, - void *ifa, struct sockaddr *addr, uint32_t ifa_flags); + void *ifa, struct sockaddr *addr, uint32_t ifa_flags, int dynamic_add); void sctp_free_ifa(struct sctp_ifa *sctp_ifap); -struct sctp_ifa * +void sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr, uint32_t ifn_index); diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c index 81f3924..35696fd 100644 --- a/sys/netinet/sctp_peeloff.c +++ b/sys/netinet/sctp_peeloff.c @@ -99,7 +99,7 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id) */ sctp_move_pcb_and_assoc(inp, n_inp, stcb); - sctp_pull_off_control_to_new_inp(inp, n_inp, stcb); + sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK); SCTP_TCB_UNLOCK(stcb); return (0); @@ -196,7 +196,7 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error) * And now the final hack. We move data in the pending side i.e. * head to the new socket buffer. Let the GRUBBING begin :-0 */ - sctp_pull_off_control_to_new_inp(inp, n_inp, stcb); + sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK); SCTP_TCB_UNLOCK(stcb); return (newso); diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index b9797a2..8e558cb 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -3331,15 +3331,15 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); - - if (stcb) { + if (stcb != NULL) { if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) { error = EINVAL; } + SCTP_TCB_UNLOCK(stcb); } else { error = EINVAL; } - SCTP_TCB_UNLOCK(stcb); + } break; case SCTP_BINDX_ADD_ADDR: @@ -3651,6 +3651,7 @@ sctp_listen(struct socket *so, int backlog, struct thread *p) error = solisten_proto_check(so); if (error) { SOCK_UNLOCK(so); + SCTP_INP_RUNLOCK(inp); return (error); } if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && @@ -3674,7 +3675,6 @@ sctp_listen(struct socket *so, int backlog, struct thread *p) } /* It appears for 7.0 and on, we must always call this. */ solisten_proto(so, backlog); - if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { /* remove the ACCEPTCONN flag for one-to-many sockets */ so->so_options &= ~SO_ACCEPTCONN; diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 66334b4..0d0c270 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -3846,7 +3846,8 @@ sctp_print_address_pkt(struct ip *iph, struct sctphdr *sh) void sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, - struct sctp_tcb *stcb) + struct sctp_tcb *stcb, + int waitflags) { /* * go through our old INP and pull off any control structures that @@ -3861,11 +3862,8 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, old_so = old_inp->sctp_socket; new_so = new_inp->sctp_socket; TAILQ_INIT(&tmp_queue); - SOCKBUF_LOCK(&(old_so->so_rcv)); - - error = sblock(&old_so->so_rcv, 0); - + error = sblock(&old_so->so_rcv, waitflags); SOCKBUF_UNLOCK(&(old_so->so_rcv)); if (error) { /* @@ -3904,13 +3902,11 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, control = nctl; } SCTP_INP_READ_UNLOCK(old_inp); - /* Remove the sb-lock on the old socket */ SOCKBUF_LOCK(&(old_so->so_rcv)); sbunlock(&old_so->so_rcv); SOCKBUF_UNLOCK(&(old_so->so_rcv)); - /* Now we move them over to the new socket buffer */ control = TAILQ_FIRST(&tmp_queue); SCTP_INP_READ_LOCK(new_inp); @@ -4298,43 +4294,6 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, int holds_loc return (NULL); } -struct sctp_ifa * -sctp_find_ifa_in_ifn(struct sctp_ifn *sctp_ifnp, struct sockaddr *addr, - int holds_lock) -{ - struct sctp_ifa *sctp_ifap; - - if (holds_lock == 0) - SCTP_IPI_ADDR_LOCK(); - - LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) { - if (addr->sa_family != sctp_ifap->address.sa.sa_family) - continue; - if (addr->sa_family == AF_INET) { - if (((struct sockaddr_in *)addr)->sin_addr.s_addr == - sctp_ifap->address.sin.sin_addr.s_addr) { - /* found him. */ - if (holds_lock == 0) - SCTP_IPI_ADDR_UNLOCK(); - return (sctp_ifap); - break; - } - } else if (addr->sa_family == AF_INET6) { - if (SCTP6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)addr)->sin6_addr, - &sctp_ifap->address.sin6.sin6_addr)) { - /* found him. */ - if (holds_lock == 0) - SCTP_IPI_ADDR_UNLOCK(); - return (sctp_ifap); - break; - } - } - } - if (holds_lock == 0) - SCTP_IPI_ADDR_UNLOCK(); - return (NULL); -} - uint32_t sctp_get_ifa_hash_val(struct sockaddr *addr) { @@ -4741,6 +4700,10 @@ restart_nosblocks: } goto out; } + if (hold_sblock == 1) { + SOCKBUF_UNLOCK(&so->so_rcv); + hold_sblock = 0; + } error = sblock(&so->so_rcv, (block_allowed ? M_WAITOK : 0)); /* we possibly have data we can read */ control = TAILQ_FIRST(&inp->read_queue); @@ -4862,9 +4825,6 @@ found_one: * If we reach here, control has a some data for us to read off. * Note that stcb COULD be NULL. */ - if (control->do_not_ref_stcb == 0) { - control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1; - } control->some_taken = 1; if (hold_sblock) { SOCKBUF_UNLOCK(&so->so_rcv); @@ -4901,6 +4861,9 @@ found_one: stcb->freed_by_sorcv_sincelast = 0; } } + if (stcb && control->do_not_ref_stcb == 0) { + stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1; + } /* First lets get off the sinfo and sockaddr info */ if ((sinfo) && filling_sinfo) { memcpy(sinfo, control, sizeof(struct sctp_nonpad_sndrcvinfo)); diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h index e0ae668..3b4acf6 100644 --- a/sys/netinet/sctputil.h +++ b/sys/netinet/sctputil.h @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); * Any new logging added must also define SCTP_STAT_LOGGING if * its not already defined. */ + #if defined(SCTP_LOG_MAXBURST) || defined(SCTP_LOG_RWND) || defined(SCTP_LOG_RWND) #ifndef SCTP_STAT_LOGGING #define SCTP_STAT_LOGGING 1 @@ -86,6 +87,13 @@ __FBSDID("$FreeBSD$"); #endif #endif +#if defined(SCTP_LOG_SACK_ARRIVALS) +#ifndef SCTP_STAT_LOGGING +#define SCTP_STAT_LOGGING 1 +#endif +#endif + + #ifdef SCTP_ASOCLOG_OF_TSNS void sctp_print_out_track_log(struct sctp_tcb *stcb); @@ -112,9 +120,6 @@ sctp_get_ifa_hash_val(struct sockaddr *addr); struct sctp_ifa * sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, int hold_lock); -struct sctp_ifa * -sctp_find_ifa_in_ifn(struct sctp_ifn *sctp_ifnp, struct sockaddr *addr, - int holds_lock); struct sctp_ifa * sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock); @@ -188,7 +193,7 @@ void sctp_ulp_notify(uint32_t, struct sctp_tcb *, uint32_t, void *); void sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp, - struct sctp_tcb *stcb); + struct sctp_tcb *stcb, int waitflags); void sctp_stop_timers_for_shutdown(struct sctp_tcb *); |