summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_indata.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-05-08 00:21:05 +0000
committerrrs <rrs@FreeBSD.org>2007-05-08 00:21:05 +0000
commit532412f6c49a9077f90f5cd40b66c87a16efe085 (patch)
tree4db56edaf6063ffdff843e7c1228529525ec2e80 /sys/netinet/sctp_indata.c
parentcaa15fdaeb248ba5c8dd136083da6989cacd1979 (diff)
downloadFreeBSD-src-532412f6c49a9077f90f5cd40b66c87a16efe085.zip
FreeBSD-src-532412f6c49a9077f90f5cd40b66c87a16efe085.tar.gz
- More macros for OS compatabilty
- PR-SCTP would ignore FWD-TSN's above a rwnd's worth of TSN's (1 byte msgs).. this left the peer hopelessly out of sync.. or an attacker. So now we abort the assoc. - New IFN hash, also rename hashes to match addr/ifn now that the vrf has multiple. - Do not enable SCTP_PCB_FLAGS_RECVDATAIOEVNT per default as defined in the Socket API ID. - Export MTU information via sysctl. - Vrf's need table id's. This is default for BSD, but may be other things later when BSD fully supports VRFs. - Additional stream reset bug (caught by cisco dev-test). - Additional validations for the address in sending a message (socket api). -------- and ----- - Fix association notifications not to give the active open side false notifications. - Fix so sendfile and SENDALL will work properly (missing flag to say socket sender is done). - Fix Bug that prevented COOKIES from being retransmitted. - Break out connectx into helper sub-models so that iox routines can reuse the helpers. - When an address is added during system init (non-dynamic mode) make sure that the "defer use" flag is not set. ** its compiling on XR now :-D ** Reviewed by: gnn
Diffstat (limited to 'sys/netinet/sctp_indata.c')
-rw-r--r--sys/netinet/sctp_indata.c182
1 files changed, 126 insertions, 56 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index bf5727a..3f30220 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -207,6 +207,7 @@ sctp_build_readq_entry(struct sctp_tcb *stcb,
read_queue_e->data = dm;
read_queue_e->spec_flags = 0;
read_queue_e->tail_mbuf = NULL;
+ read_queue_e->aux_data = NULL;
read_queue_e->stcb = stcb;
read_queue_e->port_from = stcb->rport;
read_queue_e->do_not_ref_stcb = 0;
@@ -241,6 +242,7 @@ sctp_build_readq_entry_chk(struct sctp_tcb *stcb,
read_queue_e->sinfo_cumtsn = chk->rec.data.TSN_seq;
read_queue_e->sinfo_assoc_id = sctp_get_associd(stcb);
read_queue_e->whoFrom = chk->whoTo;
+ read_queue_e->aux_data = NULL;
read_queue_e->length = 0;
atomic_add_int(&chk->whoTo->ref_count, 1);
read_queue_e->data = chk->data;
@@ -304,6 +306,50 @@ sctp_build_ctl_nchunk(struct sctp_inpcb *inp,
}
+char *
+sctp_build_ctl_cchunk(struct sctp_inpcb *inp,
+ int *control_len,
+ struct sctp_sndrcvinfo *sinfo)
+{
+ struct sctp_sndrcvinfo *outinfo;
+ struct cmsghdr *cmh;
+ char *buf;
+ int len;
+ int use_extended = 0;
+
+ if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
+ /* user does not want the sndrcv ctl */
+ return (NULL);
+ }
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
+ use_extended = 1;
+ len = CMSG_LEN(sizeof(struct sctp_extrcvinfo));
+ } else {
+ len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ }
+ SCTP_MALLOC(buf, char *, len, "SCTP_CMSG");
+ if (buf == NULL) {
+ /* No space */
+ return (buf);
+ }
+ /* We need a CMSG header followed by the struct */
+ cmh = (struct cmsghdr *)buf;
+ outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh);
+ cmh->cmsg_level = IPPROTO_SCTP;
+ if (use_extended) {
+ cmh->cmsg_type = SCTP_EXTRCV;
+ cmh->cmsg_len = len;
+ memcpy(outinfo, sinfo, len);
+ } else {
+ cmh->cmsg_type = SCTP_SNDRCV;
+ cmh->cmsg_len = len;
+ *outinfo = *sinfo;
+ }
+ *control_len = len;
+ return (buf);
+}
+
+
/*
* We are delivering currently from the reassembly queue. We must continue to
* deliver until we either: 1) run out of space. 2) run out of sequential
@@ -1453,6 +1499,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
int ordered;
uint32_t protocol_id;
uint8_t chunk_flags;
+ struct sctp_stream_reset_list *liste;
chk = NULL;
tsn = ntohl(ch->dp.tsn);
@@ -2106,6 +2153,57 @@ finish_express_del:
asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE);
#endif
SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
+ /* check the special flag for stream resets */
+ if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
+ ((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
+ * time to reset streams. 1: call reset function. 2: free
+ * pending_reply space 3: distribute any chunks in
+ * pending_reply_queue.
+ */
+ struct sctp_queued_to_read *ctl;
+
+ sctp_reset_in_stream(stcb, liste->number_entries, liste->req.list_of_streams);
+ TAILQ_REMOVE(&asoc->resetHead, liste, next_resp);
+ SCTP_FREE(liste);
+ liste = TAILQ_FIRST(&asoc->resetHead);
+ ctl = TAILQ_FIRST(&asoc->pending_reply_queue);
+ if (ctl && (liste == NULL)) {
+ /* All can be removed */
+ while (ctl) {
+ TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
+ sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag);
+ if (*abort_flag) {
+ return (0);
+ }
+ ctl = TAILQ_FIRST(&asoc->pending_reply_queue);
+ }
+ } else if (ctl) {
+ /* more than one in queue */
+ 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
+ * ctl->sinfo_tsn > liste->tsn
+ */
+ TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
+ sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag);
+ if (*abort_flag) {
+ return (0);
+ }
+ ctl = TAILQ_FIRST(&asoc->pending_reply_queue);
+ }
+ }
+ /*
+ * Now service re-assembly to pick up anything that has been
+ * held on reassembly queue?
+ */
+ sctp_deliver_reasm_check(stcb, asoc);
+ need_reasm_check = 0;
+ }
if (need_reasm_check) {
/* Another one waits ? */
sctp_deliver_reasm_check(stcb, asoc);
@@ -2166,7 +2264,6 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
unsigned char aux_array[64];
#endif
- struct sctp_stream_reset_list *liste;
asoc = &stcb->asoc;
at = 0;
@@ -2301,56 +2398,6 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
#endif
}
}
- /* check the special flag for stream resets */
- if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
- ((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
- * time to reset streams. 1: call reset function. 2: free
- * pending_reply space 3: distribute any chunks in
- * pending_reply_queue.
- */
- struct sctp_queued_to_read *ctl;
-
- sctp_reset_in_stream(stcb, liste->number_entries, liste->req.list_of_streams);
- TAILQ_REMOVE(&asoc->resetHead, liste, next_resp);
- SCTP_FREE(liste);
- liste = TAILQ_FIRST(&asoc->resetHead);
- ctl = TAILQ_FIRST(&asoc->pending_reply_queue);
- if (ctl && (liste == NULL)) {
- /* All can be removed */
- while (ctl) {
- TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
- sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag);
- if (*abort_flag) {
- return;
- }
- ctl = TAILQ_FIRST(&asoc->pending_reply_queue);
- }
- } else if (ctl) {
- /* more than one in queue */
- 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
- * ctl->sinfo_tsn > liste->tsn
- */
- TAILQ_REMOVE(&asoc->pending_reply_queue, ctl, next);
- sctp_queue_data_to_stream(stcb, asoc, ctl, abort_flag);
- if (*abort_flag) {
- return;
- }
- ctl = TAILQ_FIRST(&asoc->pending_reply_queue);
- }
- }
- /*
- * Now service re-assembly to pick up anything that has been
- * held on reassembly queue?
- */
- sctp_deliver_reasm_check(stcb, asoc);
- }
/*
* Now we need to see if we need to queue a sack or just start the
* timer (if allowed).
@@ -2609,7 +2656,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_19;
sctp_abort_association(inp, stcb, m, iphlen, sh,
- op_err);
+ op_err, 0, 0);
return (2);
}
#ifdef SCTP_AUDITING_ENABLED
@@ -2672,7 +2719,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
struct mbuf *op_err;
op_err = sctp_generate_invmanparam(SCTP_CAUSE_PROTOCOL_VIOLATION);
- sctp_abort_association(inp, stcb, m, iphlen, sh, op_err);
+ sctp_abort_association(inp, stcb, m, iphlen, sh, op_err, 0, 0);
return (2);
}
break;
@@ -5713,14 +5760,37 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
gap = new_cum_tsn + (MAX_TSN - asoc->mapping_array_base_tsn) + 1;
}
- if (gap > m_size || gap < 0) {
+ if (gap > m_size) {
asoc->highest_tsn_inside_map = back_out_htsn;
if ((long)gap > sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv)) {
+ struct mbuf *oper;
+
/*
* out of range (of single byte chunks in the rwnd I
- * give out) too questionable. better to drop it
- * silently
+ * give out). This must be an attacker.
*/
+ *abort_flag = 1;
+ oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + 3 * sizeof(uint32_t)),
+ 0, M_DONTWAIT, 1, MT_DATA);
+ if (oper) {
+ struct sctp_paramhdr *ph;
+ uint32_t *ippp;
+
+ SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr) +
+ (sizeof(uint32_t) * 3);
+ ph = mtod(oper, struct sctp_paramhdr *);
+ ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
+ ph->param_length = htons(SCTP_BUF_LEN(oper));
+ ippp = (uint32_t *) (ph + 1);
+ *ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_33);
+ ippp++;
+ *ippp = asoc->highest_tsn_inside_map;
+ ippp++;
+ *ippp = new_cum_tsn;
+ }
+ stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_33;
+ sctp_abort_an_association(stcb->sctp_ep, stcb,
+ SCTP_PEER_FAULTY, oper);
return;
}
if (asoc->highest_tsn_inside_map >
OpenPOWER on IntegriCloud