- Somehow the disable fragment option got lost. We could

set/clear it but would not do it. Now we will.
-  Moved to latest socket api for extended sndrcv info struct.
-  Moved to support all new levels of fragment interleave (0-2).
-  Codenomicon security test updates - length checks and such.
-  Bug in stream reset (2 actually).
-  setpeerprimary could unlock a null pointer, fixed.
-  Added a flag in the pcb so netstat can see if we are listening easier.

Obtained from:	(some of the Listen changes from Weongyo Jeong)
This commit is contained in:
Randall Stewart 2007-05-02 12:50:13 +00:00
parent d562befcdd
commit d06c82f169
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=169208
18 changed files with 568 additions and 358 deletions

View File

@ -400,6 +400,7 @@ struct sctp_error_unrecognized_chunk {
#define SCTP_PCB_FLAGS_BOUNDALL 0x00000004
#define SCTP_PCB_FLAGS_ACCEPTING 0x00000008
#define SCTP_PCB_FLAGS_UNBOUND 0x00000010
#define SCTP_PCB_FLAGS_LISTENING 0x00000020
#define SCTP_PCB_FLAGS_CLOSE_IP 0x00040000
#define SCTP_PCB_FLAGS_WAS_CONNECTED 0x00080000
#define SCTP_PCB_FLAGS_WAS_ABORTED 0x00100000

View File

@ -1440,7 +1440,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(random_store))
break;
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)random_store, plen);
(struct sctp_paramhdr *)random_store, min(plen, sizeof(random_store)));
if (phdr == NULL)
return;
/* save the random and length for the key */
@ -1453,7 +1453,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(hmacs_store))
break;
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)hmacs_store, plen);
(struct sctp_paramhdr *)hmacs_store, min(plen, sizeof(hmacs_store)));
if (phdr == NULL)
return;
/* save the hmacs list and num for the key */
@ -1475,7 +1475,7 @@ sctp_auth_get_cookie_params(struct sctp_tcb *stcb, struct mbuf *m,
if (plen > sizeof(chunks_store))
break;
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)chunks_store, plen);
(struct sctp_paramhdr *)chunks_store, min(plen, sizeof(chunks_store)));
if (phdr == NULL)
return;
chunks = (struct sctp_auth_chunk_list *)phdr;
@ -1850,7 +1850,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
int num_ent, i;
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)&local_store, plen);
(struct sctp_paramhdr *)&local_store, min(plen, sizeof(local_store)));
if (phdr == NULL) {
return (-1);
}
@ -1889,7 +1889,7 @@ sctp_validate_init_auth_params(struct mbuf *m, int offset, int limit)
if (plen > sizeof(store))
break;
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)store, plen);
(struct sctp_paramhdr *)store, min(plen, sizeof(store)));
if (phdr == NULL)
return (-1);
hmacs = (struct sctp_auth_hmac_algo *)phdr;

View File

@ -44,14 +44,10 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctputil.h>
#include <netinet/sctp_timer.h>
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_sysctl.h>
#include <netinet/sctp_indata.h>
#include <sys/unistd.h>
#ifdef SCTP_DEBUG
extern uint32_t sctp_debug_on;
#endif
#if defined(SCTP_USE_THREAD_BASED_ITERATOR)
void
@ -211,7 +207,7 @@ sctp_init_ifns_for_vrf(int vrfid)
ifn->if_xname,
(void *)ifa,
ifa->ifa_addr,
ifa_flags
ifa_flags, 0
);
if (sctp_ifa) {
sctp_ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
@ -245,7 +241,6 @@ static uint8_t first_time = 0;
void
sctp_addr_change(struct ifaddr *ifa, int cmd)
{
struct sctp_laddr *wi;
struct sctp_ifa *ifap = NULL;
uint32_t ifa_flags = 0;
struct in6_ifaddr *ifa6;
@ -293,58 +288,53 @@ sctp_addr_change(struct ifaddr *ifa, int cmd)
ifap = sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp,
ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type,
ifa->ifa_ifp->if_xname,
(void *)ifa, ifa->ifa_addr, ifa_flags);
/*
* Bump up the refcount so that when the timer completes it
* will drop back down.
*/
if (ifap)
atomic_add_int(&ifap->refcount, 1);
(void *)ifa, ifa->ifa_addr, ifa_flags, 1);
} else if (cmd == RTM_DELETE) {
ifap = sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, ifa->ifa_ifp->if_index);
sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, ifa->ifa_ifp->if_index);
/*
* We don't bump refcount here so when it completes the
* final delete will happen.
*/
}
if (ifap == NULL)
return;
wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
if (wi == NULL) {
/*
* Gak, what can we do? We have lost an address change can
* you say HOSED?
*/
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_PCB1) {
printf("Lost and address change ???\n");
}
#endif /* SCTP_DEBUG */
/* Opps, must decrement the count */
sctp_free_ifa(ifap);
return;
}
SCTP_INCR_LADDR_COUNT();
bzero(wi, sizeof(*wi));
wi->ifa = ifap;
if (cmd == RTM_ADD) {
wi->action = SCTP_ADD_IP_ADDRESS;
} else if (cmd == RTM_DELETE) {
wi->action = SCTP_DEL_IP_ADDRESS;
}
SCTP_IPI_ITERATOR_WQ_LOCK();
/*
* Should this really be a tailq? As it is we will process the
* newest first :-0
*/
LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr);
sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
(struct sctp_inpcb *)NULL,
(struct sctp_tcb *)NULL,
(struct sctp_nets *)NULL);
SCTP_IPI_ITERATOR_WQ_UNLOCK();
}
struct mbuf *
sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header,
int how, int allonebuf, int type)
{
struct mbuf *m = NULL;
m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0);
if (m == NULL) {
/* bad, no memory */
return (m);
}
if (allonebuf) {
int siz;
if (SCTP_BUF_IS_EXTENDED(m)) {
siz = SCTP_BUF_EXTEND_SIZE(m);
} else {
if (want_header)
siz = MHLEN;
else
siz = MLEN;
}
if (siz < space_needed) {
m_freem(m);
return (NULL);
}
}
if (SCTP_BUF_NEXT(m)) {
sctp_m_freem(SCTP_BUF_NEXT(m));
SCTP_BUF_NEXT(m) = NULL;
}
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BUF_IS_EXTENDED(m)) {
sctp_log_mb(m, SCTP_MBUF_IALLOC);
}
#endif
return (m);
}

View File

@ -196,7 +196,10 @@ __FBSDID("$FreeBSD$");
#define SCTP_FLIGHT_LOG_UP_REVOKE 113
#define SCTP_FLIGHT_LOG_DOWN_PDRP 114
#define SCTP_FLIGHT_LOG_DOWN_PMTU 115
#define SCTP_LOG_MAX_TYPES 116
#define SCTP_SACK_LOG_NORMAL 116
#define SCTP_SACK_LOG_EXPRESS 117
#define SCTP_LOG_MAX_TYPES 118
/*
* To turn on various logging, you must first define SCTP_STAT_LOGGING. Then
* to get something to log you define one of the logging defines i.e.

View File

@ -64,13 +64,17 @@ struct sctp_cookie_perserve_param {
};
#define SCTP_ARRAY_MIN_LEN 1
/* Host Name Address */
struct sctp_host_name_param {
struct sctp_paramhdr ph;/* type=SCTP_HOSTNAME_ADDRESS */
char name[SCTP_ARRAY_MIN_LEN]; /* host name */
};
/*
* This is the maximum padded size of a s-a-p
* so paramheadr + 3 address types (6 bytes) + 2 byte pad = 12
*/
#define SCTP_MAX_ADDR_PARAMS_SIZE 12
/* supported address type */
struct sctp_supported_addr_param {
struct sctp_paramhdr ph;/* type=SCTP_SUPPORTED_ADDRTYPE */
@ -121,6 +125,8 @@ struct sctp_asconf_addrv4_param { /* an ASCONF address (v4) parameter */
struct sctp_ipv4addr_param addrp; /* max storage size */
};
#define SCTP_MAX_SUPPORTED_EXT 256
struct sctp_supported_chunk_types_param {
struct sctp_paramhdr ph;/* type = 0x8008 len = x */
uint8_t chunk_types[0];
@ -490,6 +496,9 @@ struct sctp_stream_reset_resp_tsn {
/*
* Authenticated chunks support draft-ietf-tsvwg-sctp-auth
*/
/* Should we make the max be 32? */
#define SCTP_RANDOM_MAX_SIZE 256
struct sctp_auth_random {
struct sctp_paramhdr ph;/* type = 0x8002 */
uint8_t random_data[0];

View File

@ -1595,6 +1595,18 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
sctp_queue_op_err(stcb, mb);
}
SCTP_STAT_INCR(sctps_badsid);
SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) {
/* we have a new high score */
asoc->highest_tsn_inside_map = tsn;
#ifdef SCTP_MAP_LOGGING
sctp_log_map(0, 2, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
#endif
}
if (tsn == (asoc->cumulative_tsn + 1)) {
/* Update cum-ack */
asoc->cumulative_tsn = tsn;
}
return (0);
}
/*
@ -1631,10 +1643,6 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
asoc->strmin[strmno].last_sequence_delivered);
}
#endif
/*
* throw it in the stream so it gets cleaned up in
* association destruction
*/
oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + 3 * sizeof(uint32_t)),
0, M_DONTWAIT, 1, MT_DATA);
if (oper) {
@ -2014,7 +2022,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
struct sctp_stream_reset_list *liste;
if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
((compare_with_wrap(tsn, liste->tsn, MAX_TSN)) ||
((compare_with_wrap(tsn, ntohl(liste->tsn), MAX_TSN)) ||
(tsn == ntohl(liste->tsn)))
) {
/*
@ -2181,6 +2189,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
all_ones = 1;
at = 0;
for (i = 0; i < stcb->asoc.mapping_array_size; i++) {
if (asoc->mapping_array[i] == 0xff) {
at += 8;
last_all_ones = 1;
@ -2294,8 +2303,8 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
}
/* check the special flag for stream resets */
if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
((compare_with_wrap(asoc->cumulative_tsn, liste->tsn, MAX_TSN)) ||
(asoc->cumulative_tsn == liste->tsn))
((compare_with_wrap(asoc->cumulative_tsn, ntohl(liste->tsn), MAX_TSN)) ||
(asoc->cumulative_tsn == ntohl(liste->tsn)))
) {
/*
* we have finished working through the backlogged TSN's now
@ -2322,7 +2331,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
}
} else if (ctl) {
/* more than one in queue */
while (!compare_with_wrap(ctl->sinfo_tsn, liste->tsn, MAX_TSN)) {
while (!compare_with_wrap(ctl->sinfo_tsn, ntohl(liste->tsn), MAX_TSN)) {
/*
* if ctl->sinfo_tsn is <= liste->tsn we can
* process it which is the NOT of
@ -2522,12 +2531,13 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
*/
asoc->last_data_chunk_from = net;
/*
/*-
* Now before we proceed we must figure out if this is a wasted
* cluster... i.e. it is a small packet sent in and yet the driver
* underneath allocated a full cluster for it. If so we must copy it
* to a smaller mbuf and free up the cluster mbuf. This will help
* with cluster starvation.
* with cluster starvation. Note for __Panda__ we don't do this
* since it has clusters all the way down to 64 bytes.
*/
if (SCTP_BUF_LEN(m) < (long)MLEN && SCTP_BUF_NEXT(m) == NULL) {
/* we only handle mbufs that are singletons.. not chains */
@ -3082,6 +3092,11 @@ sctp_check_for_revoked(struct sctp_tcb *stcb,
* time i.e. revoked. If it is MARKED it was ACK'ed
* again.
*/
if (compare_with_wrap(tp1->rec.data.TSN_seq, biggest_tsn_acked,
MAX_TSN))
break;
if (tp1->sent == SCTP_DATAGRAM_ACKED) {
/* it has been revoked */
tp1->sent = SCTP_DATAGRAM_SENT;
@ -4148,13 +4163,32 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
uint32_t old_rwnd;
int win_probe_recovery = 0;
int win_probe_recovered = 0;
int j, done_once;;
int j, done_once = 0;
#ifdef SCTP_LOG_SACK_ARRIVALS
sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack,
rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
#endif
SCTP_TCB_LOCK_ASSERT(stcb);
asoc = &stcb->asoc;
old_rwnd = asoc->peers_rwnd;
if (compare_with_wrap(asoc->last_acked_seq, cumack, MAX_TSN)) {
/* old ack */
return;
} else if (asoc->last_acked_seq == cumack) {
/* Window update sack */
asoc->peers_rwnd = sctp_sbspace_sub(rwnd,
(uint32_t) (asoc->total_flight + (asoc->sent_queue_cnt * sctp_peer_chunk_oh)));
if (asoc->peers_rwnd < stcb->sctp_ep->sctp_ep.sctp_sws_sender) {
/* SWS sender side engages */
asoc->peers_rwnd = 0;
}
if (asoc->peers_rwnd > old_rwnd) {
goto again;
}
return;
}
/* First setup for CC stuff */
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
@ -4210,7 +4244,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
#endif
}
}
old_rwnd = asoc->peers_rwnd;
asoc->this_sack_highest_gap = cumack;
stcb->asoc.overall_error_count = 0;
if (compare_with_wrap(cumack, asoc->last_acked_seq, MAX_TSN)) {
@ -4411,7 +4444,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
win_probe_recovery = 1;
}
/* Now assure a timer where data is queued at */
done_once = 0;
again:
j = 0;
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
@ -4574,7 +4606,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
void
sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
struct sctp_nets *net_from, int *abort_now)
struct sctp_nets *net_from, int *abort_now, int sack_len, uint32_t rwnd)
{
struct sctp_association *asoc;
struct sctp_sack *sack;
@ -4624,22 +4656,18 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
/* CMT DAC algo */
this_sack_lowest_newack = 0;
j = 0;
sack_length = ntohs(ch->ch.chunk_length);
if (sack_length < sizeof(struct sctp_sack_chunk)) {
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_INDATA1) {
printf("Bad size on sack chunk .. to small\n");
}
#endif
return;
}
sack_length = (unsigned int)sack_len;
/* ECN Nonce */
SCTP_STAT_INCR(sctps_slowpath_sack);
nonce_sum_flag = ch->ch.chunk_flags & SCTP_SACK_NONCE_SUM;
cum_ack = last_tsn = ntohl(sack->cum_tsn_ack);
num_seg = ntohs(sack->num_gap_ack_blks);
a_rwnd = (uint32_t) ntohl(sack->a_rwnd);
a_rwnd = rwnd;
#ifdef SCTP_LOG_SACK_ARRIVALS
sctp_misc_ints(SCTP_SACK_LOG_NORMAL, cum_ack,
rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
#endif
/* CMT DAC algo */
cmt_dac_flag = ch->ch.chunk_flags & SCTP_SACK_CMT_DAC;
num_dup = ntohs(sack->num_dup_tsns);

View File

@ -91,7 +91,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
void
sctp_handle_sack(struct sctp_sack_chunk *, struct sctp_tcb *,
struct sctp_nets *, int *);
struct sctp_nets *, int *, int, uint32_t);
/* draft-ietf-tsvwg-usctp */
void
@ -109,7 +109,8 @@ sctp_update_acked(struct sctp_tcb *, struct sctp_shutdown_chunk *,
int
sctp_process_data(struct mbuf **, int, int *, int, struct sctphdr *,
struct sctp_inpcb *, struct sctp_tcb *, struct sctp_nets *, uint32_t *);
struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *, uint32_t *);
void sctp_sack_check(struct sctp_tcb *, int, int, int *);

View File

@ -2231,7 +2231,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
* another and get the tcb in the right place.
*/
sctp_move_pcb_and_assoc(*inp_p, inp, *stcb);
sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb);
sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb, M_NOWAIT);
/*
* now we must check to see if we were aborted while
@ -2798,9 +2798,11 @@ sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chu
asoc = &stcb->asoc;
if (TAILQ_EMPTY(&stcb->asoc.control_send_queue)) {
asoc->stream_reset_outstanding = 0;
return (NULL);
}
if (stcb->asoc.str_reset == NULL) {
asoc->stream_reset_outstanding = 0;
return (NULL);
}
chk = stcb->asoc.str_reset;
@ -3154,6 +3156,7 @@ sctp_handle_stream_reset(struct sctp_tcb *stcb, struct sctp_stream_reset_out_req
return (ret_code);
}
chk->rec.chunk_id.id = SCTP_STREAM_RESET;
chk->rec.chunk_id.can_take_data = 0;
chk->asoc = &stcb->asoc;
chk->no_fr_allowed = 0;
chk->book_size = chk->send_size = sizeof(struct sctp_chunkhdr);
@ -3181,7 +3184,6 @@ sctp_handle_stream_reset(struct sctp_tcb *stcb, struct sctp_stream_reset_out_req
ch->chunk_flags = 0;
ch->chunk_length = htons(chk->send_size);
SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size);
ph = (struct sctp_paramhdr *)&sr_req->sr_req;
while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) {
param_len = ntohs(ph->param_length);
@ -3726,7 +3728,8 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
* because we don't have to process the peer's COOKIE. All
* others get a complete chunk.
*/
if (ch->chunk_type == SCTP_INITIATION_ACK) {
if ((ch->chunk_type == SCTP_INITIATION_ACK) ||
(ch->chunk_type == SCTP_INITIATION)) {
/* get an init-ack chunk */
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
sizeof(struct sctp_init_ack_chunk), chunk_buf);
@ -3736,6 +3739,29 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
SCTP_TCB_UNLOCK(locked_tcb);
return (NULL);
}
} else if (ch->chunk_type == SCTP_COOKIE_ECHO) {
if (chk_length > sizeof(chunk_buf)) {
/*
* use just the size of the chunk buffer so
* the front part of our cookie is intact.
* The rest of cookie processing should use
* the sctp_m_getptr() function to access
* the other parts.
*/
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
(sizeof(chunk_buf) - 4),
chunk_buf);
if (ch == NULL) {
*offset = length;
if (locked_tcb)
SCTP_TCB_UNLOCK(locked_tcb);
return (NULL);
}
} else {
/* We can fit it all */
goto all_fits;
}
} else {
/* get a complete chunk... */
if ((size_t)chk_length > sizeof(chunk_buf)) {
@ -3743,21 +3769,25 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
struct sctp_paramhdr *phdr;
oper = NULL;
oper = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
0, M_DONTWAIT, 1, MT_DATA);
if (oper) {
/* pre-reserve some space */
SCTP_BUF_RESV_UF(oper, sizeof(struct sctp_chunkhdr));
SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr);
phdr = mtod(oper, struct sctp_paramhdr *);
phdr->param_type = htons(SCTP_CAUSE_OUT_OF_RESC);
phdr->param_length = htons(sizeof(struct sctp_paramhdr));
sctp_queue_op_err(stcb, oper);
if (stcb) {
oper = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr),
0, M_DONTWAIT, 1, MT_DATA);
if (oper) {
/* pre-reserve some space */
SCTP_BUF_RESV_UF(oper, sizeof(struct sctp_chunkhdr));
SCTP_BUF_LEN(oper) = sizeof(struct sctp_paramhdr);
phdr = mtod(oper, struct sctp_paramhdr *);
phdr->param_type = htons(SCTP_CAUSE_OUT_OF_RESC);
phdr->param_length = htons(sizeof(struct sctp_paramhdr));
sctp_queue_op_err(stcb, oper);
}
}
if (locked_tcb)
SCTP_TCB_UNLOCK(locked_tcb);
return (NULL);
}
all_fits:
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
chk_length, chunk_buf);
if (ch == NULL) {
@ -3902,8 +3932,16 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
uint16_t num_seg;
int nonce_sum_flag;
if (chk_length < sizeof(struct sctp_sack_chunk)) {
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_INDATA1) {
printf("Bad size on sack chunk .. to small\n");
}
#endif
*offset = length;
return (NULL);
}
sack = (struct sctp_sack_chunk *)ch;
nonce_sum_flag = ch->chunk_flags & SCTP_SACK_NONCE_SUM;
cum_ack = ntohl(sack->sack.cum_tsn_ack);
num_seg = ntohs(sack->sack.num_gap_ack_blks);
@ -3925,9 +3963,10 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
* with no missing segments to go
* this way too.
*/
sctp_express_handle_sack(stcb, cum_ack, a_rwnd, nonce_sum_flag, &abort_now);
sctp_express_handle_sack(stcb, cum_ack, a_rwnd, nonce_sum_flag,
&abort_now);
} else {
sctp_handle_sack(sack, stcb, *netp, &abort_now);
sctp_handle_sack(sack, stcb, *netp, &abort_now, chk_length, a_rwnd);
}
if (abort_now) {
/* ABORT signal from sack processing */
@ -3955,7 +3994,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
printf("SCTP_HEARTBEAT-ACK\n");
}
#endif /* SCTP_DEBUG */
if (chk_length != sizeof(struct sctp_heartbeat_chunk)) {
/* Its not ours */
*offset = length;
return (NULL);
}
/* He's alive so give him credit */
stcb->asoc.overall_error_count = 0;
SCTP_STAT_INCR(sctps_recvheartbeatack);
@ -3979,7 +4022,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
printf("SCTP_SHUTDOWN\n");
}
#endif /* SCTP_DEBUG */
{
if (chk_length != sizeof(struct sctp_shutdown_chunk)) {
*offset = length;
return (NULL);
} {
int abort_flag = 0;
sctp_handle_shutdown((struct sctp_shutdown_chunk *)ch,
@ -4162,6 +4209,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
#endif /* SCTP_DEBUG */
/* He's alive so give him credit */
if (chk_length != sizeof(struct sctp_ecne_chunk)) {
/* Its not ours */
*offset = length;
return (NULL);
}
stcb->asoc.overall_error_count = 0;
sctp_handle_ecn_echo((struct sctp_ecne_chunk *)ch,
stcb);
@ -4173,6 +4225,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
#endif /* SCTP_DEBUG */
/* He's alive so give him credit */
if (chk_length != sizeof(struct sctp_cwr_chunk)) {
/* Its not ours */
*offset = length;
return (NULL);
}
stcb->asoc.overall_error_count = 0;
sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb);
@ -4215,6 +4272,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
printf("SCTP_ASCONF-ACK\n");
}
#endif /* SCTP_DEBUG */
if (chk_length < sizeof(struct sctp_asconf_ack_chunk)) {
/* Its not ours */
*offset = length;
return (NULL);
}
/* He's alive so give him credit */
stcb->asoc.overall_error_count = 0;
@ -4227,6 +4289,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
printf("SCTP_FWD-TSN\n");
}
#endif /* SCTP_DEBUG */
if (chk_length < sizeof(struct sctp_forward_tsn_chunk)) {
/* Its not ours */
*offset = length;
return (NULL);
}
/* He's alive so give him credit */
{
int abort_flag = 0;
@ -4258,6 +4325,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
#endif /* SCTP_DEBUG */
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
chk_length, chunk_buf);
if (chk_length < sizeof(struct sctp_stream_reset_tsn_req)) {
/* Its not ours */
*offset = length;
return (NULL);
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */
sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_29);
@ -4285,6 +4357,11 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
#endif /* SCTP_DEBUG */
/* re-get it all please */
if (chk_length < sizeof(struct sctp_pktdrop_chunk)) {
/* Its not ours */
*offset = length;
return (NULL);
}
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
chk_length, chunk_buf);
@ -4312,6 +4389,12 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
/* skip this chunk (temporarily) */
goto next_chunk;
}
if ((chk_length < (sizeof(struct sctp_auth_chunk))) ||
(chk_length > (sizeof(struct sctp_auth_chunk) + SCTP_AUTH_DIGEST_LEN_MAX))) {
/* Its not ours */
*offset = length;
return (NULL);
}
if (got_auth == 1) {
/* skip this chunk... it's already auth'd */
goto next_chunk;
@ -4902,5 +4985,7 @@ sctp_input(i_pak, off)
if (m) {
sctp_m_freem(m);
}
/* For BSD/MAC this does nothing */
SCTP_RELEASE_PAK(i_pak);
return;
}

View File

@ -226,6 +226,7 @@ typedef struct callout sctp_os_timer_t;
#define SCTP_HEADER_TO_CHAIN(m) (m)
#define SCTP_HEADER_LEN(m) (m->m_pkthdr.len)
#define SCTP_GET_HEADER_FOR_OUTPUT(len) sctp_get_mbuf_for_msg(len, 1, M_DONTWAIT, 1, MT_DATA)
#define SCTP_RELEASE_PAK(i_pak)
/* Attach the chain of data into the sendable packet. */
#define SCTP_ATTACH_CHAIN(pak, m, packet_length) do { \
@ -242,7 +243,6 @@ typedef struct callout sctp_os_timer_t;
* into the chain of data holders, for BSD
* its a NOP.
*/
#define SCTP_PAK_TO_BUF(i_pak) (i_pak)
/* Macro's for getting length from V6/V4 header */
#define SCTP_GET_IPV4_LENGTH(iph) (iph->ip_len)
@ -273,6 +273,11 @@ typedef struct callout sctp_os_timer_t;
typedef struct route sctp_route_t;
struct mbuf *
sctp_get_mbuf_for_msg(unsigned int space_needed,
int want_header, int how, int allonebuf, int type);
/*
* SCTP AUTH
*/

View File

@ -3160,43 +3160,6 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, int cpsize)
return (0);
}
struct mbuf *
sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header,
int how, int allonebuf, int type)
{
struct mbuf *m = NULL;
m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0);
if (allonebuf) {
int siz;
if (SCTP_BUF_IS_EXTENDED(m)) {
siz = SCTP_BUF_EXTEND_SIZE(m);
} else {
if (want_header)
siz = MHLEN;
else
siz = MLEN;
}
if (siz < space_needed) {
m_freem(m);
return (NULL);
}
}
if (SCTP_BUF_NEXT(m)) {
sctp_m_freem(SCTP_BUF_NEXT(m));
SCTP_BUF_NEXT(m) = NULL;
}
#ifdef SCTP_MBUF_LOGGING
if (SCTP_BUF_IS_EXTENDED(m)) {
sctp_log_mb(m, SCTP_MBUF_IALLOC);
}
#endif
return (m);
}
static struct mbuf *
sctp_add_cookie(struct sctp_inpcb *inp, struct mbuf *init, int init_offset,
struct mbuf *initack, int initack_offset, struct sctp_state_cookie *stc_in)
@ -3569,10 +3532,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
printf("RTP route is %p through\n", ro->ro_rt);
}
#endif
#ifdef _WHY_THIS_CODE
if ((have_mtu) && (net) && (have_mtu > net->mtu)) {
ro->ro_rt->rt_ifp->if_mtu = net->mtu;
}
#endif
if (ro != &iproute) {
memcpy(&iproute, ro, sizeof(*ro));
}
@ -3580,9 +3544,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
ro, o_flgs, inp->ip_inp.inp.inp_moptions
,(struct inpcb *)NULL
);
#ifdef _WHY_THIS_CODE
if ((ro->ro_rt) && (have_mtu) && (net) && (have_mtu > net->mtu)) {
ro->ro_rt->rt_ifp->if_mtu = have_mtu;
}
#endif
SCTP_STAT_INCR(sctps_sendpackets);
SCTP_STAT_INCR_COUNTER64(sctps_outpackets);
if (ret)
@ -4150,9 +4116,9 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
struct sctp_paramhdr *phdr, params;
struct mbuf *mat, *op_err;
char tempbuf[SCTP_CHUNK_BUFFER_SIZE];
char tempbuf[SCTP_PARAM_BUFFER_SIZE];
int at, limit, pad_needed;
uint16_t ptype, plen;
uint16_t ptype, plen, padded_size;
int err_at;
*abort_processing = 0;
@ -4166,105 +4132,164 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
while ((phdr != NULL) && ((size_t)limit >= sizeof(struct sctp_paramhdr))) {
ptype = ntohs(phdr->param_type);
plen = ntohs(phdr->param_length);
limit -= SCTP_SIZE32(plen);
if (plen < sizeof(struct sctp_paramhdr)) {
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
printf("sctp_output.c:Impossible length in parameter < %d\n", plen);
}
#endif
*abort_processing = 1;
break;
if ((plen > limit) || (plen < sizeof(struct sctp_paramhdr))) {
/* wacked parameter */
goto invalid_size;
}
/*
limit -= SCTP_SIZE32(plen);
/*-
* All parameters for all chunks that we know/understand are
* listed here. We process them other places and make
* appropriate stop actions per the upper bits. However this
* is the generic routine processor's can call to get back
* an operr.. to either incorporate (init-ack) or send.
*/
if ((ptype == SCTP_HEARTBEAT_INFO) ||
(ptype == SCTP_IPV4_ADDRESS) ||
(ptype == SCTP_IPV6_ADDRESS) ||
(ptype == SCTP_STATE_COOKIE) ||
(ptype == SCTP_UNRECOG_PARAM) ||
(ptype == SCTP_COOKIE_PRESERVE) ||
(ptype == SCTP_SUPPORTED_ADDRTYPE) ||
(ptype == SCTP_PRSCTP_SUPPORTED) ||
(ptype == SCTP_ADD_IP_ADDRESS) ||
(ptype == SCTP_DEL_IP_ADDRESS) ||
(ptype == SCTP_ECN_CAPABLE) ||
(ptype == SCTP_ULP_ADAPTATION) ||
(ptype == SCTP_ERROR_CAUSE_IND) ||
(ptype == SCTP_RANDOM) ||
(ptype == SCTP_CHUNK_LIST) ||
(ptype == SCTP_CHUNK_LIST) ||
(ptype == SCTP_SET_PRIM_ADDR) ||
(ptype == SCTP_SUCCESS_REPORT) ||
(ptype == SCTP_ULP_ADAPTATION) ||
(ptype == SCTP_SUPPORTED_CHUNK_EXT) ||
(ptype == SCTP_ECN_NONCE_SUPPORTED)
) {
/* no skip it */
at += SCTP_SIZE32(plen);
} else if (ptype == SCTP_HOSTNAME_ADDRESS) {
/* We can NOT handle HOST NAME addresses!! */
int l_len;
padded_size = SCTP_SIZE32(plen);
switch (ptype) {
/* Param's with variable size */
case SCTP_HEARTBEAT_INFO:
case SCTP_STATE_COOKIE:
case SCTP_UNRECOG_PARAM:
case SCTP_ERROR_CAUSE_IND:
/* ok skip fwd */
at += padded_size;
break;
/* Param's with variable size within a range */
case SCTP_CHUNK_LIST:
case SCTP_SUPPORTED_CHUNK_EXT:
if (padded_size > (sizeof(struct sctp_supported_chunk_types_param) + (sizeof(uint8_t) * SCTP_MAX_SUPPORTED_EXT))) {
goto invalid_size;
}
at += padded_size;
break;
case SCTP_SUPPORTED_ADDRTYPE:
if (padded_size > SCTP_MAX_ADDR_PARAMS_SIZE) {
goto invalid_size;
}
at += padded_size;
break;
case SCTP_RANDOM:
if (padded_size > (sizeof(struct sctp_auth_random) + SCTP_RANDOM_MAX_SIZE)) {
goto invalid_size;
}
at += padded_size;
break;
case SCTP_SET_PRIM_ADDR:
case SCTP_DEL_IP_ADDRESS:
case SCTP_ADD_IP_ADDRESS:
if ((padded_size != sizeof(struct sctp_asconf_addrv4_param)) &&
(padded_size != sizeof(struct sctp_asconf_addr_param))) {
goto invalid_size;
}
at += padded_size;
break;
/* Param's with a fixed size */
case SCTP_IPV4_ADDRESS:
if (padded_size != sizeof(struct sctp_ipv4addr_param)) {
goto invalid_size;
}
at += padded_size;
break;
case SCTP_IPV6_ADDRESS:
if (padded_size != sizeof(struct sctp_ipv6addr_param)) {
goto invalid_size;
}
at += padded_size;
break;
case SCTP_COOKIE_PRESERVE:
if (padded_size != sizeof(struct sctp_cookie_perserve_param)) {
goto invalid_size;
}
at += padded_size;
break;
case SCTP_ECN_NONCE_SUPPORTED:
case SCTP_PRSCTP_SUPPORTED:
if (padded_size != sizeof(struct sctp_paramhdr)) {
goto invalid_size;
}
at += padded_size;
break;
case SCTP_ECN_CAPABLE:
if (padded_size != sizeof(struct sctp_ecn_supported_param)) {
goto invalid_size;
}
at += padded_size;
break;
case SCTP_ULP_ADAPTATION:
if (padded_size != sizeof(struct sctp_adaptation_layer_indication)) {
goto invalid_size;
}
at += padded_size;
break;
case SCTP_SUCCESS_REPORT:
if (padded_size != sizeof(struct sctp_asconf_paramhdr)) {
goto invalid_size;
}
at += padded_size;
break;
case SCTP_HOSTNAME_ADDRESS:
{
/* We can NOT handle HOST NAME addresses!! */
int l_len;
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
printf("Can't handle hostname addresses.. abort processing\n");
}
if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
printf("Can't handle hostname addresses.. abort processing\n");
}
#endif
*abort_processing = 1;
if (op_err == NULL) {
/* Ok need to try to get a mbuf */
l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
l_len += plen;
l_len += sizeof(struct sctp_paramhdr);
op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA);
*abort_processing = 1;
if (op_err == NULL) {
/* Ok need to try to get a mbuf */
l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
l_len += plen;
l_len += sizeof(struct sctp_paramhdr);
op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA);
if (op_err) {
SCTP_BUF_LEN(op_err) = 0;
/*
* pre-reserve space for ip
* and sctp header and
* chunk hdr
*/
SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr));
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
}
}
if (op_err) {
SCTP_BUF_LEN(op_err) = 0;
/*
* pre-reserve space for ip and sctp
* header and chunk hdr
*/
SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr));
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
}
}
if (op_err) {
/* If we have space */
struct sctp_paramhdr s;
/* If we have space */
struct sctp_paramhdr s;
if (err_at % 4) {
uint32_t cpthis = 0;
if (err_at % 4) {
uint32_t cpthis = 0;
pad_needed = 4 - (err_at % 4);
m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis);
err_at += pad_needed;
pad_needed = 4 - (err_at % 4);
m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis);
err_at += pad_needed;
}
s.param_type = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR);
s.param_length = htons(sizeof(s) + plen);
m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s);
err_at += sizeof(s);
phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf), plen));
if (phdr == NULL) {
sctp_m_freem(op_err);
/*
* we are out of memory but
* we still need to have a
* look at what to do (the
* system is in trouble
* though).
*/
return (NULL);
}
m_copyback(op_err, err_at, plen, (caddr_t)phdr);
err_at += plen;
}
s.param_type = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR);
s.param_length = htons(sizeof(s) + plen);
m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s);
err_at += sizeof(s);
phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, plen);
if (phdr == NULL) {
sctp_m_freem(op_err);
/*
* we are out of memory but we still
* need to have a look at what to do
* (the system is in trouble
* though).
*/
return (NULL);
}
m_copyback(op_err, err_at, plen, (caddr_t)phdr);
err_at += plen;
return (op_err);
break;
}
return (op_err);
} else {
default:
/*
* we do not recognize the parameter figure out what
* we do.
@ -4304,7 +4329,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
if (plen > sizeof(tempbuf)) {
plen = sizeof(tempbuf);
}
phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, plen);
phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf), plen));
if (phdr == NULL) {
sctp_m_freem(op_err);
/*
@ -4314,6 +4339,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
* system is in trouble
* though).
*/
op_err = NULL;
goto more_processing;
}
m_copyback(op_err, err_at, plen, (caddr_t)phdr);
@ -4327,11 +4353,43 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt,
/* skip this chunk and continue processing */
at += SCTP_SIZE32(plen);
}
break;
}
phdr = sctp_get_next_param(mat, at, &params, sizeof(params));
}
return (op_err);
invalid_size:
*abort_processing = 1;
if ((op_err == NULL) && phdr) {
int l_len;
l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
l_len += (2 * sizeof(struct sctp_paramhdr));
op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA);
SCTP_BUF_LEN(op_err) = 0;
SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr));
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr));
SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr));
}
if ((op_err) && phdr) {
struct sctp_paramhdr s;
if (err_at % 4) {
uint32_t cpthis = 0;
pad_needed = 4 - (err_at % 4);
m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis);
err_at += pad_needed;
}
s.param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
s.param_length = htons(sizeof(s) + sizeof(struct sctp_paramhdr));
m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s);
err_at += sizeof(s);
/* Only copy back the p-hdr that caused the issue */
m_copyback(op_err, err_at, sizeof(struct sctp_paramhdr), (caddr_t)phdr);
}
return (op_err);
}
static int
@ -7976,6 +8034,9 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
#endif
asoc->sent_queue_cnt = 0;
asoc->sent_queue_cnt_removeable = 0;
/* send back 0/0 so we enter normal transmission */
*cnt_out = 0;
return (0);
}
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
if ((chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) ||
@ -8444,13 +8505,16 @@ sctp_chunk_output(struct sctp_inpcb *inp,
{
/*-
* Ok this is the generic chunk service queue. we must do the
* following: - See if there are retransmits pending, if so we must
* do these first and return. - Service the stream queue that is
* next, moving any message (note I must get a complete message i.e.
* FIRST/MIDDLE and LAST to the out queue in one pass) and assigning
* TSN's - Check to see if the cwnd/rwnd allows any output, if so we
* go ahead and fomulate and send the low level chunks. Making sure
* to combine any control in the control chunk queue also.
* following:
* - See if there are retransmits pending, if so we must
* do these first.
* - Service the stream queue that is next, moving any
* message (note I must get a complete message i.e.
* FIRST/MIDDLE and LAST to the out queue in one pass) and assigning
* TSN's
* - Check to see if the cwnd/rwnd allows any output, if so we
* go ahead and fomulate and send the low level chunks. Making sure
* to combine any control in the control chunk queue also.
*/
struct sctp_association *asoc;
struct sctp_nets *net;
@ -8497,7 +8561,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
*/
if (from_where == SCTP_OUTPUT_FROM_COOKIE_ACK) {
/*-
*Special hook for handling cookiess discarded
* Special hook for handling cookiess discarded
* by peer that carried data. Send cookie-ack only
* and then the next call with get the retran's.
*/
@ -9064,7 +9128,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)sack + sizeof(struct sctp_sack_chunk));
siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8;
if (asoc->cumulative_tsn < asoc->mapping_array_base_tsn) {
if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) {
offset = 1;
/*-
* cum-ack behind the mapping array, so we start and use all
@ -9075,7 +9139,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn;
/*-
* we skip the first one when the cum-ack is at or above the
* mapping array base.
* mapping array base. Note this only works if
*/
jstart = 1;
}
@ -11142,11 +11206,15 @@ sctp_lower_sosend(struct socket *so,
}
initial_out = uio->uio_resid;
SCTP_TCB_SEND_LOCK(stcb);
if ((asoc->stream_locked) &&
(asoc->stream_locked_on != srcv->sinfo_stream)) {
SCTP_TCB_SEND_UNLOCK(stcb);
error = EAGAIN;
goto out;
}
SCTP_TCB_SEND_UNLOCK(stcb);
strm = &stcb->asoc.strmout[srcv->sinfo_stream];
user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
if (strm->last_msg_incomplete == 0) {

View File

@ -40,11 +40,6 @@ __FBSDID("$FreeBSD$");
#if defined(_KERNEL)
struct mbuf *
sctp_get_mbuf_for_msg(unsigned int space_needed,
int want_header, int how, int allonebuf, int type);
struct mbuf *
sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp,

View File

@ -234,7 +234,7 @@ sctp_free_ifa(struct sctp_ifa *sctp_ifap)
struct sctp_ifa *
sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
uint32_t ifn_type, const char *if_name,
void *ifa, struct sockaddr *addr, uint32_t ifa_flags)
void *ifa, struct sockaddr *addr, uint32_t ifa_flags, int dynamic_add)
{
struct sctp_vrf *vrf;
struct sctp_ifn *sctp_ifnp = NULL;
@ -364,16 +364,55 @@ sctp_add_addr_to_vrf(uint32_t vrfid, void *ifn, uint32_t ifn_index,
sctp_ifap->in_ifa_list = 1;
vrf->total_ifa_count++;
SCTP_IPI_ADDR_UNLOCK();
if (dynamic_add) {
/*
* Bump up the refcount so that when the timer completes it
* will drop back down.
*/
struct sctp_laddr *wi;
atomic_add_int(&sctp_ifap->refcount, 1);
wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
if (wi == NULL) {
/*
* Gak, what can we do? We have lost an address
* change can you say HOSED?
*/
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_PCB1) {
printf("Lost and address change ???\n");
}
#endif /* SCTP_DEBUG */
/* Opps, must decrement the count */
sctp_free_ifa(sctp_ifap);
return (NULL);
}
SCTP_INCR_LADDR_COUNT();
bzero(wi, sizeof(*wi));
wi->ifa = sctp_ifap;
wi->action = SCTP_ADD_IP_ADDRESS;
SCTP_IPI_ITERATOR_WQ_LOCK();
/*
* Should this really be a tailq? As it is we will process
* the newest first :-0
*/
LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr);
sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
(struct sctp_inpcb *)NULL,
(struct sctp_tcb *)NULL,
(struct sctp_nets *)NULL);
SCTP_IPI_ITERATOR_WQ_UNLOCK();
}
return (sctp_ifap);
}
struct sctp_ifa *
void
sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
uint32_t ifn_index)
{
struct sctp_vrf *vrf;
struct sctp_ifa *sctp_ifap = NULL;
struct sctp_ifn *sctp_ifnp = NULL;
SCTP_IPI_ADDR_LOCK();
@ -382,22 +421,16 @@ sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
printf("Can't find vrfid:%d\n", vrfid);
goto out_now;
}
sctp_ifnp = sctp_find_ifn(vrf, (void *)NULL, ifn_index);
if (sctp_ifnp == NULL) {
sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
} else {
sctp_ifap = sctp_find_ifa_in_ifn(sctp_ifnp, addr, 1);
}
sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
if (sctp_ifap) {
sctp_ifap->localifa_flags &= SCTP_ADDR_VALID;
sctp_ifap->localifa_flags |= SCTP_BEING_DELETED;
sctp_ifnp->ifa_count--;
sctp_ifap->ifn_p->ifa_count--;
vrf->total_ifa_count--;
LIST_REMOVE(sctp_ifap, next_bucket);
LIST_REMOVE(sctp_ifap, next_ifa);
sctp_ifap->in_ifa_list = 0;
atomic_add_int(&sctp_ifnp->refcount, -1);
atomic_add_int(&sctp_ifap->ifn_p->refcount, -1);
} else {
printf("Del Addr-ifn:%d Could not find address:",
ifn_index);
@ -405,37 +438,51 @@ sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
}
out_now:
SCTP_IPI_ADDR_UNLOCK();
return (sctp_ifap);
if (sctp_ifap) {
struct sctp_laddr *wi;
wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr);
if (wi == NULL) {
/*
* Gak, what can we do? We have lost an address
* change can you say HOSED?
*/
#ifdef SCTP_DEBUG
if (sctp_debug_on & SCTP_DEBUG_PCB1) {
printf("Lost and address change ???\n");
}
#endif /* SCTP_DEBUG */
/* Opps, must decrement the count */
sctp_free_ifa(sctp_ifap);
return;
}
SCTP_INCR_LADDR_COUNT();
bzero(wi, sizeof(*wi));
wi->ifa = sctp_ifap;
wi->action = SCTP_DEL_IP_ADDRESS;
SCTP_IPI_ITERATOR_WQ_LOCK();
/*
* Should this really be a tailq? As it is we will process
* the newest first :-0
*/
LIST_INSERT_HEAD(&sctppcbinfo.addr_wq, wi, sctp_nxt_addr);
sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
(struct sctp_inpcb *)NULL,
(struct sctp_tcb *)NULL,
(struct sctp_nets *)NULL);
SCTP_IPI_ITERATOR_WQ_UNLOCK();
}
return;
}
/*
* Notes on locks for FreeBSD 5 and up. All association lookups that have a
* definte ep, the INP structure is assumed to be locked for reading. If we
* need to go find the INP (ususally when a **inp is passed) then we must
* lock the INFO structure first and if needed lock the INP too. Note that if
* we lock it we must
*
*/
/*
* Given a endpoint, look and find in its association list any association
* with the "to" address given. This can be a "from" address, too, for
* inbound packets. For outbound packets it is a true "to" address.
*/
static struct sctp_tcb *
sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
struct sockaddr *to, struct sctp_nets **netp, uint32_t vrf_id)
{
/**** ASSUMSES THE CALLER holds the INP_INFO_RLOCK */
/*
* Note for this module care must be taken when observing what to is
* for. In most of the rest of the code the TO field represents my
* peer and the FROM field represents my address. For this module it
* is reversed of that.
*/
/*
* If we support the TCP model, then we must now dig through to see
* if we can find our endpoint in the list of tcp ep's.
@ -468,14 +515,14 @@ sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
* to this ep and return the tcb from it.
*/
LIST_FOREACH(inp, ephead, sctp_hash) {
if (lport != inp->sctp_lport) {
continue;
}
SCTP_INP_RLOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
SCTP_INP_RUNLOCK(inp);
continue;
}
if (lport != inp->sctp_lport) {
continue;
}
if (inp->def_vrf_id != vrf_id) {
SCTP_INP_RUNLOCK(inp);
continue;
@ -1224,7 +1271,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset,
struct sctp_ipv4addr_param ip4_parm, *p4;
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)&ip4_parm, plen);
(struct sctp_paramhdr *)&ip4_parm, min(plen, sizeof(ip4_parm)));
if (phdr == NULL) {
return (NULL);
}
@ -1242,7 +1289,7 @@ sctp_findassociation_special_addr(struct mbuf *m, int iphlen, int offset,
struct sctp_ipv6addr_param ip6_parm, *p6;
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)&ip6_parm, plen);
(struct sctp_paramhdr *)&ip6_parm, min(plen, sizeof(ip6_parm)));
if (phdr == NULL) {
return (NULL);
}
@ -1291,8 +1338,7 @@ sctp_findassoc_by_vtag(struct sockaddr *from, uint32_t vtag,
SCTP_INP_RLOCK(stcb->sctp_ep);
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
SCTP_INP_RUNLOCK(stcb->sctp_ep);
SCTP_INP_INFO_RUNLOCK();
return (NULL);
continue;
}
SCTP_TCB_LOCK(stcb);
SCTP_INP_RUNLOCK(stcb->sctp_ep);
@ -1426,12 +1472,6 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
sa6_embedscope(to6, ip6_use_defzone);
}
find_tcp_pool = 0;
/*
* FIX FIX?, I think we only need to look in the TCP pool if its an
* INIT or COOKIE-ECHO, We really don't need to find it that way if
* its a INIT-ACK or COOKIE_ACK since these in bot one-2-one and
* one-2-N would be in the main pool anyway.
*/
if ((ch->chunk_type != SCTP_INITIATION) &&
(ch->chunk_type != SCTP_INITIATION_ACK) &&
(ch->chunk_type != SCTP_COOKIE_ACK) &&
@ -1456,7 +1496,7 @@ sctp_findassociation_addr(struct mbuf *m, int iphlen, int offset,
/* Found a EP but not this address */
if ((ch->chunk_type == SCTP_INITIATION) ||
(ch->chunk_type == SCTP_INITIATION_ACK)) {
/*
/*-
* special hook, we do NOT return linp or an
* association that is linked to an existing
* association that is under the TCP pool (i.e. no
@ -3584,6 +3624,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* Now the read queue needs to be cleaned up (only once) */
cnt = 0;
if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) {
stcb->asoc.state |= SCTP_STATE_ABOUT_TO_BE_FREED;
SCTP_INP_READ_LOCK(inp);
TAILQ_FOREACH(sq, &inp->read_queue, next) {
if (sq->stcb == stcb) {
@ -3627,7 +3668,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
stcb->block_entry = NULL;
}
}
stcb->asoc.state |= SCTP_STATE_ABOUT_TO_BE_FREED;
if ((from_inpcbfree != SCTP_PCBFREE_FORCE) && (stcb->asoc.refcnt)) {
/*
* reader or writer in the way, we have hopefully given him
@ -4687,6 +4727,10 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
p4 = (struct sctp_ipv4addr_param *)phdr;
sin.sin_addr.s_addr = p4->addr;
if (IN_MULTICAST(sin.sin_addr.s_addr)) {
/* Skip multi-cast addresses */
goto next_param;
}
sa = (struct sockaddr *)&sin;
inp = stcb->sctp_ep;
atomic_add_int(&stcb->asoc.refcnt, 1);
@ -4749,6 +4793,17 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
p6 = (struct sctp_ipv6addr_param *)phdr;
memcpy((caddr_t)&sin6.sin6_addr, p6->addr,
sizeof(p6->addr));
if (IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr)) {
/* Skip multi-cast addresses */
goto next_param;
}
if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) {
/*
* Link local make no sense without
* scope
*/
goto next_param;
}
sa = (struct sockaddr *)&sin6;
inp = stcb->sctp_ep;
atomic_add_int(&stcb->asoc.refcnt, 1);
@ -4822,7 +4877,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
return (-23);
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)&lstore, plen);
(struct sctp_paramhdr *)&lstore, min(plen, sizeof(lstore)));
if (phdr == NULL) {
return (-24);
}
@ -4865,7 +4920,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
int num_ent, i;
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)&local_store, plen);
(struct sctp_paramhdr *)&local_store, min(sizeof(local_store), plen));
if (phdr == NULL) {
return (-25);
}
@ -4913,7 +4968,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)random_store,
plen);
min(sizeof(random_store), plen));
if (phdr == NULL)
return (-26);
p_random = (struct sctp_auth_random *)phdr;
@ -4939,7 +4994,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)hmacs_store,
plen);
min(plen, sizeof(hmacs_store)));
if (phdr == NULL)
return (-28);
hmacs = (struct sctp_auth_hmac_algo *)phdr;
@ -4970,7 +5025,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m,
}
phdr = sctp_get_next_param(m, offset,
(struct sctp_paramhdr *)chunks_store,
plen);
min(plen, sizeof(chunks_store)));
if (phdr == NULL)
return (-30);
chunks = (struct sctp_auth_chunk_list *)phdr;

View File

@ -403,11 +403,11 @@ struct sctp_ifa *
sctp_add_addr_to_vrf(uint32_t vrfid,
void *ifn, uint32_t ifn_index, uint32_t ifn_type,
const char *if_name,
void *ifa, struct sockaddr *addr, uint32_t ifa_flags);
void *ifa, struct sockaddr *addr, uint32_t ifa_flags, int dynamic_add);
void sctp_free_ifa(struct sctp_ifa *sctp_ifap);
struct sctp_ifa *
void
sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
uint32_t ifn_index);

View File

@ -99,7 +99,7 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
*/
sctp_move_pcb_and_assoc(inp, n_inp, stcb);
sctp_pull_off_control_to_new_inp(inp, n_inp, stcb);
sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
SCTP_TCB_UNLOCK(stcb);
return (0);
@ -196,7 +196,7 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
* And now the final hack. We move data in the pending side i.e.
* head to the new socket buffer. Let the GRUBBING begin :-0
*/
sctp_pull_off_control_to_new_inp(inp, n_inp, stcb);
sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
SCTP_TCB_UNLOCK(stcb);
return (newso);

View File

@ -3331,15 +3331,15 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
if (stcb) {
if (stcb != NULL) {
if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) {
error = EINVAL;
}
SCTP_TCB_UNLOCK(stcb);
} else {
error = EINVAL;
}
SCTP_TCB_UNLOCK(stcb);
}
break;
case SCTP_BINDX_ADD_ADDR:
@ -3651,6 +3651,7 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
error = solisten_proto_check(so);
if (error) {
SOCK_UNLOCK(so);
SCTP_INP_RUNLOCK(inp);
return (error);
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
@ -3674,7 +3675,6 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
}
/* It appears for 7.0 and on, we must always call this. */
solisten_proto(so, backlog);
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
/* remove the ACCEPTCONN flag for one-to-many sockets */
so->so_options &= ~SO_ACCEPTCONN;

View File

@ -3846,7 +3846,8 @@ sctp_print_address_pkt(struct ip *iph, struct sctphdr *sh)
void
sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
struct sctp_inpcb *new_inp,
struct sctp_tcb *stcb)
struct sctp_tcb *stcb,
int waitflags)
{
/*
* go through our old INP and pull off any control structures that
@ -3861,11 +3862,8 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
old_so = old_inp->sctp_socket;
new_so = new_inp->sctp_socket;
TAILQ_INIT(&tmp_queue);
SOCKBUF_LOCK(&(old_so->so_rcv));
error = sblock(&old_so->so_rcv, 0);
error = sblock(&old_so->so_rcv, waitflags);
SOCKBUF_UNLOCK(&(old_so->so_rcv));
if (error) {
/*
@ -3904,13 +3902,11 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
control = nctl;
}
SCTP_INP_READ_UNLOCK(old_inp);
/* Remove the sb-lock on the old socket */
SOCKBUF_LOCK(&(old_so->so_rcv));
sbunlock(&old_so->so_rcv);
SOCKBUF_UNLOCK(&(old_so->so_rcv));
/* Now we move them over to the new socket buffer */
control = TAILQ_FIRST(&tmp_queue);
SCTP_INP_READ_LOCK(new_inp);
@ -4298,43 +4294,6 @@ sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, int holds_loc
return (NULL);
}
struct sctp_ifa *
sctp_find_ifa_in_ifn(struct sctp_ifn *sctp_ifnp, struct sockaddr *addr,
int holds_lock)
{
struct sctp_ifa *sctp_ifap;
if (holds_lock == 0)
SCTP_IPI_ADDR_LOCK();
LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
if (addr->sa_family != sctp_ifap->address.sa.sa_family)
continue;
if (addr->sa_family == AF_INET) {
if (((struct sockaddr_in *)addr)->sin_addr.s_addr ==
sctp_ifap->address.sin.sin_addr.s_addr) {
/* found him. */
if (holds_lock == 0)
SCTP_IPI_ADDR_UNLOCK();
return (sctp_ifap);
break;
}
} else if (addr->sa_family == AF_INET6) {
if (SCTP6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)addr)->sin6_addr,
&sctp_ifap->address.sin6.sin6_addr)) {
/* found him. */
if (holds_lock == 0)
SCTP_IPI_ADDR_UNLOCK();
return (sctp_ifap);
break;
}
}
}
if (holds_lock == 0)
SCTP_IPI_ADDR_UNLOCK();
return (NULL);
}
uint32_t
sctp_get_ifa_hash_val(struct sockaddr *addr)
{
@ -4741,6 +4700,10 @@ sctp_sorecvmsg(struct socket *so,
}
goto out;
}
if (hold_sblock == 1) {
SOCKBUF_UNLOCK(&so->so_rcv);
hold_sblock = 0;
}
error = sblock(&so->so_rcv, (block_allowed ? M_WAITOK : 0));
/* we possibly have data we can read */
control = TAILQ_FIRST(&inp->read_queue);
@ -4862,9 +4825,6 @@ sctp_sorecvmsg(struct socket *so,
* If we reach here, control has a some data for us to read off.
* Note that stcb COULD be NULL.
*/
if (control->do_not_ref_stcb == 0) {
control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1;
}
control->some_taken = 1;
if (hold_sblock) {
SOCKBUF_UNLOCK(&so->so_rcv);
@ -4901,6 +4861,9 @@ sctp_sorecvmsg(struct socket *so,
stcb->freed_by_sorcv_sincelast = 0;
}
}
if (stcb && control->do_not_ref_stcb == 0) {
stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1;
}
/* First lets get off the sinfo and sockaddr info */
if ((sinfo) && filling_sinfo) {
memcpy(sinfo, control, sizeof(struct sctp_nonpad_sndrcvinfo));

View File

@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
* Any new logging added must also define SCTP_STAT_LOGGING if
* its not already defined.
*/
#if defined(SCTP_LOG_MAXBURST) || defined(SCTP_LOG_RWND) || defined(SCTP_LOG_RWND)
#ifndef SCTP_STAT_LOGGING
#define SCTP_STAT_LOGGING 1
@ -86,6 +87,13 @@ __FBSDID("$FreeBSD$");
#endif
#endif
#if defined(SCTP_LOG_SACK_ARRIVALS)
#ifndef SCTP_STAT_LOGGING
#define SCTP_STAT_LOGGING 1
#endif
#endif
#ifdef SCTP_ASOCLOG_OF_TSNS
void sctp_print_out_track_log(struct sctp_tcb *stcb);
@ -112,9 +120,6 @@ sctp_get_ifa_hash_val(struct sockaddr *addr);
struct sctp_ifa *
sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, int hold_lock);
struct sctp_ifa *
sctp_find_ifa_in_ifn(struct sctp_ifn *sctp_ifnp, struct sockaddr *addr,
int holds_lock);
struct sctp_ifa *
sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock);
@ -188,7 +193,7 @@ void sctp_ulp_notify(uint32_t, struct sctp_tcb *, uint32_t, void *);
void
sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
struct sctp_inpcb *new_inp,
struct sctp_tcb *stcb);
struct sctp_tcb *stcb, int waitflags);
void sctp_stop_timers_for_shutdown(struct sctp_tcb *);

View File

@ -240,6 +240,8 @@ sctp6_input(i_pak, offp, proto)
}
if (m)
m_freem(m);
/* For BSD/MAC this does nothing */
SCTP_RELEASE_PAK(*i_pak);
return IPPROTO_DONE;
}