summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/sctp.h2
-rw-r--r--sys/netinet/sctp_asconf.c2
-rw-r--r--sys/netinet/sctp_constants.h2
-rw-r--r--sys/netinet/sctp_indata.c182
-rw-r--r--sys/netinet/sctp_indata.h6
-rw-r--r--sys/netinet/sctp_input.c174
-rw-r--r--sys/netinet/sctp_input.h10
-rw-r--r--sys/netinet/sctp_os_bsd.h110
-rw-r--r--sys/netinet/sctp_output.c465
-rw-r--r--sys/netinet/sctp_output.h14
-rw-r--r--sys/netinet/sctp_pcb.c239
-rw-r--r--sys/netinet/sctp_pcb.h28
-rw-r--r--sys/netinet/sctp_structs.h19
-rw-r--r--sys/netinet/sctp_sysctl.c3
-rw-r--r--sys/netinet/sctp_timer.c65
-rw-r--r--sys/netinet/sctp_uio.h23
-rw-r--r--sys/netinet/sctp_usrreq.c92
-rw-r--r--sys/netinet/sctp_var.h3
-rw-r--r--sys/netinet/sctputil.c469
-rw-r--r--sys/netinet/sctputil.h26
-rw-r--r--sys/netinet6/sctp6_usrreq.c43
21 files changed, 1250 insertions, 727 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h
index c89d1c8..b9289c1 100644
--- a/sys/netinet/sctp.h
+++ b/sys/netinet/sctp.h
@@ -429,6 +429,8 @@ struct sctp_error_unrecognized_chunk {
#define SCTP_PCB_FLAGS_INTERLEAVE_STRMS 0x00000010
#define SCTP_PCB_FLAGS_DO_ASCONF 0x00000020
#define SCTP_PCB_FLAGS_AUTO_ASCONF 0x00000040
+#define SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE 0x00000080
+
/* socket options */
#define SCTP_PCB_FLAGS_NODELAY 0x00000100
#define SCTP_PCB_FLAGS_AUTOCLOSE 0x00000200
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index 5eaa7cd..a5a304e 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -1917,7 +1917,7 @@ sctp_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
struct sctp_nets *net;
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- struct rtentry *rt;
+ sctp_rtentry_t *rt;
/* delete this address if cached */
if (net->ro._s_addr &&
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index 3922222..ba4e4b0 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -727,6 +727,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_INITIAL_CWND 4380
+#define SCTP_DEFAULT_MTU 1500 /* emegency default MTU */
/* amount peer is obligated to have in rwnd or I will abort */
#define SCTP_MIN_RWND 1500
@@ -843,6 +844,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_LOC_30 0x0000001e
#define SCTP_LOC_31 0x0000001f
#define SCTP_LOC_32 0x00000020
+#define SCTP_LOC_33 0x00000021
/* Free assoc codes */
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 >
diff --git a/sys/netinet/sctp_indata.h b/sys/netinet/sctp_indata.h
index 70ba477..ad04c56 100644
--- a/sys/netinet/sctp_indata.h
+++ b/sys/netinet/sctp_indata.h
@@ -64,6 +64,7 @@ sctp_build_readq_entry(struct sctp_tcb *stcb,
(_ctl)->whoFrom = net; \
(_ctl)->data = dm; \
(_ctl)->tail_mbuf = NULL; \
+ (_ctl)->aux_data = NULL; \
(_ctl)->stcb = (in_it); \
(_ctl)->port_from = (in_it)->rport; \
(_ctl)->spec_flags = 0; \
@@ -80,6 +81,11 @@ struct mbuf *
sctp_build_ctl_nchunk(struct sctp_inpcb *inp,
struct sctp_sndrcvinfo *sinfo);
+char *
+sctp_build_ctl_cchunk(struct sctp_inpcb *inp,
+ int *control_len,
+ struct sctp_sndrcvinfo *sinfo);
+
void sctp_set_rwnd(struct sctp_tcb *, struct sctp_association *);
uint32_t
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index eae7b79..97ca903 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -78,7 +78,8 @@ sctp_stop_all_cookie_timers(struct sctp_tcb *stcb)
static void
sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
struct sctp_init_chunk *cp, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- struct sctp_nets *net, int *abort_no_unlock)
+ struct sctp_nets *net, int *abort_no_unlock, uint32_t vrf_id,
+ uint32_t table_id)
{
struct sctp_init *init;
struct mbuf *op_err;
@@ -102,7 +103,8 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
* FIX ME ?? What about TCP model and we have a
* match/restart case?
*/
- sctp_abort_association(inp, stcb, m, iphlen, sh, op_err);
+ sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
+ vrf_id, table_id);
if (stcb)
*abort_no_unlock = 1;
return;
@@ -110,7 +112,8 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_init_chunk)) {
/* Invalid length */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
- sctp_abort_association(inp, stcb, m, iphlen, sh, op_err);
+ sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
+ vrf_id, table_id);
if (stcb)
*abort_no_unlock = 1;
return;
@@ -119,7 +122,8 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
if (init->initiate_tag == 0) {
/* protocol error... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
- sctp_abort_association(inp, stcb, m, iphlen, sh, op_err);
+ sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
+ vrf_id, table_id);
if (stcb)
*abort_no_unlock = 1;
return;
@@ -127,13 +131,15 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
if (ntohl(init->a_rwnd) < SCTP_MIN_RWND) {
/* invalid parameter... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
- sctp_abort_association(inp, stcb, m, iphlen, sh, op_err);
+ sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
+ vrf_id, table_id);
return;
}
if (init->num_inbound_streams == 0) {
/* protocol error... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
- sctp_abort_association(inp, stcb, m, iphlen, sh, op_err);
+ sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
+ vrf_id, table_id);
if (stcb)
*abort_no_unlock = 1;
return;
@@ -141,7 +147,8 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
if (init->num_outbound_streams == 0) {
/* protocol error... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
- sctp_abort_association(inp, stcb, m, iphlen, sh, op_err);
+ sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
+ vrf_id, table_id);
if (stcb)
*abort_no_unlock = 1;
return;
@@ -150,7 +157,8 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
if (sctp_validate_init_auth_params(m, offset + sizeof(*cp),
init_limit)) {
/* auth parameter(s) error... send abort */
- sctp_abort_association(inp, stcb, m, iphlen, sh, NULL);
+ sctp_abort_association(inp, stcb, m, iphlen, sh, NULL, vrf_id,
+ table_id);
if (stcb)
*abort_no_unlock = 1;
return;
@@ -161,7 +169,8 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
printf("sctp_handle_init: sending INIT-ACK\n");
}
#endif
- sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, sh, cp);
+ sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, sh, cp, vrf_id,
+ table_id);
}
/*
@@ -307,7 +316,8 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb,
static int
sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
struct sctphdr *sh, struct sctp_init_ack_chunk *cp, struct sctp_tcb *stcb,
- struct sctp_nets *net, int *abort_no_unlock)
+ struct sctp_nets *net, int *abort_no_unlock, uint32_t vrf_id,
+ uint32_t table_id)
{
struct sctp_association *asoc;
struct mbuf *op_err;
@@ -324,7 +334,9 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
if (abort_flag) {
/* Send an abort and notify peer */
if (op_err != NULL) {
- sctp_send_operr_to(m, iphlen, op_err, cp->init.initiate_tag);
+ sctp_send_operr_to(m, iphlen, op_err,
+ cp->init.initiate_tag, vrf_id,
+ table_id);
} else {
/*
* Just notify (abort_assoc does this if we send an
@@ -358,7 +370,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
}
#endif
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
- NULL);
+ NULL, 0, 0);
*abort_no_unlock = 1;
return (-1);
}
@@ -417,7 +429,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
mp->resv = 0;
}
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
- sh, op_err);
+ sh, op_err, 0, 0);
*abort_no_unlock = 1;
}
return (retval);
@@ -920,9 +932,10 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
}
static int
-sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
- struct sctp_init_ack_chunk *cp, struct sctp_tcb *stcb,
- struct sctp_nets *net, int *abort_no_unlock)
+sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
+ struct sctphdr *sh, struct sctp_init_ack_chunk *cp, struct sctp_tcb *stcb,
+ struct sctp_nets *net, int *abort_no_unlock, uint32_t vrf_id,
+ uint32_t table_id)
{
struct sctp_init_ack *init_ack;
int *state;
@@ -945,7 +958,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* Invalid length */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
- op_err);
+ op_err, 0, 0);
*abort_no_unlock = 1;
return (-1);
}
@@ -955,7 +968,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* protocol error... send an abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
- op_err);
+ op_err, 0, 0);
*abort_no_unlock = 1;
return (-1);
}
@@ -963,7 +976,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* protocol error... send an abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
- op_err);
+ op_err, 0, 0);
*abort_no_unlock = 1;
return (-1);
}
@@ -971,7 +984,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* protocol error... send an abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
- op_err);
+ op_err, 0, 0);
*abort_no_unlock = 1;
return (-1);
}
@@ -979,7 +992,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* protocol error... send an abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
- op_err);
+ op_err, 0, 0);
*abort_no_unlock = 1;
return (-1);
}
@@ -1002,8 +1015,9 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED,
stcb, 0, (void *)stcb->asoc.primary_destination);
}
- if (sctp_process_init_ack(m, iphlen, offset, sh, cp, stcb, net,
- abort_no_unlock) < 0) {
+ if (sctp_process_init_ack(m, iphlen, offset, sh, cp, stcb,
+ net, abort_no_unlock, vrf_id,
+ table_id) < 0) {
/* error in parsing parameters */
return (-1);
}
@@ -1069,7 +1083,8 @@ static struct sctp_tcb *
sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len,
struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net,
- struct sockaddr *init_src, int *notification, sctp_assoc_t * sac_assoc_id)
+ struct sockaddr *init_src, int *notification, sctp_assoc_t * sac_assoc_id,
+ uint32_t vrf_id, uint32_t table_id)
{
struct sctp_association *asoc;
struct sctp_init_chunk *init_cp, init_buf;
@@ -1110,7 +1125,8 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
ph = mtod(op_err, struct sctp_paramhdr *);
ph->param_type = htons(SCTP_CAUSE_COOKIE_IN_SHUTDOWN);
ph->param_length = htons(sizeof(struct sctp_paramhdr));
- sctp_send_operr_to(m, iphlen, op_err, cookie->peers_vtag);
+ sctp_send_operr_to(m, iphlen, op_err, cookie->peers_vtag,
+ vrf_id, table_id);
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 2;
return (NULL);
@@ -1168,7 +1184,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
case SCTP_STATE_COOKIE_WAIT:
case SCTP_STATE_COOKIE_ECHOED:
/*
- * INIT was sent, but got got a COOKIE_ECHO with the
+ * INIT was sent but got a COOKIE_ECHO with the
* correct tags... just accept it...but we must
* process the init so that we can make sure we have
* the right seq no's.
@@ -1233,7 +1249,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
* we're in the OPEN state (or beyond), so peer must
* have simply lost the COOKIE-ACK
*/
-
break;
} /* end switch */
sctp_stop_all_cookie_timers(stcb);
@@ -1255,7 +1270,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 5;
return (stcb);
- } /* end if */
+ }
if (ntohl(initack_cp->init.initiate_tag) != asoc->my_vtag &&
ntohl(init_cp->init.initiate_tag) == asoc->peer_vtag &&
cookie->tie_tag_my_vtag == 0 &&
@@ -1543,7 +1558,8 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
struct sctphdr *sh, struct sctp_state_cookie *cookie, int cookie_len,
struct sctp_inpcb *inp, struct sctp_nets **netp,
struct sockaddr *init_src, int *notification,
- int auth_skipped, uint32_t auth_offset, uint32_t auth_len)
+ int auth_skipped, uint32_t auth_offset, uint32_t auth_len,
+ uint32_t vrf_id, uint32_t table_id)
{
struct sctp_tcb *stcb;
struct sctp_init_chunk *init_cp, init_buf;
@@ -1553,7 +1569,6 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
struct sctp_association *asoc;
- uint32_t vrf_id;
int chk_length;
int init_offset, initack_offset, initack_limit;
int retval;
@@ -1561,8 +1576,6 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
uint32_t old_tag;
uint8_t auth_chunk_buf[SCTP_PARAM_BUFFER_SIZE];
- vrf_id = inp->def_vrf_id;
-
/*
* find and validate the INIT chunk in the cookie (peer's info) the
* INIT should start after the cookie-echo header struct (chunk
@@ -1633,15 +1646,17 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
printf("process_cookie_new: no room for another TCB!\n");
}
-#endif /* SCTP_DEBUG */
+#endif
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
- sh, op_err);
+ sh, op_err, vrf_id, table_id);
return (NULL);
}
/* get the correct sctp_nets */
*netp = sctp_findnet(stcb, init_src);
asoc = &stcb->asoc;
+ /* save the table id (vrf_id is done in aloc_assoc) */
+ asoc->table_id = table_id;
/* get scope variables out of cookie */
asoc->ipv4_local_scope = cookie->ipv4_scope;
asoc->site_scope = cookie->site_scope;
@@ -1659,7 +1674,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
*/
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
- sh, op_err);
+ sh, op_err, vrf_id, table_id);
return (NULL);
}
/* process the INIT-ACK info (my info) */
@@ -1817,7 +1832,8 @@ static struct mbuf *
sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
struct sctphdr *sh, struct sctp_cookie_echo_chunk *cp,
struct sctp_inpcb **inp_p, struct sctp_tcb **stcb, struct sctp_nets **netp,
- int auth_skipped, uint32_t auth_offset, uint32_t auth_len, struct sctp_tcb **locked_tcb)
+ int auth_skipped, uint32_t auth_offset, uint32_t auth_len,
+ struct sctp_tcb **locked_tcb, uint32_t vrf_id, uint32_t table_id)
{
struct sctp_state_cookie *cookie;
struct sockaddr_in6 sin6;
@@ -1892,7 +1908,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
* invalid ports or bad tag. Note that we always leave the
* v_tag in the header in network order and when we stored
* it in the my_vtag slot we also left it in network order.
- * This maintians the match even though it may be in the
+ * This maintains the match even though it may be in the
* opposite byte order of the machine :->
*/
return (NULL);
@@ -2029,7 +2045,8 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
if (tim == 0)
tim = now.tv_usec - cookie->time_entered.tv_usec;
scm->time_usec = htonl(tim);
- sctp_send_operr_to(m, iphlen, op_err, cookie->peers_vtag);
+ sctp_send_operr_to(m, iphlen, op_err, cookie->peers_vtag,
+ vrf_id, table_id);
return (NULL);
}
/*
@@ -2103,13 +2120,13 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
/* this is the "normal" case... get a new TCB */
*stcb = sctp_process_cookie_new(m, iphlen, offset, sh, cookie,
cookie_len, *inp_p, netp, to, &notification,
- auth_skipped, auth_offset, auth_len);
+ auth_skipped, auth_offset, auth_len, vrf_id, table_id);
} else {
/* this is abnormal... cookie-echo on existing TCB */
had_a_existing_tcb = 1;
*stcb = sctp_process_cookie_existing(m, iphlen, offset, sh,
cookie, cookie_len, *inp_p, *stcb, *netp, to, &notification,
- &sac_restart_id);
+ &sac_restart_id, vrf_id, table_id);
}
if (*stcb == NULL) {
@@ -2188,7 +2205,8 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
#endif /* SCTP_DEBUG */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(*inp_p, NULL, m, iphlen,
- sh, op_err);
+ sh, op_err, vrf_id,
+ table_id);
sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_20);
return (NULL);
}
@@ -3527,7 +3545,8 @@ sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp,
static struct sctp_tcb *
sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
struct sctphdr *sh, struct sctp_chunkhdr *ch, struct sctp_inpcb *inp,
- struct sctp_tcb *stcb, struct sctp_nets **netp, int *fwd_tsn_seen)
+ struct sctp_tcb *stcb, struct sctp_nets **netp, int *fwd_tsn_seen,
+ uint32_t vrf_id, uint32_t table_id)
{
struct sctp_association *asoc;
uint32_t vtag_in;
@@ -3639,7 +3658,8 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
if (stcb == NULL) {
/* no association, so it's out of the blue... */
- sctp_handle_ootb(m, iphlen, *offset, sh, inp, NULL);
+ sctp_handle_ootb(m, iphlen, *offset, sh, inp, NULL,
+ vrf_id, table_id);
*offset = length;
if (locked_tcb)
SCTP_TCB_UNLOCK(locked_tcb);
@@ -3673,7 +3693,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
if (locked_tcb)
SCTP_TCB_UNLOCK(locked_tcb);
sctp_handle_ootb(m, iphlen, *offset, sh, inp,
- NULL);
+ NULL, vrf_id, table_id);
return (NULL);
}
} else {
@@ -3705,7 +3725,6 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
*netp);
}
process_control_chunks:
-
while (IS_SCTP_CONTROL(ch)) {
/* validate chunk length */
chk_length = ntohs(ch->chunk_length);
@@ -3761,7 +3780,6 @@ process_control_chunks:
/* We can fit it all */
goto all_fits;
}
-
} else {
/* get a complete chunk... */
if ((size_t)chk_length > sizeof(chunk_buf)) {
@@ -3865,7 +3883,7 @@ process_control_chunks:
return (NULL);
}
sctp_handle_init(m, iphlen, *offset, sh,
- (struct sctp_init_chunk *)ch, inp, stcb, *netp, &abort_no_unlock);
+ (struct sctp_init_chunk *)ch, inp, stcb, *netp, &abort_no_unlock, vrf_id, table_id);
if (abort_no_unlock)
return (NULL);
@@ -3903,7 +3921,7 @@ process_control_chunks:
return (NULL);
}
ret = sctp_handle_init_ack(m, iphlen, *offset, sh,
- (struct sctp_init_ack_chunk *)ch, stcb, *netp, &abort_no_unlock);
+ (struct sctp_init_ack_chunk *)ch, stcb, *netp, &abort_no_unlock, vrf_id, table_id);
/*
* Special case, I must call the output routine to
* get the cookie echoed
@@ -3938,9 +3956,10 @@ process_control_chunks:
printf("Bad size on sack chunk .. to small\n");
}
#endif
- if (locked_tcb)
- SCTP_TCB_UNLOCK(locked_tcb);
*offset = length;
+ if (locked_tcb)
+ SCTP_TCB_UNLOCK(locked_tcb);
+
return (NULL);
}
sack = (struct sctp_sack_chunk *)ch;
@@ -3972,8 +3991,6 @@ process_control_chunks:
}
if (abort_now) {
/* ABORT signal from sack processing */
- if (locked_tcb)
- SCTP_TCB_UNLOCK(locked_tcb);
*offset = length;
return (NULL);
}
@@ -4000,9 +4017,9 @@ process_control_chunks:
#endif /* SCTP_DEBUG */
if (chk_length != sizeof(struct sctp_heartbeat_chunk)) {
/* Its not ours */
+ *offset = length;
if (locked_tcb)
SCTP_TCB_UNLOCK(locked_tcb);
- *offset = length;
return (NULL);
}
/* He's alive so give him credit */
@@ -4099,8 +4116,9 @@ process_control_chunks:
*/
goto process_cookie_anyway;
}
- sctp_abort_association(inp, stcb, m, iphlen, sh,
- NULL);
+ sctp_abort_association(inp, stcb, m, iphlen,
+ sh, NULL, vrf_id,
+ table_id);
*offset = length;
return (NULL);
} else if (inp->sctp_socket->so_qlimit) {
@@ -4126,7 +4144,7 @@ process_control_chunks:
htons(sizeof(struct sctp_paramhdr));
}
sctp_abort_association(inp, stcb, m,
- iphlen, sh, oper);
+ iphlen, sh, oper, vrf_id, table_id);
}
*offset = length;
return (NULL);
@@ -4152,7 +4170,9 @@ process_control_chunks:
auth_skipped,
auth_offset,
auth_len,
- &locked_tcb);
+ &locked_tcb,
+ vrf_id,
+ table_id);
if (linp)
SCTP_ASOC_CREATE_UNLOCK(linp);
if (ret_buf == NULL) {
@@ -4195,7 +4215,11 @@ process_control_chunks:
printf("SCTP_COOKIE-ACK\n");
}
#endif /* SCTP_DEBUG */
-
+ if (chk_length != sizeof(struct sctp_cookie_ack_chunk)) {
+ if (locked_tcb)
+ SCTP_TCB_UNLOCK(locked_tcb);
+ return (NULL);
+ }
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */
if ((stcb) && (stcb->asoc.total_output_queue_size)) {
@@ -4564,7 +4588,7 @@ int
sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
int length, struct sctphdr *sh, struct sctp_chunkhdr *ch,
struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net,
- uint8_t ecn_bits)
+ uint8_t ecn_bits, uint32_t vrf_id, uint32_t table_id)
{
/*
* Control chunk processing
@@ -4596,7 +4620,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
if (IS_SCTP_CONTROL(ch)) {
/* process the control portion of the SCTP packet */
stcb = sctp_process_control(m, iphlen, &offset, length, sh, ch,
- inp, stcb, &net, &fwd_tsn_seen);
+ inp, stcb, &net, &fwd_tsn_seen, vrf_id, table_id);
if (stcb) {
/*
* This covers us if the cookie-echo was there and
@@ -4625,7 +4649,8 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
}
if (stcb == NULL) {
/* out of the blue DATA chunk */
- sctp_handle_ootb(m, iphlen, offset, sh, inp, NULL);
+ sctp_handle_ootb(m, iphlen, offset, sh, inp, NULL,
+ vrf_id, table_id);
return (1);
}
if (stcb->asoc.my_vtag != ntohl(sh->v_tag)) {
@@ -4687,7 +4712,8 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
/*
* We consider OOTB any data sent during asoc setup.
*/
- sctp_handle_ootb(m, iphlen, offset, sh, inp, NULL);
+ sctp_handle_ootb(m, iphlen, offset, sh, inp, NULL,
+ vrf_id, table_id);
SCTP_TCB_UNLOCK(stcb);
return (1);
break;
@@ -4800,7 +4826,7 @@ sctp_input(i_pak, off)
#endif
struct mbuf *m;
int iphlen;
- uint32_t vrf_id;
+ uint32_t vrf_id = 0, table_id = 0;
uint8_t ecn_bits;
struct ip *ip;
struct sctphdr *sh;
@@ -4813,7 +4839,15 @@ sctp_input(i_pak, off)
int refcount_up = 0;
int length, mlen, offset;
- vrf_id = SCTP_DEFAULT_VRFID;
+
+ if (SCTP_GET_PKT_VRFID(i_pak, vrf_id)) {
+ SCTP_RELEASE_PKT(i_pak);
+ return;
+ }
+ if (SCTP_GET_PKT_TABLEID(i_pak, table_id)) {
+ SCTP_RELEASE_PKT(i_pak);
+ return;
+ }
mlen = SCTP_HEADER_LEN(i_pak);
iphlen = off;
m = SCTP_HEADER_TO_CHAIN(i_pak);
@@ -4948,14 +4982,16 @@ sctp_skip_csum_4:
sh->v_tag = init_chk->init.initiate_tag;
}
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
- sctp_send_shutdown_complete2(m, iphlen, sh);
+ sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id,
+ table_id);
goto bad;
}
if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) {
goto bad;
}
if (ch->chunk_type != SCTP_ABORT_ASSOCIATION)
- sctp_send_abort(m, iphlen, sh, 0, NULL);
+ sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id,
+ table_id);
goto bad;
} else if (stcb == NULL) {
refcount_up = 1;
@@ -4982,7 +5018,8 @@ sctp_skip_csum_4:
ecn_bits = ip->ip_tos;
sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
- inp, stcb, net, ecn_bits);
+ inp, stcb, net, ecn_bits, vrf_id,
+ table_id);
/* inp's ref-count reduced && stcb unlocked */
if (m) {
sctp_m_freem(m);
@@ -5008,6 +5045,7 @@ bad:
sctp_m_freem(m);
}
/* For BSD/MAC this does nothing */
- SCTP_RELEASE_PAK(i_pak);
+ SCTP_DETACH_HEADER_FROM_CHAIN(i_pak);
+ SCTP_RELEASE_HEADER(i_pak);
return;
}
diff --git a/sys/netinet/sctp_input.h b/sys/netinet/sctp_input.h
index c34b8cc..047cab4 100644
--- a/sys/netinet/sctp_input.h
+++ b/sys/netinet/sctp_input.h
@@ -40,14 +40,16 @@ __FBSDID("$FreeBSD$");
int
sctp_common_input_processing(struct mbuf **, int, int, int,
struct sctphdr *, struct sctp_chunkhdr *, struct sctp_inpcb *,
- struct sctp_tcb *, struct sctp_nets *, uint8_t);
+ struct sctp_tcb *, struct sctp_nets *, uint8_t, uint32_t, uint32_t);
struct sctp_stream_reset_out_request *
- sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chunk **bchk);
+sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq,
+ struct sctp_tmit_chunk **bchk);
-void
- sctp_reset_in_stream(struct sctp_tcb *stcb, int number_entries, uint16_t * list);
+void
+sctp_reset_in_stream(struct sctp_tcb *stcb, int number_entries,
+ uint16_t * list);
#endif
diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h
index b01287e..a2d4bf3 100644
--- a/sys/netinet/sctp_os_bsd.h
+++ b/sys/netinet/sctp_os_bsd.h
@@ -107,15 +107,41 @@ __FBSDID("$FreeBSD$");
#define USER_ADDR_NULL (NULL) /* FIX ME: temp */
#define SCTP_LIST_EMPTY(list) LIST_EMPTY(list)
+#if defined(SCTP_DEBUG)
+#define SCTPDBG(level, params...) \
+{ \
+ do { \
+ if (sctp_debug_on & level ) { \
+ printf(params); \
+ } \
+ } while (0); \
+}
+#define SCTPDBG_ADDR(level, addr) \
+{ \
+ do { \
+ if (sctp_debug_on & level ) { \
+ sctp_print_address(addr); \
+ } \
+ } while (0); \
+}
+#define SCTP_PRINTF(params...) printf(params)
+#else
+#define SCTPDBG(level, params...)
+#define SCTPDBG_ADDR(level, addr)
+#define SCTP_PRINTF(params...)
+#endif
+
/*
* Local address and interface list handling
*/
-#define SCTP_MAX_VRF_ID 0
-#define SCTP_SIZE_OF_VRF_HASH 3
-#define SCTP_IFNAMSIZ IFNAMSIZ
-#define SCTP_DEFAULT_VRFID 0
-#define SCTP_VRF_HASH_SIZE 16
-
+#define SCTP_MAX_VRF_ID 0
+#define SCTP_SIZE_OF_VRF_HASH 3
+#define SCTP_IFNAMSIZ IFNAMSIZ
+#define SCTP_DEFAULT_VRFID 0
+#define SCTP_DEFAULT_TABLEID 0
+#define SCTP_VRF_ADDR_HASH_SIZE 16
+#define SCTP_VRF_IFN_HASH_SIZE 3
+#define SCTP_VRF_DEFAULT_TABLEID(vrf_id) 0
#define SCTP_IFN_IS_IFT_LOOP(ifn) ((ifn)->ifn_type == IFT_LOOP)
@@ -124,7 +150,8 @@ __FBSDID("$FreeBSD$");
*/
/* This could return VOID if the index works but for BSD we provide both. */
#define SCTP_GET_IFN_VOID_FROM_ROUTE(ro) (void *)ro->ro_rt->rt_ifp
-#define SCTP_GET_IF_INDEX_FROM_ROUTE(ro) ro->ro_rt->rt_ifp->if_index
+#define SCTP_GET_IF_INDEX_FROM_ROUTE(ro) (ro)->ro_rt->rt_ifp->if_index
+#define SCTP_ROUTE_HAS_VALID_IFN(ro) ((ro)->ro_rt && (ro)->ro_rt->rt_ifp)
/*
* general memory allocation
@@ -205,6 +232,20 @@ typedef struct callout sctp_os_timer_t;
} else if ((m->m_flags & M_EXT) == 0) { \
M_ALIGN(m, len); \
}
+/*************************/
+/* MTU */
+/*************************/
+#define SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index) ((struct ifnet *)ifn)->if_mtu
+#define SCTP_GATHER_MTU_FROM_ROUTE(sctp_ifa, sa, rt) ((rt != NULL) ? rt->rt_rmx.rmx_mtu : 0)
+#define SCTP_GATHER_MTU_FROM_INTFC(sctp_ifn) ((sctp_ifn->ifn_p != NULL) ? ((struct ifnet *)(sctp_ifn->ifn_p))->if_mtu : 0)
+#define SCTP_SET_MTU_OF_ROUTE(sa, rt, mtu) do { \
+ if (rt != NULL) \
+ rt->rt_rmx.rmx_mtu = mtu; \
+ } while(0)
+
+/* (de-)register interface event notifications */
+#define SCTP_REGISTER_INTERFACE(ifhandle, ifname)
+#define SCTP_DEREGISTER_INTERFACE(ifhandle, ifname)
/*************************/
/* These are for logging */
@@ -224,13 +265,28 @@ typedef struct callout sctp_os_timer_t;
* chain pointers.. thus the macro.
*/
#define SCTP_HEADER_TO_CHAIN(m) (m)
+#define SCTP_DETACH_HEADER_FROM_CHAIN(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)
+#define SCTP_GET_HEADER_FOR_OUTPUT(o_pak) 0
+#define SCTP_RELEASE_HEADER(m)
+#define SCTP_RELEASE_PKT(m) sctp_m_freem(m)
+
+static inline int
+SCTP_GET_PKT_VRFID(void *m, uint32_t vrf_id)
+{
+ vrf_id = SCTP_DEFAULT_VRFID;
+ return (0);
+}
+static inline int
+SCTP_GET_PKT_TABLEID(void *m, uint32_t table_id)
+{
+ table_id = SCTP_DEFAULT_TABLEID;
+ return (0);
+}
/* Attach the chain of data into the sendable packet. */
#define SCTP_ATTACH_CHAIN(pak, m, packet_length) do { \
- pak->m_next = m; \
+ pak = m; \
pak->m_pkthdr.len = packet_length; \
} while(0)
@@ -248,6 +304,9 @@ typedef struct callout sctp_os_timer_t;
#define SCTP_GET_IPV4_LENGTH(iph) (iph->ip_len)
#define SCTP_GET_IPV6_LENGTH(ip6) (ntohs(ip6->ip6_plen))
+/* get the v6 hop limit */
+#define SCTP_GET_HLIM(inp, ro) in6_selecthlim((struct in6pcb *)&inp->ip_inp.inp, (ro ? (ro->ro_rt ? (ro->ro_rt->rt_ifp) : (NULL)) : (NULL)));
+
/* is the endpoint v6only? */
#define SCTP_IPV6_V6ONLY(inp) (((struct inpcb *)inp)->inp_flags & IN6P_IPV6_V6ONLY)
/* is the socket non-blocking? */
@@ -258,6 +317,8 @@ typedef struct callout sctp_os_timer_t;
#define SCTP_SO_TYPE(so) ((so)->so_type)
/* reserve sb space for a socket */
#define SCTP_SORESERVE(so, send, recv) soreserve(so, send, recv)
+/* wakeup a socket */
+#define SCTP_SOWAKEUP(so) wakeup(&(so)->so_timeo)
/* clear the socket buffer state */
#define SCTP_SB_CLEAR(sb) \
(sb).sb_cc = 0; \
@@ -271,7 +332,36 @@ typedef struct callout sctp_os_timer_t;
* routes, output, etc.
*/
typedef struct route sctp_route_t;
+typedef struct rtentry sctp_rtentry_t;
+
+#define SCTP_RTALLOC(ro, vrf_id, table_id) rtalloc_ign((struct route *)ro, 0UL)
+/* Future zero copy wakeup/send function */
+#define SCTP_ZERO_COPY_EVENT(inp, so)
+
+/*
+ * IP output routines
+ */
+#define SCTP_IP_OUTPUT(result, o_pak, ro, stcb, vrf_id, table_id) \
+{ \
+ int o_flgs = 0; \
+ if (stcb && stcb->sctp_ep && stcb->sctp_ep->sctp_socket) { \
+ o_flgs = IP_RAWOUTPUT | (stcb->sctp_ep->sctp_socket->so_options & SO_DONTROUTE); \
+ } else { \
+ o_flgs = IP_RAWOUTPUT; \
+ } \
+ result = ip_output(o_pak, NULL, ro, o_flgs, 0, NULL); \
+}
+
+#define SCTP_IP6_OUTPUT(result, o_pak, ro, ifp, stcb, vrf_id, table_id) \
+{ \
+ if (stcb && stcb->sctp_ep) \
+ result = ip6_output(o_pak, \
+ ((struct in6pcb *)(stcb->sctp_ep))->in6p_outputopts, \
+ (ro), 0, 0, ifp, NULL); \
+ else \
+ result = ip6_output(o_pak, NULL, (ro), 0, 0, ifp, NULL); \
+}
struct mbuf *
sctp_get_mbuf_for_msg(unsigned int space_needed,
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 96d9495..b13e9c4 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -2880,7 +2880,9 @@ bound_all_plan_b:
printf("Plan C no preferred for Dest, acceptable for?\n");
}
#endif
-
+ if (emit_ifn == NULL) {
+ goto plan_d;
+ }
LIST_FOREACH(sctp_ifa, &emit_ifn->ifalist, next_ifa) {
if ((sctp_ifa->localifa_flags & SCTP_ADDR_DEFER_USE) &&
(non_asoc_addr_ok == 0))
@@ -2902,7 +2904,7 @@ bound_all_plan_b:
atomic_add_int(&sifa->refcount, 1);
return (sifa);
}
-
+plan_d:
/*
* plan_d: We are in trouble. No preferred address on the emit
* interface. And not even a perfered address on all interfaces. Go
@@ -2969,7 +2971,6 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&ro->ro_dst;
struct sctp_ifa *answer;
uint8_t dest_is_priv, dest_is_loop;
- int did_rtalloc = 0;
sa_family_t fam;
/*
@@ -3024,11 +3025,17 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
* we must use rotation amongst the bound addresses..
*/
if (ro->ro_rt == NULL) {
+ uint32_t table_id = 0;
+
/*
* Need a route to cache.
*/
- rtalloc_ign(ro, 0UL);
- did_rtalloc = 1;
+ if (stcb) {
+ table_id = stcb->asoc.table_id;
+ } else {
+ table_id = SCTP_VRF_DEFAULT_TABLEID(vrf_id);
+ }
+ SCTP_RTALLOC(ro, vrf_id, table_id);
}
if (ro->ro_rt == NULL) {
return (NULL);
@@ -3327,25 +3334,22 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
*/
/* Will need ifdefs around this */
struct mbuf *o_pak;
-
+ struct mbuf *newm;
struct sctphdr *sctphdr;
int packet_length;
- int o_flgs;
uint32_t csum;
int ret;
- unsigned int have_mtu;
uint32_t vrf_id;
- sctp_route_t *ro;
-
+ sctp_route_t *ro = NULL;
if ((net) && (net->dest_state & SCTP_ADDR_OUT_OF_SCOPE)) {
sctp_m_freem(m);
return (EFAULT);
}
- if (stcb == NULL) {
- vrf_id = inp->def_vrf_id;
- } else {
+ if (stcb) {
vrf_id = stcb->asoc.vrf_id;
+ } else {
+ vrf_id = inp->def_vrf_id;
}
/* fill in the HMAC digest for any AUTH chunk in the packet */
@@ -3354,7 +3358,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
/* Calculate the csum and fill in the length of the packet */
sctphdr = mtod(m, struct sctphdr *);
- have_mtu = 0;
if (sctp_no_csum_on_loopback &&
(stcb) &&
(stcb->asoc.loopback_scope)) {
@@ -3376,17 +3379,17 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_route_t iproute;
uint8_t tos_value;
- o_pak = SCTP_GET_HEADER_FOR_OUTPUT(sizeof(struct ip));
- if (o_pak == NULL) {
- /* failed to prepend data, give up */
+ newm = sctp_get_mbuf_for_msg(sizeof(struct ip), 1, M_DONTWAIT, 1, MT_DATA);
+ if (newm == NULL) {
sctp_m_freem(m);
return (ENOMEM);
}
- SCTP_ALIGN_TO_END(o_pak, sizeof(struct ip));
- SCTP_BUF_LEN(SCTP_HEADER_TO_CHAIN(o_pak)) = sizeof(struct ip);
+ SCTP_ALIGN_TO_END(newm, sizeof(struct ip));
+ SCTP_BUF_LEN(newm) = sizeof(struct ip);
packet_length += sizeof(struct ip);
- SCTP_ATTACH_CHAIN(o_pak, m, packet_length);
- ip = mtod(SCTP_HEADER_TO_CHAIN(o_pak), struct ip *);
+ SCTP_BUF_NEXT(newm) = m;
+ m = newm;
+ ip = mtod(m, struct ip *);
ip->ip_v = IPVERSION;
ip->ip_hl = (sizeof(struct ip) >> 2);
if (net) {
@@ -3403,12 +3406,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
} else
ip->ip_off = 0;
-
/* FreeBSD has a function for ip_id's */
ip->ip_id = ip_newid();
ip->ip_ttl = inp->ip_inp.inp.inp_ip_ttl;
- ip->ip_len = SCTP_HEADER_LEN(o_pak);
+ ip->ip_len = packet_length;
if (stcb) {
if ((stcb->asoc.ecn_allowed) && ecn_ok) {
/* Enable ECN */
@@ -3435,10 +3437,16 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
/* call the routine to select the src address */
if (net) {
+ if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) {
+ sctp_free_ifa(net->ro._s_addr);
+ net->ro._s_addr = NULL;
+ net->src_addr_selected = 0;
+ }
if (net->src_addr_selected == 0) {
/* Cache the source address */
net->ro._s_addr = sctp_source_address_selection(inp, stcb,
- ro, net, out_of_asoc_ok, vrf_id);
+ ro, net, out_of_asoc_ok,
+ vrf_id);
if (net->ro._s_addr == NULL) {
/* No route to host */
goto no_route;
@@ -3514,15 +3522,10 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
}
}
- sctp_m_freem(o_pak);
return (EHOSTUNREACH);
- } else {
- have_mtu = ro->ro_rt->rt_ifp->if_mtu;
}
- if (inp->sctp_socket) {
- o_flgs = (IP_RAWOUTPUT | (inp->sctp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)));
- } else {
- o_flgs = IP_RAWOUTPUT;
+ if (ro != &iproute) {
+ memcpy(&iproute, ro, sizeof(*ro));
}
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_OUTPUT3) {
@@ -3532,23 +3535,17 @@ 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));
- }
- ret = ip_output(o_pak, inp->ip_inp.inp.inp_options,
- 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;
+
+ if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
+ /* failed to prepend data, give up */
+ sctp_m_freem(m);
+ return (ENOMEM);
}
-#endif
+ SCTP_ATTACH_CHAIN(o_pak, m, packet_length);
+
+ /* send it out. table id is taken from stcb */
+ SCTP_IP_OUTPUT(ret, o_pak, ro, stcb, vrf_id, 0);
+
SCTP_STAT_INCR(sctps_sendpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
if (ret)
@@ -3568,10 +3565,17 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
} else {
/* PMTU check versus smallest asoc MTU goes here */
if (ro->ro_rt != NULL) {
- if (ro->ro_rt->rt_rmx.rmx_mtu &&
- (stcb->asoc.smallest_mtu > ro->ro_rt->rt_rmx.rmx_mtu)) {
- sctp_mtu_size_reset(inp, &stcb->asoc,
- ro->ro_rt->rt_rmx.rmx_mtu);
+ uint32_t mtu;
+
+ mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt);
+ if (mtu &&
+ (stcb->asoc.smallest_mtu > mtu)) {
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("sctp_mtu_size_reset called after ip_output mtu-change:%d\n",
+ mtu);
+#endif
+ sctp_mtu_size_reset(inp, &stcb->asoc, mtu);
+ net->mtu = mtu;
}
} else {
/* route was freed */
@@ -3589,15 +3593,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
else if (to->sa_family == AF_INET6) {
uint32_t flowlabel;
struct ip6_hdr *ip6h;
-
struct route_in6 ip6route;
struct ifnet *ifp;
u_char flowTop;
uint16_t flowBottom;
u_char tosBottom, tosTop;
struct sockaddr_in6 *sin6, tmp, *lsa6, lsa6_tmp;
- struct sockaddr_in6 lsa6_storage;
int prev_scope = 0;
+ struct sockaddr_in6 lsa6_storage;
int error;
u_short prev_port = 0;
@@ -3606,18 +3609,19 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
} else {
flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo;
}
- o_pak = SCTP_GET_HEADER_FOR_OUTPUT(sizeof(struct ip6_hdr));
- if (o_pak == NULL) {
- /* failed to prepend data, give up */
+
+ newm = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA);
+ if (newm == NULL) {
sctp_m_freem(m);
return (ENOMEM);
}
- SCTP_ALIGN_TO_END(o_pak, sizeof(struct ip6_hdr));
-
- SCTP_BUF_LEN(SCTP_HEADER_TO_CHAIN(o_pak)) = sizeof(struct ip6_hdr);
+ SCTP_ALIGN_TO_END(newm, sizeof(struct ip6_hdr));
+ SCTP_BUF_LEN(newm) = sizeof(struct ip6_hdr);
packet_length += sizeof(struct ip6_hdr);
- SCTP_ATTACH_CHAIN(o_pak, m, packet_length);
- ip6h = mtod(SCTP_HEADER_TO_CHAIN(o_pak), struct ip6_hdr *);
+ SCTP_BUF_NEXT(newm) = m;
+ m = newm;
+
+ ip6h = mtod(m, struct ip6_hdr *);
/*
* We assume here that inp_flow is in host byte order within
* the TCB!
@@ -3654,7 +3658,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
}
ip6h->ip6_flow = htonl(((tosTop << 24) | ((tosBottom | flowTop) << 16) | flowBottom));
ip6h->ip6_nxt = IPPROTO_SCTP;
- ip6h->ip6_plen = (SCTP_HEADER_LEN(o_pak) - sizeof(struct ip6_hdr));
+ ip6h->ip6_plen = (packet_length - sizeof(struct ip6_hdr));
ip6h->ip6_dst = sin6->sin6_addr;
/*
@@ -3667,6 +3671,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
lsa6_tmp.sin6_len = sizeof(lsa6_tmp);
lsa6 = &lsa6_tmp;
if (net) {
+ if (net->ro._s_addr && net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED) {
+ sctp_free_ifa(net->ro._s_addr);
+ net->ro._s_addr = NULL;
+ net->src_addr_selected = 0;
+ }
if (net->src_addr_selected == 0) {
/* Cache the source address */
net->ro._s_addr = sctp_source_address_selection(inp,
@@ -3712,7 +3721,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
lsa6_storage.sin6_family = AF_INET6;
lsa6_storage.sin6_len = sizeof(lsa6_storage);
if ((error = sa6_recoverscope(&lsa6_storage)) != 0) {
- sctp_m_freem(o_pak);
+ sctp_m_freem(m);
return (error);
}
/* XXX */
@@ -3725,12 +3734,9 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
* We set the hop limit now since there is a good chance
* that our ro pointer is now filled
*/
- ip6h->ip6_hlim = in6_selecthlim((struct in6pcb *)&inp->ip_inp.inp,
- (ro ?
- (ro->ro_rt ? (ro->ro_rt->rt_ifp) : (NULL)) :
- (NULL)));
- o_flgs = 0;
- ifp = ro->ro_rt->rt_ifp;
+ ip6h->ip6_hlim = SCTP_GET_HLIM(inp, ro);
+ ifp = SCTP_GET_IFN_VOID_FROM_ROUTE(ro);
+
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_OUTPUT3) {
/* Copy to be sure something bad is not happening */
@@ -3743,20 +3749,24 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
printf("dst: ");
sctp_print_address((struct sockaddr *)sin6);
}
-#endif /* SCTP_DEBUG */
+#endif
if (net) {
sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
/* preserve the port and scope for link local send */
prev_scope = sin6->sin6_scope_id;
prev_port = sin6->sin6_port;
}
- ret = ip6_output(o_pak, ((struct in6pcb *)inp)->in6p_outputopts,
- (struct route_in6 *)ro,
- o_flgs,
- ((struct in6pcb *)inp)->in6p_moptions,
- &ifp
- ,NULL
- );
+ if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
+ /* failed to prepend data, give up */
+ sctp_m_freem(m);
+ return (ENOMEM);
+ }
+ SCTP_ATTACH_CHAIN(o_pak, m, packet_length);
+
+ /* send it out. table id is taken from stcb */
+ SCTP_IP6_OUTPUT(ret, o_pak, (struct route_in6 *)ro, &ifp,
+ stcb, vrf_id, 0);
+
if (net) {
/* for link local this must be done */
sin6->sin6_scope_id = prev_scope;
@@ -3766,7 +3776,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
if (sctp_debug_on & SCTP_DEBUG_OUTPUT3) {
printf("return from send is %d\n", ret);
}
-#endif /* SCTP_DEBUG_OUTPUT */
+#endif
SCTP_STAT_INCR(sctps_sendpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
if (ret) {
@@ -3781,7 +3791,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
/* PMTU check versus smallest asoc MTU goes here */
if (ro->ro_rt == NULL) {
/* Route was freed */
-
if (net->ro._s_addr &&
net->src_addr_selected) {
sctp_free_ifa(net->ro._s_addr);
@@ -3790,15 +3799,25 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
net->src_addr_selected = 0;
}
if (ro->ro_rt != NULL) {
- if (ro->ro_rt->rt_rmx.rmx_mtu &&
- (stcb->asoc.smallest_mtu > ro->ro_rt->rt_rmx.rmx_mtu)) {
- sctp_mtu_size_reset(inp,
- &stcb->asoc,
- ro->ro_rt->rt_rmx.rmx_mtu);
+ uint32_t mtu;
+
+ mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt);
+ if (mtu &&
+ (stcb->asoc.smallest_mtu > mtu)) {
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("sctp_mtu_size_reset called after ip6_output mtu-change:%d\n",
+ mtu);
+#endif
+ sctp_mtu_size_reset(inp, &stcb->asoc, mtu);
+ net->mtu = mtu;
}
} else if (ifp) {
if (ND_IFINFO(ifp)->linkmtu &&
(stcb->asoc.smallest_mtu > ND_IFINFO(ifp)->linkmtu)) {
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("sctp_mtu_size_reset called via ifp ND_IFINFO() linkmtu:%d\n",
+ ND_IFINFO(ifp)->linkmtu);
+#endif
sctp_mtu_size_reset(inp,
&stcb->asoc,
ND_IFINFO(ifp)->linkmtu);
@@ -4544,7 +4563,7 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
void
sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct mbuf *init_pkt, int iphlen, int offset, struct sctphdr *sh,
- struct sctp_init_chunk *init_chk)
+ struct sctp_init_chunk *init_chk, uint32_t vrf_id, uint32_t table_id)
{
struct sctp_association *asoc;
struct mbuf *m, *m_at, *m_tmp, *m_cookie, *op_err, *mp_last;
@@ -4567,15 +4586,11 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
int abort_flag, padval, sz_of;
int num_ext;
int p_len;
- uint32_t vrf_id;
- if (stcb) {
+ if (stcb)
asoc = &stcb->asoc;
- vrf_id = asoc->vrf_id;
- } else {
- vrf_id = inp->def_vrf_id;
+ else
asoc = NULL;
- }
mp_last = NULL;
if ((asoc != NULL) &&
(SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT) &&
@@ -4586,7 +4601,8 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
* though we even set the T bit and copy in the 0 tag.. this
* looks no different than if no listener was present.
*/
- sctp_send_abort(init_pkt, iphlen, sh, 0, NULL);
+ sctp_send_abort(init_pkt, iphlen, sh, 0, NULL, vrf_id,
+ table_id);
return;
}
abort_flag = 0;
@@ -4594,7 +4610,9 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
(offset + sizeof(struct sctp_init_chunk)),
&abort_flag, (struct sctp_chunkhdr *)init_chk);
if (abort_flag) {
- sctp_send_abort(init_pkt, iphlen, sh, init_chk->init.initiate_tag, op_err);
+ sctp_send_abort(init_pkt, iphlen, sh,
+ init_chk->init.initiate_tag, op_err, vrf_id,
+ table_id);
return;
}
m = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
@@ -4682,7 +4700,8 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
ro = &iproute;
memcpy(&ro->ro_dst, sin, sizeof(*sin));
addr = sctp_source_address_selection(inp, NULL,
- ro, NULL, 0, vrf_id);
+ ro, NULL, 0,
+ vrf_id);
if (addr == NULL)
return;
@@ -4711,9 +4730,9 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
stc.site_scope = 1;
stc.local_scope = 0;
}
+ sctp_free_ifa(addr);
} else if (iph->ip_v == (IPV6_VERSION >> 4)) {
struct sctp_ifa *addr;
-
struct route_in6 iproute6;
ip6 = mtod(init_pkt, struct ip6_hdr *);
@@ -4780,6 +4799,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
memcpy(&stc.laddress, &addr->address.sin6.sin6_addr, sizeof(struct in6_addr));
stc.laddr_type = SCTP_IPV6_ADDRESS;
+ sctp_free_ifa(addr);
}
} else {
/* set the scope per the existing tcb */
@@ -5446,6 +5466,7 @@ sctp_msg_append(struct sctp_tcb *stcb,
SCTP_GETTIME_TIMEVAL(&sp->ts);
sp->stream = srcv->sinfo_stream;
sp->msg_is_complete = 1;
+ sp->sender_all_done = 1;
sp->some_taken = 0;
sp->data = m;
sp->tail_mbuf = NULL;
@@ -5509,7 +5530,9 @@ error_out:
if (can_take_mbuf) {
appendchain = clonechain;
} else {
- if (!copy_by_ref && (sizeofcpy <= ((((sctp_mbuf_threshold_count - 1) * MLEN) + MHLEN)))) {
+ if (!copy_by_ref &&
+ (sizeofcpy <= ((((sctp_mbuf_threshold_count - 1) * MLEN) + MHLEN)))
+ ) {
/* Its not in a cluster */
if (*endofchain == NULL) {
/* lets get a mbuf cluster */
@@ -8025,7 +8048,8 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
#ifdef SCTP_AUDITING_ENABLED
sctp_audit_log(0xC3, 1);
#endif
- if (TAILQ_EMPTY(&asoc->sent_queue)) {
+ if ((TAILQ_EMPTY(&asoc->sent_queue)) &&
+ (TAILQ_EMPTY(&asoc->control_send_queue))) {
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_OUTPUT1) {
printf("SCTP hits empty queue with cnt set to %d?\n",
@@ -8780,7 +8804,6 @@ sctp_output(inp, m, addr, control, p, flags)
struct mbuf *m;
struct sockaddr *addr;
struct mbuf *control;
-
struct thread *p;
int flags;
{
@@ -9338,25 +9361,26 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb,
}
int
-sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh)
+sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh,
+ uint32_t vrf_id, uint32_t table_id)
{
/* formulate and SEND a SHUTDOWN-COMPLETE */
struct mbuf *o_pak;
struct mbuf *mout;
struct ip *iph, *iph_out;
struct ip6_hdr *ip6, *ip6_out;
- int offset_out, len;
+ int offset_out, len, mlen;
struct sctp_shutdown_complete_msg *comp_cp;
/* Get room for the largest message */
len = (sizeof(struct ip6_hdr) + sizeof(struct sctp_shutdown_complete_msg));
- o_pak = SCTP_GET_HEADER_FOR_OUTPUT(len);
- if (o_pak == NULL) {
- /* no mbuf's */
+
+ mout = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA);
+ if (mout == NULL) {
return (-1);
}
- mout = SCTP_HEADER_TO_CHAIN(o_pak);
+ SCTP_BUF_LEN(mout) = len;
iph = mtod(m, struct ip *);
iph_out = NULL;
ip6_out = NULL;
@@ -9408,8 +9432,11 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh)
/* Currently not supported. */
return (-1);
}
-
- SCTP_HEADER_LEN(o_pak) = SCTP_BUF_LEN(mout);
+ if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
+ /* no mbuf's */
+ sctp_m_freem(mout);
+ return (-1);
+ }
/* Now copy in and fill in the ABORT tags etc. */
comp_cp->sh.src_port = sh->dest_port;
comp_cp->sh.dest_port = sh->src_port;
@@ -9420,31 +9447,39 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh)
comp_cp->shut_cmp.ch.chunk_length = htons(sizeof(struct sctp_shutdown_complete_chunk));
/* add checksum */
- if ((sctp_no_csum_on_loopback) && SCTP_IS_IT_LOOPBACK(o_pak)) {
+ if ((sctp_no_csum_on_loopback) && SCTP_IS_IT_LOOPBACK(mout)) {
comp_cp->sh.checksum = 0;
} else {
comp_cp->sh.checksum = sctp_calculate_sum(mout, NULL, offset_out);
}
if (iph_out != NULL) {
sctp_route_t ro;
+ int ret;
+ struct sctp_tcb *stcb = NULL;
+ mlen = SCTP_BUF_LEN(mout);
bzero(&ro, sizeof ro);
/* set IPv4 length */
- iph_out->ip_len = SCTP_HEADER_LEN(o_pak);
+ iph_out->ip_len = mlen;
+ SCTP_ATTACH_CHAIN(o_pak, mout, mlen);
+
/* out it goes */
- ip_output(o_pak, 0, &ro, IP_RAWOUTPUT, NULL
- ,NULL
- );
+ SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id, table_id);
+
/* Free the route if we got one back */
if (ro.ro_rt)
RTFREE(ro.ro_rt);
} else if (ip6_out != NULL) {
struct route_in6 ro;
+ int ret;
+ struct sctp_tcb *stcb = NULL;
+ struct ifnet *ifp = NULL;
bzero(&ro, sizeof(ro));
- ip6_output(o_pak, NULL, &ro, 0, NULL, NULL
- ,NULL
- );
+ mlen = SCTP_BUF_LEN(mout);
+ SCTP_ATTACH_CHAIN(o_pak, mout, mlen);
+ SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id, table_id);
+
/* Free the route if we got one back */
if (ro.ro_rt)
RTFREE(ro.ro_rt);
@@ -9453,6 +9488,7 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh)
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
return (0);
+
}
static struct sctp_nets *
@@ -10166,7 +10202,7 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
void
sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
- struct mbuf *err_cause)
+ struct mbuf *err_cause, uint32_t vrf_id, uint32_t table_id)
{
/*-
* Formulate the abort message, and send it back down.
@@ -10176,7 +10212,7 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
struct sctp_abort_msg *abm;
struct ip *iph, *iph_out;
struct ip6_hdr *ip6, *ip6_out;
- int iphlen_out;
+ int iphlen_out, len;
/* don't respond to ABORT with ABORT */
if (sctp_is_there_an_abort_here(m, iphlen, &vtag)) {
@@ -10184,13 +10220,14 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
sctp_m_freem(err_cause);
return;
}
- o_pak = SCTP_GET_HEADER_FOR_OUTPUT((sizeof(struct ip6_hdr) + sizeof(struct sctp_abort_msg)));
- if (o_pak == NULL) {
+ len = (sizeof(struct ip6_hdr) + sizeof(struct sctp_abort_msg));
+
+ mout = sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA);
+ if (mout == NULL) {
if (err_cause)
sctp_m_freem(err_cause);
return;
}
- mout = SCTP_HEADER_TO_CHAIN(o_pak);
iph = mtod(m, struct ip *);
iph_out = NULL;
ip6_out = NULL;
@@ -10255,19 +10292,19 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
err_len += SCTP_BUF_LEN(m_tmp);
m_tmp = SCTP_BUF_NEXT(m_tmp);
}
- SCTP_HEADER_LEN(o_pak) = SCTP_BUF_LEN(mout) + err_len;
+ len = SCTP_BUF_LEN(mout) + err_len;
if (err_len % 4) {
/* need pad at end of chunk */
uint32_t cpthis = 0;
int padlen;
- padlen = 4 - (SCTP_HEADER_LEN(o_pak) % 4);
- m_copyback(mout, SCTP_HEADER_LEN(o_pak), padlen, (caddr_t)&cpthis);
- SCTP_HEADER_LEN(o_pak) += padlen;
+ padlen = 4 - (len % 4);
+ m_copyback(mout, len, padlen, (caddr_t)&cpthis);
+ len += padlen;
}
abm->msg.ch.chunk_length = htons(sizeof(abm->msg.ch) + err_len);
} else {
- SCTP_HEADER_LEN(mout) = SCTP_BUF_LEN(mout);
+ len = SCTP_BUF_LEN(mout);
abm->msg.ch.chunk_length = htons(sizeof(abm->msg.ch));
}
@@ -10277,8 +10314,15 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
} else {
abm->sh.checksum = sctp_calculate_sum(mout, NULL, iphlen_out);
}
+ if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
+ /* no mbuf's */
+ sctp_m_freem(mout);
+ return;
+ }
if (iph_out != NULL) {
sctp_route_t ro;
+ struct sctp_tcb *stcb = NULL;
+ int ret;
/* zap the stack pointer to the route */
bzero(&ro, sizeof ro);
@@ -10289,16 +10333,19 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
}
#endif
/* set IPv4 length */
- iph_out->ip_len = SCTP_HEADER_LEN(o_pak);
+ iph_out->ip_len = len;
/* out it goes */
- (void)ip_output(o_pak, 0, &ro, IP_RAWOUTPUT, NULL
- ,NULL
- );
+ SCTP_ATTACH_CHAIN(o_pak, mout, len);
+ SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id, table_id);
+
/* Free the route if we got one back */
if (ro.ro_rt)
RTFREE(ro.ro_rt);
} else if (ip6_out != NULL) {
struct route_in6 ro;
+ int ret;
+ struct sctp_tcb *stcb = NULL;
+ struct ifnet *ifp = NULL;
/* zap the stack pointer to the route */
bzero(&ro, sizeof(ro));
@@ -10308,10 +10355,10 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
sctp_print_address_pkt((struct ip *)ip6_out, &abm->sh);
}
#endif
- ip6_out->ip6_plen = SCTP_HEADER_LEN(o_pak) - sizeof(*ip6_out);
- ip6_output(o_pak, NULL, &ro, 0, NULL, NULL
- ,NULL
- );
+ ip6_out->ip6_plen = len - sizeof(*ip6_out);
+ SCTP_ATTACH_CHAIN(o_pak, mout, len);
+ SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id, table_id);
+
/* Free the route if we got one back */
if (ro.ro_rt)
RTFREE(ro.ro_rt);
@@ -10321,17 +10368,16 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag,
}
void
-sctp_send_operr_to(struct mbuf *m, int iphlen,
- struct mbuf *scm,
- uint32_t vtag)
+sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag,
+ uint32_t vrf_id, uint32_t table_id)
{
struct mbuf *o_pak;
struct sctphdr *ihdr;
int retcode;
struct sctphdr *ohdr;
struct sctp_chunkhdr *ophdr;
-
struct ip *iph;
+ struct mbuf *mout;
#ifdef SCTP_DEBUG
struct sockaddr_in6 lsa6, fsa6;
@@ -10363,7 +10409,6 @@ sctp_send_operr_to(struct mbuf *m, int iphlen,
len += SCTP_BUF_LEN(at);
at = SCTP_BUF_NEXT(at);
}
-
ophdr->chunk_length = htons(len - sizeof(struct sctphdr));
if (len % 4) {
/* need padding */
@@ -10379,22 +10424,28 @@ sctp_send_operr_to(struct mbuf *m, int iphlen,
} else {
val = sctp_calculate_sum(scm, NULL, 0);
}
+ mout = sctp_get_mbuf_for_msg(sizeof(struct ip6_hdr), 1, M_DONTWAIT, 1, MT_DATA);
+ if (mout == NULL) {
+ sctp_m_freem(scm);
+ return;
+ }
+ SCTP_BUF_NEXT(mout) = scm;
+ if (SCTP_GET_HEADER_FOR_OUTPUT(o_pak)) {
+ sctp_m_freem(mout);
+ return;
+ }
ohdr->checksum = val;
if (iph->ip_v == IPVERSION) {
/* V4 */
struct ip *out;
sctp_route_t ro;
+ struct sctp_tcb *stcb = NULL;
- o_pak = SCTP_GET_HEADER_FOR_OUTPUT(sizeof(struct ip));
- if (o_pak == NULL) {
- sctp_m_freem(scm);
- return;
- }
- SCTP_BUF_LEN(SCTP_HEADER_TO_CHAIN(o_pak)) = sizeof(struct ip);
+ SCTP_BUF_LEN(mout) = sizeof(struct ip);
len += sizeof(struct ip);
- SCTP_ATTACH_CHAIN(o_pak, scm, len);
+
bzero(&ro, sizeof ro);
- out = mtod(SCTP_HEADER_TO_CHAIN(o_pak), struct ip *);
+ out = mtod(mout, struct ip *);
out->ip_v = iph->ip_v;
out->ip_hl = (sizeof(struct ip) / 4);
out->ip_tos = iph->ip_tos;
@@ -10405,10 +10456,11 @@ sctp_send_operr_to(struct mbuf *m, int iphlen,
out->ip_sum = 0;
out->ip_src = iph->ip_dst;
out->ip_dst = iph->ip_src;
- out->ip_len = SCTP_HEADER_LEN(o_pak);
- retcode = ip_output(o_pak, 0, &ro, IP_RAWOUTPUT, NULL
- ,NULL
- );
+ out->ip_len = len;
+ SCTP_ATTACH_CHAIN(o_pak, mout, len);
+
+ SCTP_IP_OUTPUT(retcode, o_pak, &ro, stcb, vrf_id, table_id);
+
SCTP_STAT_INCR(sctps_sendpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
/* Free the route if we got one back */
@@ -10417,20 +10469,16 @@ sctp_send_operr_to(struct mbuf *m, int iphlen,
} else {
/* V6 */
struct route_in6 ro;
+ int ret;
+ struct sctp_tcb *stcb = NULL;
+ struct ifnet *ifp = NULL;
struct ip6_hdr *out6, *in6;
- o_pak = SCTP_GET_HEADER_FOR_OUTPUT(sizeof(struct ip6_hdr));
- if (o_pak == NULL) {
- sctp_m_freem(scm);
- return;
- }
- SCTP_BUF_LEN(SCTP_HEADER_TO_CHAIN(o_pak)) = sizeof(struct ip6_hdr);
+ SCTP_BUF_LEN(mout) = sizeof(struct ip6_hdr);
len += sizeof(struct ip6_hdr);
- SCTP_ATTACH_CHAIN(o_pak, scm, len);
-
bzero(&ro, sizeof ro);
in6 = mtod(m, struct ip6_hdr *);
- out6 = mtod(SCTP_HEADER_TO_CHAIN(o_pak), struct ip6_hdr *);
+ out6 = mtod(mout, struct ip6_hdr *);
out6->ip6_flow = in6->ip6_flow;
out6->ip6_hlim = ip6_defhlim;
out6->ip6_nxt = IPPROTO_SCTP;
@@ -10454,9 +10502,10 @@ sctp_send_operr_to(struct mbuf *m, int iphlen,
sctp_print_address((struct sockaddr *)&fsa6);
}
#endif /* SCTP_DEBUG */
- ip6_output(o_pak, NULL, &ro, 0, NULL, NULL
- ,NULL
- );
+
+ SCTP_ATTACH_CHAIN(o_pak, mout, len);
+ SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id, table_id);
+
SCTP_STAT_INCR(sctps_sendpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
/* Free the route if we got one back */
@@ -10496,7 +10545,7 @@ sctp_copy_one(struct sctp_stream_queue_pending *sp,
left = sp->length;
sp->data = m_uiotombuf(uio, M_WAITOK, sp->length,
- resv_upfront, M_PKTHDR);
+ resv_upfront, 0);
if (sp->data == NULL)
return (ENOMEM);
@@ -10596,8 +10645,6 @@ out_now:
}
-
-
int
sctp_sosend(struct socket *so,
struct sockaddr *addr,
@@ -10640,7 +10687,8 @@ sctp_lower_sosend(struct socket *so,
struct mbuf *control,
int flags,
int use_rcvinfo,
- struct sctp_sndrcvinfo *srcv,
+ struct sctp_sndrcvinfo *srcv
+ ,
struct thread *p
)
{
@@ -10669,6 +10717,7 @@ sctp_lower_sosend(struct socket *so,
int got_all_of_the_send = 0;
int hold_tcblock = 0;
int non_blocking = 0;
+ int temp_flags = 0;
error = 0;
net = NULL;
@@ -10721,12 +10770,50 @@ sctp_lower_sosend(struct socket *so,
}
hold_tcblock = 0;
SCTP_INP_RUNLOCK(inp);
- if (addr)
+ if (addr) {
/* Must locate the net structure if addr given */
net = sctp_findnet(stcb, addr);
- else
+ if (net) {
+ /* validate port was 0 or correct */
+ struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *)addr;
+ if ((sin->sin_port != 0) &&
+ (sin->sin_port != stcb->rport)) {
+ net = NULL;
+ }
+ }
+ temp_flags |= SCTP_ADDR_OVER;
+ } else
net = stcb->asoc.primary_destination;
+ if (addr && (net == NULL)) {
+ /* Could not find address, was it legal */
+ if (addr->sa_family == AF_INET) {
+ struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *)addr;
+ if (sin->sin_addr.s_addr == 0) {
+ if ((sin->sin_port == 0) ||
+ (sin->sin_port == stcb->rport)) {
+ net = stcb->asoc.primary_destination;
+ }
+ }
+ } else {
+ struct sockaddr_in6 *sin6;
+ sin6 = (struct sockaddr_in6 *)addr;
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+ if ((sin6->sin6_port == 0) ||
+ (sin6->sin6_port == stcb->rport)) {
+ net = stcb->asoc.primary_destination;
+ }
+ }
+ }
+ }
+ if (net == NULL) {
+ error = EINVAL;
+ goto out_unlocked;
+ }
} else if (use_rcvinfo && srcv && srcv->sinfo_assoc_id) {
stcb = sctp_findassociation_ep_asocid(inp, srcv->sinfo_assoc_id, 0);
if (stcb) {
@@ -10738,6 +10825,21 @@ sctp_lower_sosend(struct socket *so,
net = sctp_findnet(stcb, addr);
else
net = stcb->asoc.primary_destination;
+ if ((srcv->sinfo_flags & SCTP_ADDR_OVER) &&
+ ((net == NULL) || (addr == NULL))) {
+ struct sockaddr_in *sin;
+
+ if (addr == NULL) {
+ error = EINVAL;
+ goto out_unlocked;
+ }
+ sin = (struct sockaddr_in *)addr;
+ /* Validate port is 0 or correct */
+ if ((sin->sin_port != 0) &&
+ (sin->sin_port != stcb->rport)) {
+ net = NULL;
+ }
+ }
}
hold_tcblock = 0;
} else if (addr) {
@@ -11010,13 +11112,14 @@ sctp_lower_sosend(struct socket *so,
p->td_proc->p_stats->p_ru.ru_msgsnd++;
}
if (stcb) {
- if (net && ((srcv->sinfo_flags & SCTP_ADDR_OVER))) {
- /* we take the override or the unconfirmed */
- ;
- } else {
+ if (((srcv->sinfo_flags | temp_flags) & SCTP_ADDR_OVER) == 0) {
net = stcb->asoc.primary_destination;
}
}
+ if (net == NULL) {
+ error = EINVAL;
+ goto out_unlocked;
+ }
if ((net->flight_size > net->cwnd) && (sctp_cmt_on_off == 0)) {
/*-
* CMT: Added check for CMT above. net above is the primary
@@ -11389,7 +11492,15 @@ sctp_lower_sosend(struct socket *so,
un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
((stcb->asoc.chunks_on_out_queue - stcb->asoc.total_flight_count) *
sizeof(struct sctp_data_chunk)));
- queue_only = 0;
+ if (net->flight_size > (net->mtu * stcb->asoc.max_burst)) {
+ queue_only = 1;
+ SCTP_STAT_INCR(sctps_send_burst_avoid);
+ } else if (net->flight_size > net->cwnd) {
+ queue_only = 1;
+ SCTP_STAT_INCR(sctps_send_cwnd_avoid);
+ } else {
+ queue_only = 0;
+ }
}
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
(stcb->asoc.total_flight > 0) &&
@@ -11646,7 +11757,15 @@ skip_out_eof:
un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
((stcb->asoc.chunks_on_out_queue - stcb->asoc.total_flight_count) *
sizeof(struct sctp_data_chunk)));
- queue_only = 0;
+ if (net->flight_size > (net->mtu * stcb->asoc.max_burst)) {
+ queue_only = 1;
+ SCTP_STAT_INCR(sctps_send_burst_avoid);
+ } else if (net->flight_size > net->cwnd) {
+ queue_only = 1;
+ SCTP_STAT_INCR(sctps_send_cwnd_avoid);
+ } else {
+ queue_only = 0;
+ }
}
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
(stcb->asoc.total_flight > 0) &&
diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h
index 584252a..2f9b344 100644
--- a/sys/netinet/sctp_output.h
+++ b/sys/netinet/sctp_output.h
@@ -75,7 +75,8 @@ void sctp_send_initiate(struct sctp_inpcb *, struct sctp_tcb *);
void
sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *,
- struct mbuf *, int, int, struct sctphdr *, struct sctp_init_chunk *);
+ struct mbuf *, int, int, struct sctphdr *, struct sctp_init_chunk *,
+ uint32_t, uint32_t);
struct mbuf *
sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *,
@@ -98,7 +99,9 @@ int sctp_send_shutdown_ack(struct sctp_tcb *, struct sctp_nets *);
int sctp_send_shutdown_complete(struct sctp_tcb *, struct sctp_nets *);
-int sctp_send_shutdown_complete2(struct mbuf *, int, struct sctphdr *);
+int
+sctp_send_shutdown_complete2(struct mbuf *, int, struct sctphdr *,
+ uint32_t, uint32_t);
int sctp_send_asconf(struct sctp_tcb *, struct sctp_nets *);
@@ -116,7 +119,6 @@ int
sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
struct mbuf *, struct thread *, int);
-
void
sctp_insert_on_wheel(struct sctp_tcb *stcb,
struct sctp_association *asoc,
@@ -176,9 +178,11 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
void
sctp_send_abort(struct mbuf *, int, struct sctphdr *, uint32_t,
- struct mbuf *);
+ struct mbuf *, uint32_t, uint32_t);
-void sctp_send_operr_to(struct mbuf *, int, struct mbuf *, uint32_t);
+void
+sctp_send_operr_to(struct mbuf *, int, struct mbuf *, uint32_t, uint32_t,
+ uint32_t);
int
sctp_sosend(struct socket *so,
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 31c4bc0..75af8b3 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -130,13 +130,13 @@ sctp_fill_pcbinfo(struct sctp_pcbinfo *spcb)
*/
struct sctp_vrf *
-sctp_allocate_vrf(int vrfid)
+sctp_allocate_vrf(int vrf_id)
{
struct sctp_vrf *vrf = NULL;
struct sctp_vrflist *bucket;
/* First allocate the VRF structure */
- vrf = sctp_find_vrf(vrfid);
+ vrf = sctp_find_vrf(vrf_id);
if (vrf) {
/* Already allocated */
return (vrf);
@@ -146,28 +146,38 @@ sctp_allocate_vrf(int vrfid)
if (vrf == NULL) {
/* No memory */
#ifdef INVARIANTS
- panic("No memory for VRF:%d", vrfid);
+ panic("No memory for VRF:%d", vrf_id);
#endif
return (NULL);
}
/* setup the VRF */
memset(vrf, 0, sizeof(struct sctp_vrf));
- vrf->vrf_id = vrfid;
+ vrf->vrf_id = vrf_id;
LIST_INIT(&vrf->ifnlist);
vrf->total_ifa_count = 0;
/* Init the HASH of addresses */
- vrf->vrf_addr_hash = SCTP_HASH_INIT(SCTP_VRF_HASH_SIZE,
- &vrf->vrf_hashmark);
+ vrf->vrf_addr_hash = SCTP_HASH_INIT(SCTP_VRF_ADDR_HASH_SIZE,
+ &vrf->vrf_addr_hashmark);
if (vrf->vrf_addr_hash == NULL) {
/* No memory */
#ifdef INVARIANTS
- panic("No memory for VRF:%d", vrfid);
+ panic("No memory for VRF:%d", vrf_id);
+#endif
+ return (NULL);
+ }
+ vrf->vrf_ifn_hash = SCTP_HASH_INIT(SCTP_VRF_IFN_HASH_SIZE,
+ &vrf->vrf_ifn_hashmark);
+ if (vrf->vrf_ifn_hash == NULL) {
+ /* No memory */
+#ifdef INVARIANTS
+ panic("No memory for VRF:%d", vrf_id);
#endif
return (NULL);
}
/* Add it to the hash table */
- bucket = &sctppcbinfo.sctp_vrfhash[(vrfid & sctppcbinfo.hashvrfmark)];
+ bucket = &sctppcbinfo.sctp_vrfhash[(vrf_id & sctppcbinfo.hashvrfmark)];
LIST_INSERT_HEAD(bucket, vrf, next_vrf);
+ atomic_add_int(&sctppcbinfo.ipi_count_vrfs, 1);
return (vrf);
}
@@ -176,12 +186,14 @@ struct sctp_ifn *
sctp_find_ifn(struct sctp_vrf *vrf, void *ifn, uint32_t ifn_index)
{
struct sctp_ifn *sctp_ifnp;
+ struct sctp_ifnlist *hash_ifn_head;
/*
* We assume the lock is held for the addresses if thats wrong
* problems could occur :-)
*/
- LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
+ hash_ifn_head = &vrf->vrf_ifn_hash[(ifn_index & vrf->vrf_ifn_hashmark)];
+ LIST_FOREACH(sctp_ifnp, hash_ifn_head, next_bucket) {
if (sctp_ifnp->ifn_index == ifn_index) {
return (sctp_ifnp);
}
@@ -192,15 +204,17 @@ sctp_find_ifn(struct sctp_vrf *vrf, void *ifn, uint32_t ifn_index)
return (NULL);
}
+
+
struct sctp_vrf *
-sctp_find_vrf(uint32_t vrfid)
+sctp_find_vrf(uint32_t vrf_id)
{
struct sctp_vrflist *bucket;
struct sctp_vrf *liste;
- bucket = &sctppcbinfo.sctp_vrfhash[(vrfid & sctppcbinfo.hashvrfmark)];
+ bucket = &sctppcbinfo.sctp_vrfhash[(vrf_id & sctppcbinfo.hashvrfmark)];
LIST_FOREACH(liste, bucket, next_vrf) {
- if (vrfid == liste->vrf_id) {
+ if (vrf_id == liste->vrf_id) {
return (liste);
}
}
@@ -209,6 +223,35 @@ sctp_find_vrf(uint32_t vrfid)
void
+sctp_free_ifn(struct sctp_ifn *sctp_ifnp)
+{
+ int ret;
+
+ ret = atomic_fetchadd_int(&sctp_ifnp->refcount, -1);
+ if (ret == 1) {
+ /* We zero'd the count */
+ SCTP_FREE(sctp_ifnp);
+ atomic_subtract_int(&sctppcbinfo.ipi_count_ifns, 1);
+ }
+}
+
+void
+sctp_update_ifn_mtu(uint32_t vrf_id, uint32_t ifn_index, uint32_t mtu)
+{
+ struct sctp_ifn *sctp_ifnp;
+ struct sctp_vrf *vrf;
+
+ vrf = sctp_find_vrf(vrf_id);
+ if (vrf == NULL)
+ return;
+ sctp_ifnp = sctp_find_ifn(vrf, (void *)NULL, ifn_index);
+ if (sctp_ifnp != NULL) {
+ sctp_ifnp->ifn_mtu = mtu;
+ }
+}
+
+
+void
sctp_free_ifa(struct sctp_ifa *sctp_ifap)
{
int ret;
@@ -216,37 +259,50 @@ sctp_free_ifa(struct sctp_ifa *sctp_ifap)
ret = atomic_fetchadd_int(&sctp_ifap->refcount, -1);
if (ret == 1) {
/* We zero'd the count */
-#ifdef INVARIANTS
- if (sctp_ifap->in_ifa_list) {
- panic("Attempt to free item in a list");
- }
-#else
- if (sctp_ifap->in_ifa_list) {
- printf("in_ifa_list was not clear, fixing cnt\n");
- atomic_add_int(&sctp_ifap->refcount, 1);
- return;
- }
-#endif
SCTP_FREE(sctp_ifap);
+ atomic_subtract_int(&sctppcbinfo.ipi_count_ifas, 1);
}
}
+static void
+sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock)
+{
+ struct sctp_ifn *found;
+
+ found = sctp_find_ifn(sctp_ifnp->vrf, sctp_ifnp->ifn_p, sctp_ifnp->ifn_index);
+ if (found == NULL) {
+ /* Not in the list.. sorry */
+ return;
+ }
+ if (hold_addr_lock == 0)
+ SCTP_IPI_ADDR_LOCK();
+ LIST_REMOVE(sctp_ifnp, next_bucket);
+ LIST_REMOVE(sctp_ifnp, next_ifn);
+ if (hold_addr_lock == 0)
+ SCTP_IPI_ADDR_UNLOCK();
+ /* Take away the reference, and possibly free it */
+ sctp_free_ifn(sctp_ifnp);
+}
+
+
struct sctp_ifa *
-sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
+sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
uint32_t ifn_type, const char *if_name,
- void *ifa, struct sockaddr *addr, uint32_t ifa_flags, int dynamic_add)
+ void *ifa, struct sockaddr *addr, uint32_t ifa_flags,
+ int dynamic_add)
{
struct sctp_vrf *vrf;
struct sctp_ifn *sctp_ifnp = NULL;
struct sctp_ifa *sctp_ifap = NULL;
- struct sctp_ifalist *hash_head;
+ struct sctp_ifalist *hash_addr_head;
+ struct sctp_ifnlist *hash_ifn_head;
uint32_t hash_of_addr;
/* How granular do we need the locks to be here? */
SCTP_IPI_ADDR_LOCK();
- vrf = sctp_find_vrf(vrfid);
+ vrf = sctp_find_vrf(vrf_id);
if (vrf == NULL) {
- vrf = sctp_allocate_vrf(vrfid);
+ vrf = sctp_allocate_vrf(vrf_id);
if (vrf == NULL) {
SCTP_IPI_ADDR_UNLOCK();
return (NULL);
@@ -270,12 +326,20 @@ sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
sctp_ifnp->ifn_p = ifn;
sctp_ifnp->ifn_type = ifn_type;
sctp_ifnp->ifa_count = 0;
- sctp_ifnp->refcount = 0;
+ sctp_ifnp->refcount = 1;
sctp_ifnp->vrf = vrf;
- memcpy(sctp_ifnp->ifn_name, if_name, SCTP_IFNAMSIZ);
+ sctp_ifnp->ifn_mtu = SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index);
+ if (if_name != NULL) {
+ memcpy(sctp_ifnp->ifn_name, if_name, SCTP_IFNAMSIZ);
+ } else {
+ memcpy(sctp_ifnp->ifn_name, "unknown", min(7, SCTP_IFNAMSIZ));
+ }
+ hash_ifn_head = &vrf->vrf_ifn_hash[(ifn_index & vrf->vrf_ifn_hashmark)];
LIST_INIT(&sctp_ifnp->ifalist);
SCTP_IPI_ADDR_LOCK();
+ LIST_INSERT_HEAD(hash_ifn_head, sctp_ifnp, next_bucket);
LIST_INSERT_HEAD(&vrf->ifnlist, sctp_ifnp, next_ifn);
+ atomic_add_int(&sctppcbinfo.ipi_count_ifns, 1);
}
sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
if (sctp_ifap) {
@@ -303,7 +367,7 @@ sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
/* repair ifnp which was NULL ? */
sctp_ifap->localifa_flags = SCTP_ADDR_VALID;
sctp_ifap->ifn_p = sctp_ifnp;
- atomic_add_int(&sctp_ifnp->refcount, 1);
+ atomic_add_int(&sctp_ifap->ifn_p->refcount, 1);
}
goto exit_stage_left;
}
@@ -356,13 +420,13 @@ sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
sctp_ifap->src_is_glob = 1;
}
SCTP_IPI_ADDR_LOCK();
- hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_hashmark)];
- LIST_INSERT_HEAD(hash_head, sctp_ifap, next_bucket);
+ hash_addr_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)];
+ LIST_INSERT_HEAD(hash_addr_head, sctp_ifap, next_bucket);
sctp_ifap->refcount = 1;
LIST_INSERT_HEAD(&sctp_ifnp->ifalist, sctp_ifap, next_ifa);
sctp_ifnp->ifa_count++;
- sctp_ifap->in_ifa_list = 1;
vrf->total_ifa_count++;
+ atomic_add_int(&sctppcbinfo.ipi_count_ifas, 1);
SCTP_IPI_ADDR_UNLOCK();
if (dynamic_add) {
/*
@@ -383,9 +447,8 @@ sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
printf("Lost and address change ???\n");
}
#endif /* SCTP_DEBUG */
-
/* Opps, must decrement the count */
- sctp_free_ifa(sctp_ifap);
+ sctp_del_addr_from_vrf(vrf_id, addr, ifn_index);
return (NULL);
}
SCTP_INCR_LADDR_COUNT();
@@ -403,12 +466,15 @@ sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
(struct sctp_tcb *)NULL,
(struct sctp_nets *)NULL);
SCTP_IPI_ITERATOR_WQ_UNLOCK();
+ } else {
+ /* it's ready for use */
+ sctp_ifap->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
}
return (sctp_ifap);
}
void
-sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
+sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr,
uint32_t ifn_index)
{
struct sctp_vrf *vrf;
@@ -416,9 +482,11 @@ sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
SCTP_IPI_ADDR_LOCK();
- vrf = sctp_find_vrf(vrfid);
+ vrf = sctp_find_vrf(vrf_id);
if (vrf == NULL) {
- printf("Can't find vrfid:%d\n", vrfid);
+#ifdef SCTP_DEBUG
+ printf("Can't find vrf_id:%d\n", vrf_id);
+#endif
goto out_now;
}
sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
@@ -429,13 +497,21 @@ sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
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_ifap->ifn_p->refcount, -1);
- } else {
+ if (sctp_ifap->ifn_p) {
+ if (SCTP_LIST_EMPTY(&sctp_ifap->ifn_p->ifalist)) {
+ sctp_delete_ifn(sctp_ifap->ifn_p, 1);
+ }
+ sctp_free_ifn(sctp_ifap->ifn_p);
+ sctp_ifap->ifn_p = NULL;
+ }
+ }
+#ifdef SCTP_DEBUG
+ else {
printf("Del Addr-ifn:%d Could not find address:",
ifn_index);
sctp_print_address(addr);
}
+#endif
out_now:
SCTP_IPI_ADDR_UNLOCK();
if (sctp_ifap) {
@@ -521,7 +597,7 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
continue;
}
if (lport != inp->sctp_lport) {
- SCTP_INP_RUNLOCK(inp);
+ SCTP_INP_RUNLOCK(inp);
continue;
}
if (inp->def_vrf_id != vrf_id) {
@@ -1671,7 +1747,6 @@ sctp_inpcb_alloc(struct socket *so)
*/
int i, error;
struct sctp_inpcb *inp;
-
struct sctp_pcb *m;
struct timeval time;
sctp_sharedkey_t *null_key;
@@ -1722,14 +1797,12 @@ sctp_inpcb_alloc(struct socket *so)
/* UDP style socket */
inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE |
SCTP_PCB_FLAGS_UNBOUND);
- sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
/* Be sure it is NON-BLOCKING IO for UDP */
/* SCTP_SET_SO_NBIO(so); */
} else if (SCTP_SO_TYPE(so) == SOCK_STREAM) {
/* TCP style socket */
inp->sctp_flags = (SCTP_PCB_FLAGS_TCPTYPE |
SCTP_PCB_FLAGS_UNBOUND);
- sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
/* Be sure we have blocking IO by default */
SCTP_CLEAR_SO_NBIO(so);
} else {
@@ -1748,6 +1821,7 @@ sctp_inpcb_alloc(struct socket *so)
return (ENOBUFS);
}
inp->def_vrf_id = SCTP_DEFAULT_VRFID;
+ inp->def_table_id = SCTP_DEFAULT_TABLEID;
SCTP_INP_INFO_WLOCK();
SCTP_INP_LOCK_INIT(inp);
@@ -2882,7 +2956,6 @@ sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
net->ssthresh = stcb->asoc.peers_rwnd;
}
-
int
sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
int set_scope, int from)
@@ -3062,7 +3135,8 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
(void)sa6_embedscope(sin6, ip6_use_defzone);
sin6->sin6_scope_id = 0;
}
- rtalloc_ign((struct route *)&net->ro, 0UL);
+ SCTP_RTALLOC((sctp_route_t *) & net->ro, stcb->asoc.vrf_id,
+ stcb->asoc.table_id);
if (newaddr->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;
@@ -3070,19 +3144,64 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
sin6 = (struct sockaddr_in6 *)&net->ro._l_addr;
(void)sa6_recoverscope(sin6);
}
- if ((net->ro.ro_rt) &&
- (net->ro.ro_rt->rt_ifp)) {
- net->mtu = net->ro.ro_rt->rt_ifp->if_mtu;
+ if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro)) {
+ /* Get source address */
+ net->ro._s_addr = sctp_source_address_selection(stcb->sctp_ep,
+ stcb,
+ (sctp_route_t *) & net->ro,
+ net,
+ 0,
+ stcb->asoc.vrf_id);
+ /* Now get the interface MTU */
+ if (net->ro._s_addr && net->ro._s_addr->ifn_p) {
+ net->mtu = SCTP_GATHER_MTU_FROM_INTFC(net->ro._s_addr->ifn_p);
+ } else {
+ net->mtu = 0;
+ }
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("We have found an interface mtu of %d\n", net->mtu);
+#endif
+ if (net->mtu == 0) {
+ /* Huh ?? */
+ net->mtu = SCTP_DEFAULT_MTU;
+ } else {
+ uint32_t rmtu;
+
+ rmtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, net->ro.ro_rt);
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("The route mtu is %d\n", rmtu);
+#endif
+ if (rmtu == 0) {
+ /*
+ * Start things off to match mtu of
+ * interface please.
+ */
+ SCTP_SET_MTU_OF_ROUTE(&net->ro._l_addr.sa,
+ net->ro.ro_rt, net->mtu);
+ } else {
+ /*
+ * we take the route mtu over the interface,
+ * since the route may be leading out the
+ * loopback, or a different interface.
+ */
+ net->mtu = rmtu;
+ }
+ }
if (from == SCTP_ALLOC_ASOC) {
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("New assoc sets mtu to :%d\n",
+ net->mtu);
+#endif
stcb->asoc.smallest_mtu = net->mtu;
}
- /* start things off to match mtu of interface please. */
- net->ro.ro_rt->rt_rmx.rmx_mtu = net->ro.ro_rt->rt_ifp->if_mtu;
} else {
net->mtu = stcb->asoc.smallest_mtu;
}
-
if (stcb->asoc.smallest_mtu > net->mtu) {
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("new address mtu:%d smaller than smallest:%d\n",
+ net->mtu, stcb->asoc.smallest_mtu);
+#endif
stcb->asoc.smallest_mtu = net->mtu;
}
/*
@@ -3187,7 +3306,7 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr,
*/
struct sctp_tcb *
sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
- int for_a_init, int *error, uint32_t override_tag, uint32_t vrf)
+ int for_a_init, int *error, uint32_t override_tag, uint32_t vrf_id)
{
struct sctp_tcb *stcb;
struct sctp_association *asoc;
@@ -3287,7 +3406,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
/* setup back pointer's */
stcb->sctp_ep = inp;
stcb->sctp_socket = inp->sctp_socket;
- if ((err = sctp_init_asoc(inp, asoc, for_a_init, override_tag, vrf))) {
+ if ((err = sctp_init_asoc(inp, asoc, for_a_init, override_tag, vrf_id))) {
/* failed */
SCTP_TCB_LOCK_DESTROY(stcb);
SCTP_TCB_SEND_LOCK_DESTROY(stcb);
@@ -3745,7 +3864,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
SOCK_UNLOCK(so);
sctp_sowwakeup(inp, so);
sctp_sorwakeup(inp, so);
- wakeup(&so->so_timeo);
+ SCTP_SOWAKEUP(so);
}
}
}
@@ -4295,7 +4414,7 @@ sctp_del_local_addr_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa)
if (net->ro._s_addr &&
(net->ro._s_addr->ifa == laddr->ifa)) {
/* Yep, purge src address selected */
- struct rtentry *rt;
+ sctp_rtentry_t *rt;
/* delete this address if cached */
rt = net->ro.ro_rt;
@@ -4732,6 +4851,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
/* Skip multi-cast addresses */
goto next_param;
}
+ if ((sin.sin_addr.s_addr == INADDR_BROADCAST) ||
+ (sin.sin_addr.s_addr == INADDR_ANY)) {
+ goto next_param;
+ }
sa = (struct sockaddr *)&sin;
inp = stcb->sctp_ep;
atomic_add_int(&stcb->asoc.refcnt, 1);
diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h
index 85e5dc6..077d345 100644
--- a/sys/netinet/sctp_pcb.h
+++ b/sys/netinet/sctp_pcb.h
@@ -51,7 +51,6 @@ TAILQ_HEAD(sctp_readhead, sctp_queued_to_read);
TAILQ_HEAD(sctp_streamhead, sctp_stream_queue_pending);
#include <netinet/sctp_structs.h>
-#include <netinet/sctp_uio.h>
#include <netinet/sctp_auth.h>
#define SCTP_PCBHASH_ALLADDR(port, mask) (port & mask)
@@ -60,17 +59,21 @@ TAILQ_HEAD(sctp_streamhead, sctp_stream_queue_pending);
struct sctp_vrf {
LIST_ENTRY(sctp_vrf) next_vrf;
struct sctp_ifalist *vrf_addr_hash;
+ struct sctp_ifnlist *vrf_ifn_hash;
struct sctp_ifnlist ifnlist;
uint32_t vrf_id;
uint32_t total_ifa_count;
- u_long vrf_hashmark;
+ u_long vrf_addr_hashmark;
+ u_long vrf_ifn_hashmark;
};
struct sctp_ifn {
struct sctp_ifalist ifalist;
struct sctp_vrf *vrf;
LIST_ENTRY(sctp_ifn) next_ifn;
+ LIST_ENTRY(sctp_ifn) next_bucket;
void *ifn_p; /* never access without appropriate lock */
+ uint32_t ifn_mtu;
uint32_t ifn_type;
uint32_t ifn_index; /* shorthand way to look at ifn for reference */
uint32_t refcount; /* number of reference held should be >=
@@ -105,7 +108,8 @@ struct sctp_ifa {
uint8_t src_is_loop;
uint8_t src_is_priv;
uint8_t src_is_glob;
- uint8_t in_ifa_list;
+ uint8_t resv;
+
};
struct sctp_laddr {
@@ -197,10 +201,20 @@ struct sctp_epinfo {
/* socket queue zone info */
uint32_t ipi_count_strmoq;
+ /* Number of vrfs */
+ uint32_t ipi_count_vrfs;
+
+ /* Number of ifns */
+ uint32_t ipi_count_ifns;
+
+ /* Number of ifas */
+ uint32_t ipi_count_ifas;
+
/* system wide number of free chunks hanging around */
uint32_t ipi_free_chunks;
uint32_t ipi_free_strmoq;
+
struct sctpvtaghead vtag_timewait[SCTP_STACK_VTAG_HASH_SIZE];
/* address work queue handling */
@@ -345,6 +359,7 @@ struct sctp_inpcb {
struct mtx inp_rdata_mtx;
int32_t refcount;
uint32_t def_vrf_id;
+ uint32_t def_table_id;
uint32_t total_sends;
uint32_t total_recvs;
uint32_t last_abort_code;
@@ -405,15 +420,18 @@ sctp_add_addr_to_vrf(uint32_t vrfid,
const char *if_name,
void *ifa, struct sockaddr *addr, uint32_t ifa_flags, int dynamic_add);
+void sctp_update_ifn_mtu(uint32_t vrf_id, uint32_t ifn_index, uint32_t mtu);
+
+void sctp_free_ifn(struct sctp_ifn *sctp_ifnp);
void sctp_free_ifa(struct sctp_ifa *sctp_ifap);
-void
+
+void
sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
uint32_t ifn_index);
-
struct sctp_nets *sctp_findnet(struct sctp_tcb *, struct sockaddr *);
struct sctp_inpcb *sctp_pcb_findep(struct sockaddr *, int, int, uint32_t);
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index fc6588b..b0be404 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -38,7 +38,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_os.h>
#include <netinet/sctp_header.h>
-#include <netinet/sctp_uio.h>
#include <netinet/sctp_auth.h>
struct sctp_timer {
@@ -157,6 +156,12 @@ struct sctp_asconf_iterator {
};
+struct sctp_net_route {
+ sctp_rtentry_t *ro_rt;
+ union sctp_sockstore _l_addr; /* remote peer addr */
+ struct sctp_ifa *_s_addr; /* our selected src addr */
+};
+
struct sctp_nets {
TAILQ_ENTRY(sctp_nets) sctp_next; /* next link */
@@ -170,11 +175,8 @@ struct sctp_nets {
* The following two in combination equate to a route entry for v6
* or v4.
*/
- struct sctp_route {
- struct rtentry *ro_rt;
- union sctp_sockstore _l_addr; /* remote peer addr */
- struct sctp_ifa *_s_addr; /* our selected src addr */
- } ro;
+ struct sctp_net_route ro;
+
/* mtu discovered so far */
uint32_t mtu;
uint32_t ssthresh; /* not sure about this one for split */
@@ -368,6 +370,8 @@ struct sctp_queued_to_read { /* sinfo structure Pluse more */
struct mbuf *data; /* front of the mbuf chain of data with
* PKT_HDR */
struct mbuf *tail_mbuf; /* used for multi-part data */
+ struct mbuf *aux_data; /* used to hold/cache control if o/s does not
+ * take it from us */
struct sctp_tcb *stcb; /* assoc, used for window update */
TAILQ_ENTRY(sctp_queued_to_read) next;
uint16_t port_from;
@@ -585,6 +589,7 @@ struct sctp_association {
struct sctp_readhead pending_reply_queue;
uint32_t vrf_id;
+ uint32_t table_id;
uint32_t cookie_preserve_req;
/* ASCONF next seq I am sending out, inits at init-tsn */
@@ -594,11 +599,9 @@ struct sctp_association {
/* next seq I am sending in str reset messages */
uint32_t str_reset_seq_out;
-
/* next seq I am expecting in str reset messages */
uint32_t str_reset_seq_in;
-
/* various verification tag information */
uint32_t my_vtag; /* The tag to be used. if assoc is re-initited
* by remote end, and I have unlocked this
diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c
index 943399e..07ec1b1 100644
--- a/sys/netinet/sctp_sysctl.c
+++ b/sys/netinet/sctp_sysctl.c
@@ -194,6 +194,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
xinpcb.total_sends = inp->total_sends;
xinpcb.total_recvs = inp->total_recvs;
xinpcb.total_nospaces = inp->total_nospaces;
+ xinpcb.fragmentation_point = inp->sctp_frag_point;
SCTP_INP_INCR_REF(inp);
SCTP_INP_RUNLOCK(inp);
SCTP_INP_INFO_RUNLOCK();
@@ -249,6 +250,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
xstcb.highest_tsn = stcb->asoc.sending_seq - 1;
xstcb.cumulative_tsn = stcb->asoc.last_acked_seq;
xstcb.cumulative_tsn_ack = stcb->asoc.cumulative_tsn;
+ xstcb.mtu = stcb->asoc.smallest_mtu;
SCTP_INP_RUNLOCK(inp);
SCTP_INP_INFO_RUNLOCK();
error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb));
@@ -268,6 +270,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
xraddr.RemAddrCwnd = net->cwnd;
xraddr.RemAddrFlightSize = net->flight_size;
xraddr.RemAddrStartTime = net->start_time;
+ xraddr.RemAddrMTU = net->mtu;
error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr));
if (error) {
atomic_add_int(&stcb->asoc.refcnt, -1);
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index 57ad30d..3e72cc0 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -200,7 +200,6 @@ sctp_audit_retranmission_queue(struct sctp_association *asoc)
#endif /* SCTP_DEBUG */
}
-
int
sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct sctp_nets *net, uint16_t threshold)
@@ -354,20 +353,10 @@ sctp_find_alternate_net(struct sctp_tcb *stcb,
alt = TAILQ_FIRST(&stcb->asoc.nets);
}
if (alt->ro.ro_rt == NULL) {
- struct sockaddr_in6 *sin6;
-
- sin6 = (struct sockaddr_in6 *)&alt->ro._l_addr;
- if (sin6->sin6_family == AF_INET6) {
- (void)sa6_embedscope(sin6, ip6_use_defzone);
- }
- rtalloc_ign((struct route *)&alt->ro, 0UL);
-
- if (sin6->sin6_family == AF_INET6) {
- (void)sa6_recoverscope(sin6);
- }
if (alt->ro._s_addr) {
sctp_free_ifa(alt->ro._s_addr);
alt->ro._s_addr = NULL;
+
}
alt->src_addr_selected = 0;
}
@@ -936,6 +925,22 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
/* Move all pending over too */
sctp_move_all_chunks_to_alt(stcb, net, alt);
+
+ /*
+ * Get the address that failed, to force a new src address
+ * selecton and a route allocation.
+ */
+ if (net->ro._s_addr) {
+ sctp_free_ifa(net->ro._s_addr);
+ net->ro._s_addr = NULL;
+ }
+ net->src_addr_selected = 0;
+
+ /* Force a route allocation too */
+ if (net->ro.ro_rt) {
+ RTFREE(net->ro.ro_rt);
+ net->ro.ro_rt = NULL;
+ }
/* Was it our primary? */
if ((stcb->asoc.primary_destination == net) && (alt != net)) {
/*
@@ -949,11 +954,6 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp,
(struct sockaddr *)NULL,
alt) == 0) {
net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
- if (net->ro._s_addr) {
- sctp_free_ifa(net->ro._s_addr);
- net->ro._s_addr = NULL;
- }
- net->src_addr_selected = 0;
}
}
}
@@ -1538,16 +1538,27 @@ sctp_pathmtu_timer(struct sctp_inpcb *inp,
if (next_mtu <= net->mtu) {
/* nothing to do */
return;
- }
- if (net->ro.ro_rt != NULL) {
- /*
- * only if we have a route and interface do we set anything.
- * Note we always restart the timer though just in case it
- * is updated (i.e. the ifp) or route/ifp is populated.
- */
- if (net->ro.ro_rt->rt_ifp != NULL) {
- if (net->ro.ro_rt->rt_ifp->if_mtu > next_mtu) {
- /* ok it will fit out the door */
+ } {
+ uint32_t mtu;
+
+ if ((net->src_addr_selected == 0) ||
+ (net->ro._s_addr == NULL) ||
+ (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) {
+ if ((net->ro._s_addr == NULL) && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) {
+ sctp_free_ifa(net->ro._s_addr);
+ net->ro._s_addr = NULL;
+ net->src_addr_selected = 0;
+ }
+ net->ro._s_addr = sctp_source_address_selection(inp,
+ stcb,
+ (sctp_route_t *) & net->ro,
+ net, 0, stcb->asoc.vrf_id);
+ if (net->ro._s_addr)
+ net->src_addr_selected = 1;
+ }
+ if (net->ro._s_addr) {
+ mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt);
+ if (mtu > next_mtu) {
net->mtu = next_mtu;
}
}
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index 1e54e9c..240db62 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -895,6 +895,10 @@ struct sctpstat {
u_long sctps_cached_strmoq; /* Number of cached stream oq's used */
u_long sctps_left_abandon; /* Number of unread message abandonded
* by close */
+ u_long sctps_send_burst_avoid; /* Send burst avoidance, already max
+ * burst inflight to net */
+ u_long sctps_send_cwnd_avoid; /* Send cwnd full avoidance, already
+ * max burst inflight to net */
};
#define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1)
@@ -929,6 +933,7 @@ struct xsctp_inpcb {
uint32_t total_sends;
uint32_t total_recvs;
uint32_t total_nospaces;
+ uint32_t fragmentation_point;
/* add more endpoint specific data here */
};
@@ -955,6 +960,7 @@ struct xsctp_tcb {
uint32_t highest_tsn;
uint32_t cumulative_tsn;
uint32_t cumulative_tsn_ack;
+ uint32_t mtu;
/* add more association specific data here */
uint16_t number_local_addresses;
uint16_t number_remote_addresses;
@@ -977,6 +983,7 @@ struct xsctp_raddr {
uint32_t RemAddrErrorCounter; /* */
uint32_t RemAddrCwnd; /* */
uint32_t RemAddrFlightSize; /* */
+ uint32_t RemAddrMTU; /* */
struct timeval RemAddrStartTime; /* sctpAssocLocalRemEntry 8 */
/* add more remote address specific data */
};
@@ -989,8 +996,7 @@ int
sctp_lower_sosend(struct socket *so,
struct sockaddr *addr,
struct uio *uio,
-
- struct mbuf *top,
+ struct mbuf *i_pak,
struct mbuf *control,
int flags,
int use_rcvinfo,
@@ -1008,7 +1014,6 @@ sctp_sorecvmsg(struct socket *so,
struct sctp_sndrcvinfo *sinfo,
int filling_sinfo);
-
#endif
/*
@@ -1027,7 +1032,7 @@ int sctp_getladdrs __P((int, sctp_assoc_t, struct sockaddr **));
void sctp_freeladdrs __P((struct sockaddr *));
int sctp_opt_info __P((int, sctp_assoc_t, int, void *, socklen_t *));
-ssize_t sctp_sendmsg
+ssize_t sctp_sendmsg
__P((int, const void *, size_t,
const struct sockaddr *,
socklen_t, uint32_t, uint32_t, uint16_t, uint32_t, uint32_t));
@@ -1035,17 +1040,15 @@ __P((int, const void *, size_t,
ssize_t sctp_send __P((int sd, const void *msg, size_t len,
const struct sctp_sndrcvinfo *sinfo, int flags));
- ssize_t
- sctp_sendx __P((int sd, const void *msg, size_t len,
+ ssize_t sctp_sendx __P((int sd, const void *msg, size_t len,
struct sockaddr *addrs, int addrcnt,
struct sctp_sndrcvinfo *sinfo, int flags));
- ssize_t
- sctp_sendmsgx __P((int sd, const void *, size_t,
+
+ ssize_t sctp_sendmsgx __P((int sd, const void *, size_t,
struct sockaddr *, int,
uint32_t, uint32_t, uint16_t, uint32_t, uint32_t));
-sctp_assoc_t
-sctp_getassocid __P((int sd, struct sockaddr *sa));
+ sctp_assoc_t sctp_getassocid __P((int sd, struct sockaddr *sa));
ssize_t sctp_recvmsg __P((int, void *, size_t, struct sockaddr *,
socklen_t *, struct sctp_sndrcvinfo *, int *));
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index c187933..a37da5c 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -110,7 +110,10 @@ sctp_pathmtu_adjustment(struct sctp_inpcb *inp,
/* Adjust that too */
stcb->asoc.smallest_mtu = nxtsz;
/* now off to subtract IP_DF flag if needed */
-
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("sctp_pathmtu_adjust called inp:%p stcb:%p net:%p nxtsz:%d\n",
+ inp, stcb, net, nxtsz);
+#endif
TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
if ((chk->send_size + IP_HDR_SIZE) > nxtsz) {
chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
@@ -201,6 +204,10 @@ sctp_notify_mbuf(struct sctp_inpcb *inp,
}
/* now what about the ep? */
if (stcb->asoc.smallest_mtu > nxtsz) {
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("notify_mbuf (ICMP) calls sctp_pathmtu_adjust mtu:%d\n",
+ nxtsz);
+#endif
sctp_pathmtu_adjustment(inp, stcb, net, nxtsz);
}
if (tmr_stopped)
@@ -513,10 +520,10 @@ sctp_attach(struct socket *so, int proto, struct thread *p)
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 15);
#endif
- SCTP_INP_WUNLOCK(inp);
+ SCTP_INP_WUNLOCK(inp);
sctp_inpcb_free(inp, 1, 0);
} else {
- SCTP_INP_WUNLOCK(inp);
+ SCTP_INP_WUNLOCK(inp);
}
return error;
}
@@ -1234,7 +1241,6 @@ sctp_count_max_addresses(struct sctp_inpcb *inp)
return (cnt);
}
-
static int
sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
size_t optsize, void *p, int delay)
@@ -1243,8 +1249,8 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
int creat_lock_on = 0;
struct sctp_tcb *stcb = NULL;
struct sockaddr *sa;
- int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr, i;
- size_t incr, at;
+ int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
+ int added = 0;
uint32_t vrf_id;
sctp_assoc_t *a_id;
@@ -1281,43 +1287,15 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
totaddrp = (int *)optval;
totaddr = *totaddrp;
sa = (struct sockaddr *)(totaddrp + 1);
- at = incr = 0;
- /* account and validate addresses */
- for (i = 0; i < totaddr; i++) {
- if (sa->sa_family == AF_INET) {
- num_v4++;
- incr = sizeof(struct sockaddr_in);
- } else if (sa->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
-
- sin6 = (struct sockaddr_in6 *)sa;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- /* Must be non-mapped for connectx */
- error = EINVAL;
- goto out_now;
- }
- num_v6++;
- incr = sizeof(struct sockaddr_in6);
- } else {
- totaddr = i;
- break;
- }
- stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
- if (stcb != NULL) {
- /* Already have or am bring up an association */
- SCTP_ASOC_CREATE_UNLOCK(inp);
- creat_lock_on = 0;
- SCTP_TCB_UNLOCK(stcb);
- error = EALREADY;
- goto out_now;
- }
- if ((at + incr) > optsize) {
- totaddr = i;
- break;
- }
- sa = (struct sockaddr *)((caddr_t)sa + incr);
+ stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)));
+ if (stcb != NULL) {
+ /* Already have or am bring up an association */
+ SCTP_ASOC_CREATE_UNLOCK(inp);
+ creat_lock_on = 0;
+ SCTP_TCB_UNLOCK(stcb);
+ error = EALREADY;
+ goto out_now;
}
- sa = (struct sockaddr *)(totaddrp + 1);
#ifdef INET6
if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
(num_v6 > 0)) {
@@ -1356,33 +1334,14 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
/* Gak! no memory */
goto out_now;
}
+ stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
/* move to second address */
if (sa->sa_family == AF_INET)
sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
else
sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
- for (i = 1; i < totaddr; i++) {
- if (sa->sa_family == AF_INET) {
- incr = sizeof(struct sockaddr_in);
- if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
- /* assoc gone no un-lock */
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
- error = ENOBUFS;
- goto out_now;
- }
- } else if (sa->sa_family == AF_INET6) {
- incr = sizeof(struct sockaddr_in6);
- if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
- /* assoc gone no un-lock */
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
- error = ENOBUFS;
- goto out_now;
- }
- }
- sa = (struct sockaddr *)((caddr_t)sa + incr);
- }
- stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
+ added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
/* Fill in the return id */
a_id = (sctp_assoc_t *) optval;
*a_id = sctp_get_associd(stcb);
@@ -3087,8 +3046,13 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) {
net->mtu = paddrp->spp_pathmtu;
- if (net->mtu < stcb->asoc.smallest_mtu)
+ if (net->mtu < stcb->asoc.smallest_mtu) {
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n",
+ net->mtu);
+#endif
sctp_pathmtu_adjustment(inp, stcb, net, net->mtu);
+ }
}
}
if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h
index b5f9ad4..ae68b23 100644
--- a/sys/netinet/sctp_var.h
+++ b/sys/netinet/sctp_var.h
@@ -296,9 +296,6 @@ __P((struct sctp_inpcb *, int, struct sctphdr *,
/* can't use sctp_assoc_t here */
int sctp_peeloff(struct socket *, struct socket *, int, caddr_t, int *);
- sctp_assoc_t sctp_getassocid(struct sockaddr *);
-
-
int sctp_ingetaddr(struct socket *,
struct sockaddr **
);
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index a489184..c9b422e 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -837,7 +837,7 @@ sctp_fill_random_store(struct sctp_pcb *m)
* our counter. The result becomes our good random numbers and we
* then setup to give these out. Note that we do no locking to
* protect this. This is ok, since if competing folks call this we
- * will get more gobbled gook in the random store whic is what we
+ * will get more gobbled gook in the random store which is what we
* want. There is a danger that two guys will use the same random
* numbers, but thats ok too since that is random as well :->
*/
@@ -1025,6 +1025,10 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc,
asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(m->sctp_socket);
asoc->smallest_mtu = m->sctp_frag_point;
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("smallest_mtu init'd with asoc to :%d\n",
+ asoc->smallest_mtu);
+#endif
asoc->minrto = m->sctp_ep.sctp_minrto;
asoc->maxrto = m->sctp_ep.sctp_maxrto;
@@ -2424,6 +2428,10 @@ sctp_mtu_size_reset(struct sctp_inpcb *inp,
struct sctp_tmit_chunk *chk;
unsigned int eff_mtu, ovh;
+#ifdef SCTP_PRINT_FOR_B_AND_M
+ printf("sctp_mtu_size_reset(%p, asoc:%p mtu:%d\n",
+ inp, asoc, mtu);
+#endif
asoc->smallest_mtu = mtu;
if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
ovh = SCTP_MIN_OVERHEAD;
@@ -3207,6 +3215,15 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
/* Can't send up to a closed socket any notifications */
return;
}
+ if (stcb && ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) ||
+ (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED))) {
+ if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) ||
+ (notification == SCTP_NOTIFY_INTERFACE_UP) ||
+ (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) {
+ /* Don't report these in front states */
+ return;
+ }
+ }
if (stcb && (stcb->asoc.assoc_up_sent == 0) && (notification != SCTP_NOTIFY_ASSOC_UP)) {
if ((notification != SCTP_NOTIFY_ASSOC_DOWN) &&
(notification != SCTP_NOTIFY_ASSOC_ABORTED) &&
@@ -3478,7 +3495,8 @@ sctp_abort_notification(struct sctp_tcb *stcb, int error)
void
sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- struct mbuf *m, int iphlen, struct sctphdr *sh, struct mbuf *op_err)
+ struct mbuf *m, int iphlen, struct sctphdr *sh, struct mbuf *op_err,
+ uint32_t vrf_id, uint32_t table_id)
{
uint32_t vtag;
@@ -3487,8 +3505,11 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* We have a TCB to abort, send notification too */
vtag = stcb->asoc.peer_vtag;
sctp_abort_notification(stcb, 0);
+ /* get the assoc vrf id and table id */
+ vrf_id = stcb->asoc.vrf_id;
+ table_id = stcb->asoc.table_id;
}
- sctp_send_abort(m, iphlen, sh, vtag, op_err);
+ sctp_send_abort(m, iphlen, sh, vtag, op_err, vrf_id, table_id);
if (stcb != NULL) {
/* Ok, now lets free it */
sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4);
@@ -3597,7 +3618,8 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
void
sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
- struct sctp_inpcb *inp, struct mbuf *op_err)
+ struct sctp_inpcb *inp, struct mbuf *op_err, uint32_t vrf_id,
+ uint32_t table_id)
{
struct sctp_chunkhdr *ch, chunk_buf;
unsigned int chk_length;
@@ -3631,7 +3653,8 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
*/
return;
case SCTP_SHUTDOWN_ACK:
- sctp_send_shutdown_complete2(m, iphlen, sh);
+ sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id,
+ table_id);
return;
default:
break;
@@ -3640,7 +3663,7 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset,
sizeof(*ch), (uint8_t *) & chunk_buf);
}
- sctp_send_abort(m, iphlen, sh, 0, op_err);
+ sctp_send_abort(m, iphlen, sh, 0, op_err, vrf_id, table_id);
}
/*
@@ -3996,7 +4019,10 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
TAILQ_INSERT_TAIL(&inp->read_queue, control, next);
SCTP_INP_READ_UNLOCK(inp);
if (inp && inp->sctp_socket) {
- sctp_sorwakeup(inp, inp->sctp_socket);
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
+ SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
+ } else
+ sctp_sorwakeup(inp, inp->sctp_socket);
}
}
@@ -4114,7 +4140,10 @@ get_out:
SCTP_INP_READ_UNLOCK(inp);
}
if (inp && inp->sctp_socket) {
- sctp_sorwakeup(inp, inp->sctp_socket);
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
+ SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
+ } else
+ sctp_sorwakeup(inp, inp->sctp_socket);
}
return (0);
}
@@ -4333,11 +4362,11 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock)
}
hash_of_addr = sctp_get_ifa_hash_val(addr);
- hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_hashmark)];
+ hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)];
if (hash_head == NULL) {
printf("hash_of_addr:%x mask:%x table:%x - ",
- (u_int)hash_of_addr, (u_int)vrf->vrf_hashmark,
- (u_int)(hash_of_addr & vrf->vrf_hashmark));
+ (u_int)hash_of_addr, (u_int)vrf->vrf_addr_hashmark,
+ (u_int)(hash_of_addr & vrf->vrf_addr_hashmark));
sctp_print_address(addr);
printf("No such bucket for address\n");
if (holds_lock == 0)
@@ -4519,6 +4548,9 @@ sctp_sorecvmsg(struct socket *so,
int held_length = 0;
int sockbuf_lock = 0;
+ if (uio == NULL) {
+ return (EINVAL);
+ }
if (msg_flags) {
in_flags = *msg_flags;
if (in_flags & MSG_PEEK)
@@ -4526,8 +4558,8 @@ sctp_sorecvmsg(struct socket *so,
} else {
in_flags = 0;
}
- if (uio)
- slen = uio->uio_resid;
+ slen = uio->uio_resid;
+
/* Pull in and set up our int flags */
if (in_flags & MSG_OOB) {
/* Out of band's NOT supported */
@@ -4554,11 +4586,11 @@ sctp_sorecvmsg(struct socket *so,
in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
#ifdef SCTP_RECV_RWND_LOGGING
sctp_misc_ints(SCTP_SORECV_ENTER,
- rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, slen);
+ rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio->uio_resid);
#endif
#ifdef SCTP_RECV_RWND_LOGGING
sctp_misc_ints(SCTP_SORECV_ENTERPL,
- rwnd_req, block_allowed, so->so_rcv.sb_cc, slen);
+ rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid);
#endif
@@ -4593,7 +4625,7 @@ restart_nosblocks:
/* we need to wait for data */
#ifdef SCTP_RECV_DETAIL_RWND_LOGGING
sctp_misc_ints(SCTP_SORECV_BLOCKSA,
- 0, 0, so->so_rcv.sb_cc, slen);
+ 0, 0, so->so_rcv.sb_cc, uio->uio_resid);
#endif
if ((so->so_rcv.sb_cc == 0) &&
((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
@@ -4768,7 +4800,7 @@ restart_nosblocks:
while (ctl) {
if ((ctl->stcb != control->stcb) && (ctl->length) &&
(ctl->some_taken ||
- (ctl->spec_flags & M_NOTIFICATION) ||
+ (ctl->spec_flags & M_NOTIFICATION) ||
((ctl->do_not_ref_stcb == 0) &&
(ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))
) {
@@ -4776,7 +4808,8 @@ restart_nosblocks:
* If we have a different TCB next, and there is data
* present. If we have already taken some (pdapi), OR we can
* ref the tcb and no delivery as started on this stream, we
- * take it.
+ * take it. Note we allow a notification on a different
+ * assoc to be delivered..
*/
control = ctl;
goto found_one;
@@ -4784,7 +4817,7 @@ restart_nosblocks:
(ctl->length) &&
((ctl->some_taken) ||
((ctl->do_not_ref_stcb == 0) &&
-- ((ctl->spec_flags & M_NOTIFICATION) == 0) &&
+ ((ctl->spec_flags & M_NOTIFICATION) == 0) &&
(ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))
) {
/*-
@@ -4792,6 +4825,8 @@ restart_nosblocks:
* have the strm interleave feature present. Then if we have
* taken some (pdapi) or we can refer to tht tcb AND we have
* not started a delivery for this stream, we can take it.
+ * Note we do NOT allow a notificaiton on the same assoc to
+ * be delivered.
*/
control = ctl;
goto found_one;
@@ -4855,8 +4890,8 @@ found_one:
stcb->freed_by_sorcv_sincelast = 0;
}
}
- if (stcb &&
- ((control->spec_flags & M_NOTIFICATION) == 0) &&
+ if (stcb &&
+ ((control->spec_flags & M_NOTIFICATION) == 0) &&
control->do_not_ref_stcb == 0) {
stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1;
}
@@ -5188,6 +5223,10 @@ get_more_data:
control->held_length = 0;
wakeup_read_socket = 1;
}
+ if (control->aux_data) {
+ sctp_m_free(control->aux_data);
+ control->aux_data = NULL;
+ }
no_rcv_needed = control->do_not_ref_stcb;
sctp_free_remote_addr(control->whoFrom);
control->data = NULL;
@@ -5325,199 +5364,48 @@ wait_some_more:
}
goto get_more_data;
} else {
- /* copy out the mbuf chain */
-get_more_data2:
- /*
- * Do we have a uio, I doubt it if so we grab the size from
- * it, if not you get it all
+ /*-
+ * Give caller back the mbuf chain,
+ * store in uio_resid the length
*/
- if (uio)
- cp_len = uio->uio_resid;
- else
- cp_len = control->length;
-
- if ((uint32_t) cp_len >= control->length) {
- /* easy way */
- if ((control->end_added == 0) ||
- (TAILQ_NEXT(control, next) == NULL)) {
- /* Need to get rlock */
- if (hold_rlock == 0) {
- SCTP_INP_READ_LOCK(inp);
- hold_rlock = 1;
- }
- }
- if (control->end_added) {
- out_flags |= MSG_EOR;
- if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0))
- control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
- }
- if (control->spec_flags & M_NOTIFICATION) {
- out_flags |= MSG_NOTIFICATION;
- }
- if (uio)
- uio->uio_resid -= control->length;
- *mp = control->data;
- m = control->data;
- while (m) {
-#ifdef SCTP_SB_LOGGING
- sctp_sblog(&so->so_rcv,
- control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
-#endif
- sctp_sbfree(control, stcb, &so->so_rcv, m);
- freed_so_far += SCTP_BUF_LEN(m);
-#ifdef SCTP_SB_LOGGING
- sctp_sblog(&so->so_rcv,
- control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
-#endif
- m = SCTP_BUF_NEXT(m);
- }
- control->data = control->tail_mbuf = NULL;
- control->length = 0;
- if (out_flags & MSG_EOR) {
- /* Done with this control */
- goto done_with_control;
- }
- /* still more to do with this conntrol */
- /* do we really support msg_waitall here? */
- if ((block_allowed == 0) ||
- ((in_flags & MSG_WAITALL) == 0)) {
- goto release;
- }
- wait_some_more2:
- if (so->so_rcv.sb_state & SBS_CANTRCVMORE)
- goto release;
- if (hold_rlock == 1) {
- SCTP_INP_READ_UNLOCK(inp);
- hold_rlock = 0;
- }
- if (hold_sblock == 0) {
- SOCKBUF_LOCK(&so->so_rcv);
- hold_sblock = 1;
- }
- if (so->so_rcv.sb_cc <= control->held_length) {
- error = sbwait(&so->so_rcv);
- if (error) {
- goto release;
- }
- }
- if (hold_sblock) {
- SOCKBUF_UNLOCK(&so->so_rcv);
- hold_sblock = 0;
- }
- if (control->length == 0) {
- /* still nothing here */
- if (control->end_added == 1) {
- /*
- * he aborted, or is done i.e.
- * shutdown
- */
- out_flags |= MSG_EOR;
- if (control->pdapi_aborted) {
- out_flags |= MSG_TRUNC;
- if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0))
- control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
- }
- goto done_with_control;
- }
- if (so->so_rcv.sb_cc > held_length) {
- control->held_length = so->so_rcv.sb_cc;
- /*
- * We don't use held_length while
- * getting a message
- */
- held_length = 0;
- }
- goto wait_some_more2;
- }
- goto get_more_data2;
- } else {
- /* hard way mbuf by mbuf */
- m = control->data;
- if (control->end_added == 0) {
- /* need the rlock */
- if (hold_rlock == 0) {
- SCTP_INP_READ_LOCK(inp);
- hold_rlock = 1;
- }
- }
- if (control->spec_flags & M_NOTIFICATION) {
- out_flags |= MSG_NOTIFICATION;
+ wakeup_read_socket = 0;
+ if ((control->end_added == 0) ||
+ (TAILQ_NEXT(control, next) == NULL)) {
+ /* Need to get rlock */
+ if (hold_rlock == 0) {
+ SCTP_INP_READ_LOCK(inp);
+ hold_rlock = 1;
}
- while ((m) && (cp_len > 0)) {
- if (cp_len >= SCTP_BUF_LEN(m)) {
- *mp = m;
- atomic_subtract_int(&control->length, SCTP_BUF_LEN(m));
- if (uio)
- uio->uio_resid -= SCTP_BUF_LEN(m);
- cp_len -= SCTP_BUF_LEN(m);
- control->data = SCTP_BUF_NEXT(m);
- SCTP_BUF_NEXT(m) = NULL;
-#ifdef SCTP_SB_LOGGING
- sctp_sblog(&so->so_rcv,
- control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
-#endif
- sctp_sbfree(control, stcb, &so->so_rcv, m);
- freed_so_far += SCTP_BUF_LEN(m);
-#ifdef SCTP_SB_LOGGING
- sctp_sblog(&so->so_rcv,
- control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
-#endif
- mp = &SCTP_BUF_NEXT(m);
- m = control->data;
- } else {
- /*
- * got all he wants and its part of
- * this mbuf only.
- */
- if (uio)
- uio->uio_resid -= SCTP_BUF_LEN(m);
- cp_len -= SCTP_BUF_LEN(m);
- if (hold_rlock) {
- SCTP_INP_READ_UNLOCK(inp);
- hold_rlock = 0;
- }
- if (hold_sblock) {
- SOCKBUF_UNLOCK(&so->so_rcv);
- hold_sblock = 0;
- }
- *mp = SCTP_M_COPYM(m, 0, cp_len,
- M_TRYWAIT
- );
-#ifdef SCTP_LOCK_LOGGING
- sctp_log_lock(inp, stcb, SCTP_LOG_LOCK_SOCKBUF_R);
-#endif
- if (hold_sblock == 0) {
- SOCKBUF_LOCK(&so->so_rcv);
- hold_sblock = 1;
- }
- if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)
- goto release;
-
- if (stcb &&
- stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
- no_rcv_needed = 1;
- }
- SCTP_BUF_RESV_UF(m, cp_len);
- SCTP_BUF_LEN(m) -= cp_len;
+ }
+ if (control->end_added) {
+ out_flags |= MSG_EOR;
+ if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0))
+ control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0;
+ }
+ if (control->spec_flags & M_NOTIFICATION) {
+ out_flags |= MSG_NOTIFICATION;
+ }
+ uio->uio_resid = control->length;
+ *mp = control->data;
+ m = control->data;
+ while (m) {
#ifdef SCTP_SB_LOGGING
- sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, cp_len);
+ sctp_sblog(&so->so_rcv,
+ control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m));
#endif
- freed_so_far += cp_len;
- atomic_subtract_int(&so->so_rcv.sb_cc, cp_len);
- if (stcb) {
- atomic_subtract_int(&stcb->asoc.sb_cc, cp_len);
- if ((freed_so_far >= rwnd_req) &&
- (control->do_not_ref_stcb == 0) &&
- (no_rcv_needed == 0))
- sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req);
- }
+ sctp_sbfree(control, stcb, &so->so_rcv, m);
+ freed_so_far += SCTP_BUF_LEN(m);
#ifdef SCTP_SB_LOGGING
- sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb,
- SCTP_LOG_SBRESULT, 0);
+ sctp_sblog(&so->so_rcv,
+ control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0);
#endif
- goto release;
- }
- }
+ m = SCTP_BUF_NEXT(m);
+ }
+ control->data = control->tail_mbuf = NULL;
+ control->length = 0;
+ if (out_flags & MSG_EOR) {
+ /* Done with this control */
+ goto done_with_control;
}
}
release:
@@ -5670,13 +5558,12 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id)
int
-sctp_soreceive(so, psa, uio, mp0, controlp, flagsp)
- struct socket *so;
- struct sockaddr **psa;
- struct uio *uio;
- struct mbuf **mp0;
- struct mbuf **controlp;
- int *flagsp;
+sctp_soreceive(struct socket *so,
+ struct sockaddr **psa,
+ struct uio *uio,
+ struct mbuf **mp0,
+ struct mbuf **controlp,
+ int *flagsp)
{
int error, fromlen;
uint8_t sockbuf[256];
@@ -5725,3 +5612,155 @@ sctp_soreceive(so, psa, uio, mp0, controlp, flagsp)
}
return (error);
}
+
+
+int
+sctp_l_soreceive(struct socket *so,
+ struct sockaddr **name,
+ struct uio *uio,
+ char **controlp,
+ int *controllen,
+ int *flag)
+{
+ int error, fromlen;
+ uint8_t sockbuf[256];
+ struct sockaddr *from;
+ struct sctp_extrcvinfo sinfo;
+ int filling_sinfo = 1;
+ struct sctp_inpcb *inp;
+
+ inp = (struct sctp_inpcb *)so->so_pcb;
+ /* pickup the assoc we are reading from */
+ if (inp == NULL) {
+ return (EINVAL);
+ }
+ if ((sctp_is_feature_off(inp,
+ SCTP_PCB_FLAGS_RECVDATAIOEVNT)) ||
+ (controlp == NULL)) {
+ /* user does not want the sndrcv ctl */
+ filling_sinfo = 0;
+ }
+ if (name) {
+ from = (struct sockaddr *)sockbuf;
+ fromlen = sizeof(sockbuf);
+ from->sa_len = 0;
+ } else {
+ from = NULL;
+ fromlen = 0;
+ }
+
+ error = sctp_sorecvmsg(so, uio,
+ (struct mbuf **)NULL,
+ from, fromlen, flag,
+ (struct sctp_sndrcvinfo *)&sinfo,
+ filling_sinfo);
+ if ((controlp) && (filling_sinfo)) {
+ /*
+ * copy back the sinfo in a CMSG format note that the caller
+ * has reponsibility for freeing the memory.
+ */
+ if (filling_sinfo)
+ *controlp = sctp_build_ctl_cchunk(inp,
+ controllen,
+ (struct sctp_sndrcvinfo *)&sinfo);
+ }
+ if (name) {
+ /* copy back the address info */
+ if (from && from->sa_len) {
+ *name = sodupsockaddr(from, M_WAIT);
+ } else {
+ *name = NULL;
+ }
+ }
+ return (error);
+}
+
+
+
+
+
+
+
+int
+sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, int totaddr, int *error)
+{
+ int added = 0;
+ int i;
+ struct sctp_inpcb *inp;
+ struct sockaddr *sa;
+ size_t incr = 0;
+
+ sa = addr;
+ inp = stcb->sctp_ep;
+ *error = 0;
+ for (i = 0; i < totaddr; i++) {
+ if (sa->sa_family == AF_INET) {
+ incr = sizeof(struct sockaddr_in);
+ if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+ /* assoc gone no un-lock */
+ sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
+ *error = ENOBUFS;
+ goto out_now;
+ }
+ added++;
+ } else if (sa->sa_family == AF_INET6) {
+ incr = sizeof(struct sockaddr_in6);
+ if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+ /* assoc gone no un-lock */
+ sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
+ *error = ENOBUFS;
+ goto out_now;
+ }
+ added++;
+ }
+ sa = (struct sockaddr *)((caddr_t)sa + incr);
+ }
+out_now:
+ return (added);
+}
+
+struct sctp_tcb *
+sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, int *totaddr,
+ int *num_v4, int *num_v6, int *error, int max)
+{
+ struct sockaddr *sa;
+ struct sctp_tcb *stcb = NULL;
+ size_t incr, at, i;
+
+ at = incr = 0;
+ sa = addr;
+ *error = *num_v6 = *num_v4 = 0;
+ /* account and validate addresses */
+ for (i = 0; i < *totaddr; i++) {
+ if (sa->sa_family == AF_INET) {
+ (*num_v4) += 1;
+ incr = sizeof(struct sockaddr_in);
+ } else if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)sa;
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ /* Must be non-mapped for connectx */
+ *error = EINVAL;
+ return (NULL);
+ }
+ (*num_v6) += 1;
+ incr = sizeof(struct sockaddr_in6);
+ } else {
+ *totaddr = i;
+ /* we are done */
+ break;
+ }
+ stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
+ if (stcb != NULL) {
+ /* Already have or am bring up an association */
+ return (stcb);
+ }
+ if ((at + incr) > max) {
+ *totaddr = i;
+ break;
+ }
+ sa = (struct sockaddr *)((caddr_t)sa + incr);
+ }
+ return ((struct sctp_tcb *)NULL);
+}
diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h
index 3b4acf6..41a5092 100644
--- a/sys/netinet/sctputil.h
+++ b/sys/netinet/sctputil.h
@@ -207,16 +207,23 @@ void sctp_abort_notification(struct sctp_tcb *, int);
/* We abort responding to an IP packet for some reason */
void
sctp_abort_association(struct sctp_inpcb *, struct sctp_tcb *,
- struct mbuf *, int, struct sctphdr *, struct mbuf *);
+ struct mbuf *, int, struct sctphdr *, struct mbuf *, uint32_t, uint32_t);
+
/* We choose to abort via user input */
void
sctp_abort_an_association(struct sctp_inpcb *, struct sctp_tcb *, int,
struct mbuf *);
-void
+void
sctp_handle_ootb(struct mbuf *, int, int, struct sctphdr *,
- struct sctp_inpcb *, struct mbuf *);
+ struct sctp_inpcb *, struct mbuf *, uint32_t, uint32_t);
+
+int sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, int totaddr, int *error);
+
+struct sctp_tcb *
+sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, int *totaddr,
+ int *num_v4, int *num_v6, int *error, int max);
int sctp_is_there_an_abort_here(struct mbuf *, int, uint32_t *);
uint32_t sctp_is_same_scope(struct sockaddr_in6 *, struct sockaddr_in6 *);
@@ -323,6 +330,19 @@ sctp_soreceive(struct socket *so, struct sockaddr **psa,
int *flagsp);
+/* For those not passing mbufs, this does the
+ * translations for you. Caller owns memory
+ * of size controllen returned in controlp.
+ */
+int
+sctp_l_soreceive(struct socket *so,
+ struct sockaddr **name,
+ struct uio *uio,
+ char **controlp,
+ int *controllen,
+ int *flag);
+
+
#ifdef SCTP_STAT_LOGGING
void
sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d);
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index 07cd299..d9c0890 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -69,7 +69,8 @@ sctp6_input(i_pak, offp, proto)
struct sctp_inpcb *in6p = NULL;
struct sctp_nets *net;
int refcount_up = 0;
- uint32_t check, calc_check, vrf_id;
+ uint32_t check, calc_check;
+ uint32_t vrf_id = 0, table_id = 0;
struct inpcb *in6p_ip;
struct sctp_chunkhdr *ch;
int length, mlen, offset, iphlen;
@@ -77,10 +78,17 @@ sctp6_input(i_pak, offp, proto)
struct sctp_tcb *stcb = NULL;
int off = *offp;
- vrf_id = SCTP_DEFAULT_VRFID;
+ /* get the VRF and table id's */
+ if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
+ SCTP_RELEASE_PKT(*i_pak);
+ return (-1);
+ }
+ if (SCTP_GET_PKT_TABLEID(*i_pak, table_id)) {
+ SCTP_RELEASE_PKT(*i_pak);
+ return (-1);
+ }
m = SCTP_HEADER_TO_CHAIN(*i_pak);
-
ip6 = mtod(m, struct ip6_hdr *);
/* Ensure that (sctphdr + sctp_chunkhdr) in a row. */
IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, sizeof(*sh) + sizeof(*ch));
@@ -104,8 +112,7 @@ sctp6_input(i_pak, offp, proto)
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
printf("V6 input gets a packet iphlen:%d pktlen:%d\n", iphlen,
- SCTP_HEADER_LEN((*i_pak))
- );
+ SCTP_HEADER_LEN((*i_pak)));
}
#endif
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
@@ -181,14 +188,16 @@ sctp_skip_csum:
sh->v_tag = init_chk->init.initiate_tag;
}
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
- sctp_send_shutdown_complete2(m, iphlen, sh);
+ sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id,
+ table_id);
goto bad;
}
if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) {
goto bad;
}
if (ch->chunk_type != SCTP_ABORT_ASSOCIATION)
- sctp_send_abort(m, iphlen, sh, 0, NULL);
+ sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id,
+ table_id);
goto bad;
} else if (stcb == NULL) {
refcount_up = 1;
@@ -215,11 +224,11 @@ sctp_skip_csum:
length = ntohs(ip6->ip6_plen) + iphlen;
(void)sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
- in6p, stcb, net, ecn_bits);
+ in6p, stcb, net, ecn_bits, vrf_id, table_id);
/* inp's ref-count reduced && stcb unlocked */
/* XXX this stuff below gets moved to appropriate parts later... */
if (m)
- m_freem(m);
+ sctp_m_freem(m);
if ((in6p) && refcount_up) {
/* reduce ref-count */
SCTP_INP_WLOCK(in6p);
@@ -239,9 +248,10 @@ bad:
SCTP_INP_WUNLOCK(in6p);
}
if (m)
- m_freem(m);
+ sctp_m_freem(m);
/* For BSD/MAC this does nothing */
- SCTP_RELEASE_PAK(*i_pak);
+ SCTP_DETACH_HEADER_FROM_CHAIN(*i_pak);
+ SCTP_RELEASE_HEADER(*i_pak);
return IPPROTO_DONE;
}
@@ -803,7 +813,6 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct thread *p);
-
static int
sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
struct mbuf *control, struct thread *p)
@@ -821,10 +830,10 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
if (control) {
- m_freem(control);
+ SCTP_RELEASE_PKT(control);
control = NULL;
}
- m_freem(m);
+ SCTP_RELEASE_PKT(m);
return EINVAL;
}
in_inp = (struct inpcb *)inp;
@@ -838,9 +847,9 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
goto connected_type;
}
if (addr == NULL) {
- m_freem(m);
+ SCTP_RELEASE_PKT(m);
if (control) {
- m_freem(control);
+ SCTP_RELEASE_PKT(control);
control = NULL;
}
return (EDESTADDRREQ);
@@ -878,7 +887,7 @@ connected_type:
if (control) {
if (inp->control) {
printf("huh? control set?\n");
- m_freem(inp->control);
+ SCTP_RELEASE_PKT(inp->control);
inp->control = NULL;
}
inp->control = control;
OpenPOWER on IntegriCloud