summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_input.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2008-05-20 13:47:46 +0000
committerrrs <rrs@FreeBSD.org>2008-05-20 13:47:46 +0000
commit8a663465644dd0d19159348afb69bb2462822ed1 (patch)
tree2eb09e824f0a51e8694f455f2aa95ba0da7b95d8 /sys/netinet/sctp_input.c
parent2f427637e0af90ccec0c813c87cd3ae5404cedc3 (diff)
downloadFreeBSD-src-8a663465644dd0d19159348afb69bb2462822ed1.zip
FreeBSD-src-8a663465644dd0d19159348afb69bb2462822ed1.tar.gz
- Adds support for the multi-asconf (From Kozuka-san)
- Adds some prepwork (Not all yet) for vimage in particular support the delete the sctppcbinfo.xx structs. There is still a leak in here if it were to be called plus we stil need the regrouping (From Me and Michael Tuexen) - Adds support for UDP tunneling. For BSD there is no socket yet setup so its disabled, but major argument changes are in here to emcompass the passing of the port number (zero when you don't have a udp tunnel, the default for BSD). Will add some hooks in UDP here shortly (discussed with Robert) that will allow easy tunneling. (Mainly from Peter Lei and Michael Tuexen with some BSD work from me :-D) - Some ease for windows, evidently leave is reserved by their compile move label leave: -> out: MFC after: 1 week
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