- 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)
This commit is contained in:
parent
d562befcdd
commit
d06c82f169
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=169208
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
/* Opps, must decrement the count */
|
||||
sctp_free_ifa(ifap);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
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 (m == NULL) {
|
||||
/* bad, no memory */
|
||||
return (m);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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];
|
||||
|
@ -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 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
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 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
|
||||
|
||||
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);
|
||||
|
@ -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 *);
|
||||
|
||||
|
@ -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 @@ sctp_handle_stream_reset(struct sctp_tcb *stcb, struct sctp_stream_reset_out_req
|
||||
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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
* 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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
* 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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
}
|
||||
#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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
}
|
||||
#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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
#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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
}
|
||||
#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 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
|
||||
/* 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 @@ sctp_input(i_pak, off)
|
||||
if (m) {
|
||||
sctp_m_freem(m);
|
||||
}
|
||||
/* For BSD/MAC this does nothing */
|
||||
SCTP_RELEASE_PAK(i_pak);
|
||||
return;
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
*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) {
|
||||
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 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;
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 @@ sctp_sorecvmsg(struct socket *so,
|
||||
}
|
||||
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 @@ sctp_sorecvmsg(struct socket *so,
|
||||
* 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 @@ sctp_sorecvmsg(struct socket *so,
|
||||
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));
|
||||
|
@ -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 *);
|
||||
|
@ -240,6 +240,8 @@ sctp6_input(i_pak, offp, proto)
|
||||
}
|
||||
if (m)
|
||||
m_freem(m);
|
||||
/* For BSD/MAC this does nothing */
|
||||
SCTP_RELEASE_PAK(*i_pak);
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user