summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/sctp_input.c')
-rw-r--r--sys/netinet/sctp_input.c104
1 files changed, 63 insertions, 41 deletions
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 4c515f6..694d8ca 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_timer.h>
+#include <netinet/udp.h>
@@ -79,7 +80,7 @@ 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, uint32_t vrf_id)
+ struct sctp_nets *net, int *abort_no_unlock, uint32_t vrf_id, uint16_t port)
{
struct sctp_init *init;
struct mbuf *op_err;
@@ -113,7 +114,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
* state :-)
*/
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
- vrf_id);
+ vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@@ -122,7 +123,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* Invalid length */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
- vrf_id);
+ vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@@ -132,7 +133,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* protocol error... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
- vrf_id);
+ vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@@ -141,7 +142,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* invalid parameter... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
- vrf_id);
+ vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@@ -150,7 +151,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* protocol error... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
- vrf_id);
+ vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@@ -159,7 +160,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
/* protocol error... send abort */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(inp, stcb, m, iphlen, sh, op_err,
- vrf_id);
+ vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
@@ -168,14 +169,14 @@ 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, vrf_id);
+ sctp_abort_association(inp, stcb, m, iphlen, sh, NULL, vrf_id, port);
if (stcb)
*abort_no_unlock = 1;
goto outnow;
}
/* send an INIT-ACK w/cookie */
SCTPDBG(SCTP_DEBUG_INPUT3, "sctp_handle_init: sending INIT-ACK\n");
- sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, sh, cp, vrf_id,
+ sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, sh, cp, vrf_id, port,
((stcb == NULL) ? SCTP_HOLDS_LOCK : SCTP_NOT_LOCKED));
outnow:
if (stcb == NULL) {
@@ -422,7 +423,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
"Load addresses from INIT causes an abort %d\n",
retval);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
- NULL, 0);
+ NULL, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@@ -497,7 +498,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, 0);
+ sh, op_err, 0, net->port);
*abort_no_unlock = 1;
}
return (retval);
@@ -1105,7 +1106,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
/* Invalid length */
op_err = sctp_generate_invmanparam(SCTP_CAUSE_INVALID_PARAM);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen, sh,
- op_err, 0);
+ op_err, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@@ -1115,7 +1116,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
/* 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, 0);
+ op_err, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@@ -1123,7 +1124,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
/* 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, 0);
+ op_err, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@@ -1131,7 +1132,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
/* 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, 0);
+ op_err, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@@ -1139,7 +1140,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
/* 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, 0);
+ op_err, 0, net->port);
*abort_no_unlock = 1;
return (-1);
}
@@ -1269,7 +1270,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
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,
- vrf_id);
+ vrf_id, net->port);
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 2;
return (NULL);
@@ -1646,6 +1647,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
ntohs(initack_cp->init.num_outbound_streams);
asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn);
asoc->sending_seq = asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number;
+ asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
asoc->last_cwr_tsn = asoc->init_seq_number - 1;
asoc->asconf_seq_in = asoc->last_acked_seq = asoc->init_seq_number - 1;
@@ -1749,7 +1751,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
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,
- uint32_t vrf_id)
+ uint32_t vrf_id, uint16_t port)
{
struct sctp_tcb *stcb;
struct sctp_init_chunk *init_cp, init_buf;
@@ -1841,7 +1843,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, vrf_id);
+ sh, op_err, vrf_id, port);
return (NULL);
}
/* get the correct sctp_nets */
@@ -1867,7 +1869,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
atomic_add_int(&stcb->asoc.refcnt, 1);
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
- sh, op_err, vrf_id);
+ sh, op_err, vrf_id, port);
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_LOCK(so, 1);
@@ -1888,6 +1890,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
asoc->pre_open_streams = ntohs(initack_cp->init.num_outbound_streams);
asoc->init_seq_number = ntohl(initack_cp->init.initial_tsn);
asoc->sending_seq = asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number;
+ asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1;
asoc->last_cwr_tsn = asoc->init_seq_number - 1;
asoc->asconf_seq_in = asoc->last_acked_seq = asoc->init_seq_number - 1;
asoc->str_reset_seq_in = asoc->init_seq_number;
@@ -2095,7 +2098,7 @@ 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, uint32_t vrf_id)
+ struct sctp_tcb **locked_tcb, uint32_t vrf_id, uint16_t port)
{
struct sctp_state_cookie *cookie;
struct sockaddr_in6 sin6;
@@ -2329,7 +2332,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
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,
- vrf_id);
+ vrf_id, port);
return (NULL);
}
/*
@@ -2409,7 +2412,7 @@ 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, vrf_id);
+ auth_skipped, auth_offset, auth_len, vrf_id, port);
} else {
/* this is abnormal... cookie-echo on existing TCB */
had_a_existing_tcb = 1;
@@ -2489,7 +2492,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
SCTPDBG(SCTP_DEBUG_INPUT1, "process_cookie_new: no room for another socket!\n");
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(*inp_p, NULL, m, iphlen,
- sh, op_err, vrf_id);
+ sh, op_err, vrf_id, port);
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
pcb_so = SCTP_INP_SO(*inp_p);
atomic_add_int(&(*stcb)->asoc.refcnt, 1);
@@ -3814,7 +3817,7 @@ __attribute__((noinline))
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,
- uint32_t vrf_id)
+ uint32_t vrf_id, uint16_t port)
{
struct sctp_association *asoc;
uint32_t vtag_in;
@@ -3968,7 +3971,7 @@ __attribute__((noinline))
if (stcb == NULL) {
/* no association, so it's out of the blue... */
sctp_handle_ootb(m, iphlen, *offset, sh, inp, NULL,
- vrf_id);
+ vrf_id, port);
*offset = length;
if (locked_tcb) {
SCTP_TCB_UNLOCK(locked_tcb);
@@ -4005,7 +4008,7 @@ __attribute__((noinline))
SCTP_TCB_UNLOCK(locked_tcb);
}
sctp_handle_ootb(m, iphlen, *offset, sh, inp,
- NULL, vrf_id);
+ NULL, vrf_id, port);
return (NULL);
}
} else {
@@ -4182,7 +4185,7 @@ process_control_chunks:
if (netp) {
sctp_handle_init(m, iphlen, *offset, sh,
(struct sctp_init_chunk *)ch, inp,
- stcb, *netp, &abort_no_unlock, vrf_id);
+ stcb, *netp, &abort_no_unlock, vrf_id, port);
}
if (abort_no_unlock)
return (NULL);
@@ -4448,7 +4451,7 @@ process_control_chunks:
htons(sizeof(struct sctp_paramhdr));
}
sctp_abort_association(inp, stcb, m,
- iphlen, sh, oper, vrf_id);
+ iphlen, sh, oper, vrf_id, port);
}
*offset = length;
return (NULL);
@@ -4475,7 +4478,8 @@ process_control_chunks:
auth_offset,
auth_len,
&locked_tcb,
- vrf_id);
+ vrf_id,
+ port);
} else {
ret_buf = NULL;
}
@@ -4984,7 +4988,7 @@ void
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, uint32_t vrf_id)
+ uint8_t ecn_bits, uint32_t vrf_id, uint16_t port)
{
/*
* Control chunk processing
@@ -5020,7 +5024,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
*/
SCTP_TCB_UNLOCK(stcb);
sctp_handle_ootb(m, iphlen, offset, sh, inp, NULL,
- vrf_id);
+ vrf_id, port);
goto out_now;
}
}
@@ -5028,7 +5032,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset,
/* process the control portion of the SCTP packet */
/* sa_ignore NO_NULL_CHK */
stcb = sctp_process_control(m, iphlen, &offset, length, sh, ch,
- inp, stcb, &net, &fwd_tsn_seen, vrf_id);
+ inp, stcb, &net, &fwd_tsn_seen, vrf_id, port);
if (stcb) {
/*
* This covers us if the cookie-echo was there and
@@ -5058,7 +5062,7 @@ 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,
- vrf_id);
+ vrf_id, port);
goto out_now;
}
if (stcb->asoc.my_vtag != ntohl(sh->v_tag)) {
@@ -5126,7 +5130,7 @@ 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,
- vrf_id);
+ vrf_id, port);
SCTP_TCB_UNLOCK(stcb);
goto out_now;
/* sa_ignore NOTREACHED */
@@ -5221,12 +5225,11 @@ out_now:
}
-
void
-sctp_input(i_pak, off)
+sctp_input_with_port(i_pak, off, port)
struct mbuf *i_pak;
int off;
-
+ uint16_t port;
{
#ifdef SCTP_MBUF_LOGGING
struct mbuf *mat;
@@ -5329,6 +5332,12 @@ sctp_input(i_pak, off)
offset - sizeof(*ch),
sh, ch, &inp, &net,
vrf_id);
+ if ((net) && (port)) {
+ if (net->port == 0) {
+ sctp_pathmtu_adjustment(inp, stcb, net, net->mtu - sizeof(struct udphdr));
+ }
+ net->port = port;
+ }
if ((inp) && (stcb)) {
sctp_send_packet_dropped(stcb, net, m, iphlen, 1);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
@@ -5357,6 +5366,12 @@ sctp_skip_csum_4:
*/
stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
sh, ch, &inp, &net, vrf_id);
+ if ((net) && (port)) {
+ if (net->port == 0) {
+ sctp_pathmtu_adjustment(inp, stcb, net, net->mtu - sizeof(struct udphdr));
+ }
+ net->port = port;
+ }
/* inp's ref-count increased && stcb locked */
if (inp == NULL) {
struct sctp_init_chunk *init_chk, chunk_buf;
@@ -5386,14 +5401,14 @@ 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, vrf_id);
+ sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id, port);
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, vrf_id);
+ sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id, port);
goto bad;
} else if (stcb == NULL) {
refcount_up = 1;
@@ -5420,7 +5435,7 @@ sctp_skip_csum_4:
/* sa_ignore NO_NULL_CHK */
sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
- inp, stcb, net, ecn_bits, vrf_id);
+ inp, stcb, net, ecn_bits, vrf_id, port);
/* inp's ref-count reduced && stcb unlocked */
if (m) {
sctp_m_freem(m);
@@ -5443,3 +5458,10 @@ bad:
}
return;
}
+void
+sctp_input(i_pak, off)
+ struct mbuf *i_pak;
+ int off;
+{
+ sctp_input_with_port(i_pak, off, 0);
+}
OpenPOWER on IntegriCloud