2005-08-10 07:14:34 +04:00
/*
* net / dccp / input . c
*
* An implementation of the DCCP protocol
* Arnaldo Carvalho de Melo < acme @ conectiva . com . br >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/config.h>
# include <linux/dccp.h>
# include <linux/skbuff.h>
# include <net/sock.h>
# include "ccid.h"
# include "dccp.h"
static void dccp_fin ( struct sock * sk , struct sk_buff * skb )
{
sk - > sk_shutdown | = RCV_SHUTDOWN ;
sock_set_flag ( sk , SOCK_DONE ) ;
__skb_pull ( skb , dccp_hdr ( skb ) - > dccph_doff * 4 ) ;
__skb_queue_tail ( & sk - > sk_receive_queue , skb ) ;
skb_set_owner_r ( skb , sk ) ;
sk - > sk_data_ready ( sk , 0 ) ;
}
static void dccp_rcv_close ( struct sock * sk , struct sk_buff * skb )
{
2005-08-24 08:50:06 +04:00
dccp_v4_send_reset ( sk , DCCP_RESET_CODE_CLOSED ) ;
dccp_fin ( sk , skb ) ;
dccp_set_state ( sk , DCCP_CLOSED ) ;
2005-08-10 07:14:34 +04:00
}
static void dccp_rcv_closereq ( struct sock * sk , struct sk_buff * skb )
{
/*
* Step 7 : Check for unexpected packet types
* If ( S . is_server and P . type = = CloseReq )
* Send Sync packet acknowledging P . seqno
* Drop packet and return
*/
if ( dccp_sk ( sk ) - > dccps_role ! = DCCP_ROLE_CLIENT ) {
2005-08-17 10:10:59 +04:00
dccp_send_sync ( sk , DCCP_SKB_CB ( skb ) - > dccpd_seq , DCCP_PKT_SYNC ) ;
2005-08-10 07:14:34 +04:00
return ;
}
2005-08-24 08:50:06 +04:00
dccp_set_state ( sk , DCCP_CLOSING ) ;
dccp_send_close ( sk , 0 ) ;
2005-08-10 07:14:34 +04:00
}
static inline void dccp_event_ack_recv ( struct sock * sk , struct sk_buff * skb )
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
if ( dp - > dccps_options . dccpo_send_ack_vector )
dccp_ackpkts_check_rcv_ackno ( dp - > dccps_hc_rx_ackpkts , sk ,
DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ) ;
}
static int dccp_check_seqno ( struct sock * sk , struct sk_buff * skb )
{
const struct dccp_hdr * dh = dccp_hdr ( skb ) ;
struct dccp_sock * dp = dccp_sk ( sk ) ;
2005-08-17 10:10:59 +04:00
u64 lswl , lawl ;
2005-08-10 07:14:34 +04:00
/*
* Step 5 : Prepare sequence numbers for Sync
* If P . type = = Sync or P . type = = SyncAck ,
* If S . AWL < = P . ackno < = S . AWH and P . seqno > = S . SWL ,
* / * P is valid , so update sequence number variables
* accordingly . After this update , P will pass the tests
* in Step 6. A SyncAck is generated if necessary in
* Step 15 * /
* Update S . GSR , S . SWL , S . SWH
* Otherwise ,
* Drop packet and return
*/
if ( dh - > dccph_type = = DCCP_PKT_SYNC | |
dh - > dccph_type = = DCCP_PKT_SYNCACK ) {
2005-08-14 03:34:54 +04:00
if ( between48 ( DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ,
dp - > dccps_awl , dp - > dccps_awh ) & &
2005-08-10 07:14:34 +04:00
! before48 ( DCCP_SKB_CB ( skb ) - > dccpd_seq , dp - > dccps_swl ) )
dccp_update_gsr ( sk , DCCP_SKB_CB ( skb ) - > dccpd_seq ) ;
else
return - 1 ;
2005-08-17 10:10:59 +04:00
}
2005-08-10 07:14:34 +04:00
/*
* Step 6 : Check sequence numbers
* Let LSWL = S . SWL and LAWL = S . AWL
* If P . type = = CloseReq or P . type = = Close or P . type = = Reset ,
* LSWL : = S . GSR + 1 , LAWL : = S . GAR
* If LSWL < = P . seqno < = S . SWH
* and ( P . ackno does not exist or LAWL < = P . ackno < = S . AWH ) ,
* Update S . GSR , S . SWL , S . SWH
* If P . type ! = Sync ,
* Update S . GAR
* Otherwise ,
* Send Sync packet acknowledging P . seqno
* Drop packet and return
*/
2005-08-17 10:10:59 +04:00
lswl = dp - > dccps_swl ;
lawl = dp - > dccps_awl ;
if ( dh - > dccph_type = = DCCP_PKT_CLOSEREQ | |
2005-08-19 04:12:02 +04:00
dh - > dccph_type = = DCCP_PKT_CLOSE | |
dh - > dccph_type = = DCCP_PKT_RESET ) {
2005-08-10 07:14:34 +04:00
lswl = dp - > dccps_gsr ;
dccp_inc_seqno ( & lswl ) ;
lawl = dp - > dccps_gar ;
}
if ( between48 ( DCCP_SKB_CB ( skb ) - > dccpd_seq , lswl , dp - > dccps_swh ) & &
( DCCP_SKB_CB ( skb ) - > dccpd_ack_seq = = DCCP_PKT_WITHOUT_ACK_SEQ | |
2005-08-14 03:34:54 +04:00
between48 ( DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ,
lawl , dp - > dccps_awh ) ) ) {
2005-08-10 07:14:34 +04:00
dccp_update_gsr ( sk , DCCP_SKB_CB ( skb ) - > dccpd_seq ) ;
if ( dh - > dccph_type ! = DCCP_PKT_SYNC & &
2005-08-14 03:34:54 +04:00
( DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ! =
DCCP_PKT_WITHOUT_ACK_SEQ ) )
2005-08-10 07:14:34 +04:00
dp - > dccps_gar = DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ;
} else {
2005-08-21 12:35:18 +04:00
LIMIT_NETDEBUG ( KERN_WARNING " DCCP: Step 6 failed for %s packet, "
" (LSWL(%llu) <= P.seqno(%llu) <= S.SWH(%llu)) and "
" (P.ackno %s or LAWL(%llu) <= P.ackno(%llu) <= S.AWH(%llu), "
" sending SYNC... \n " ,
dccp_packet_name ( dh - > dccph_type ) ,
2005-08-22 10:46:01 +04:00
( unsigned long long ) lswl ,
( unsigned long long )
DCCP_SKB_CB ( skb ) - > dccpd_seq ,
( unsigned long long ) dp - > dccps_swh ,
2005-08-21 12:35:18 +04:00
( DCCP_SKB_CB ( skb ) - > dccpd_ack_seq = =
DCCP_PKT_WITHOUT_ACK_SEQ ) ? " doesn't exist " : " exists " ,
2005-08-22 10:46:01 +04:00
( unsigned long long ) lawl ,
( unsigned long long )
DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ,
( unsigned long long ) dp - > dccps_awh ) ;
2005-08-17 10:10:59 +04:00
dccp_send_sync ( sk , DCCP_SKB_CB ( skb ) - > dccpd_seq , DCCP_PKT_SYNC ) ;
2005-08-10 07:14:34 +04:00
return - 1 ;
}
return 0 ;
}
int dccp_rcv_established ( struct sock * sk , struct sk_buff * skb ,
const struct dccp_hdr * dh , const unsigned len )
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
if ( dccp_check_seqno ( sk , skb ) )
goto discard ;
if ( dccp_parse_options ( sk , skb ) )
goto discard ;
if ( DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ! = DCCP_PKT_WITHOUT_ACK_SEQ )
dccp_event_ack_recv ( sk , skb ) ;
/*
* FIXME : check ECN to see if we should use
* DCCP_ACKPKTS_STATE_ECN_MARKED
*/
if ( dp - > dccps_options . dccpo_send_ack_vector ) {
struct dccp_ackpkts * ap = dp - > dccps_hc_rx_ackpkts ;
if ( dccp_ackpkts_add ( dp - > dccps_hc_rx_ackpkts ,
DCCP_SKB_CB ( skb ) - > dccpd_seq ,
DCCP_ACKPKTS_STATE_RECEIVED ) ) {
2005-08-19 04:12:02 +04:00
LIMIT_NETDEBUG ( KERN_WARNING " DCCP: acknowledgeable "
" packets buffer full! \n " ) ;
2005-08-10 07:14:34 +04:00
ap - > dccpap_ack_seqno = DCCP_MAX_SEQNO + 1 ;
inet_csk_schedule_ack ( sk ) ;
2005-08-14 03:34:54 +04:00
inet_csk_reset_xmit_timer ( sk , ICSK_TIME_DACK ,
TCP_DELACK_MIN ,
DCCP_RTO_MAX ) ;
2005-08-10 07:14:34 +04:00
goto discard ;
}
/*
* FIXME : this activation is probably wrong , have to study more
* TCP delack machinery and how it fits into DCCP draft , but
* for now it kinda " works " 8 )
*/
if ( ! inet_csk_ack_scheduled ( sk ) ) {
inet_csk_schedule_ack ( sk ) ;
2005-08-14 03:34:54 +04:00
inet_csk_reset_xmit_timer ( sk , ICSK_TIME_DACK , 5 * HZ ,
DCCP_RTO_MAX ) ;
2005-08-10 07:14:34 +04:00
}
}
ccid_hc_rx_packet_recv ( dp - > dccps_hc_rx_ccid , sk , skb ) ;
ccid_hc_tx_packet_recv ( dp - > dccps_hc_tx_ccid , sk , skb ) ;
switch ( dccp_hdr ( skb ) - > dccph_type ) {
case DCCP_PKT_DATAACK :
case DCCP_PKT_DATA :
/*
2005-08-14 03:34:54 +04:00
* FIXME : check if sk_receive_queue is full , schedule DATA_DROPPED
* option if it is .
2005-08-10 07:14:34 +04:00
*/
__skb_pull ( skb , dh - > dccph_doff * 4 ) ;
__skb_queue_tail ( & sk - > sk_receive_queue , skb ) ;
skb_set_owner_r ( skb , sk ) ;
sk - > sk_data_ready ( sk , 0 ) ;
return 0 ;
case DCCP_PKT_ACK :
goto discard ;
case DCCP_PKT_RESET :
/*
* Step 9 : Process Reset
* If P . type = = Reset ,
* Tear down connection
* S . state : = TIMEWAIT
* Set TIMEWAIT timer
* Drop packet and return
*/
dccp_fin ( sk , skb ) ;
dccp_time_wait ( sk , DCCP_TIME_WAIT , 0 ) ;
return 0 ;
case DCCP_PKT_CLOSEREQ :
dccp_rcv_closereq ( sk , skb ) ;
goto discard ;
case DCCP_PKT_CLOSE :
dccp_rcv_close ( sk , skb ) ;
return 0 ;
case DCCP_PKT_REQUEST :
/* Step 7
* or ( S . is_server and P . type = = Response )
* or ( S . is_client and P . type = = Request )
* or ( S . state > = OPEN and P . type = = Request
* and P . seqno > = S . OSR )
* or ( S . state > = OPEN and P . type = = Response
* and P . seqno > = S . OSR )
* or ( S . state = = RESPOND and P . type = = Data ) ,
* Send Sync packet acknowledging P . seqno
* Drop packet and return
*/
if ( dp - > dccps_role ! = DCCP_ROLE_LISTEN )
goto send_sync ;
goto check_seq ;
case DCCP_PKT_RESPONSE :
if ( dp - > dccps_role ! = DCCP_ROLE_CLIENT )
goto send_sync ;
check_seq :
if ( ! before48 ( DCCP_SKB_CB ( skb ) - > dccpd_seq , dp - > dccps_osr ) ) {
send_sync :
2005-08-17 10:10:59 +04:00
dccp_send_sync ( sk , DCCP_SKB_CB ( skb ) - > dccpd_seq ,
DCCP_PKT_SYNC ) ;
2005-08-10 07:14:34 +04:00
}
break ;
2005-08-17 10:10:59 +04:00
case DCCP_PKT_SYNC :
dccp_send_sync ( sk , DCCP_SKB_CB ( skb ) - > dccpd_seq ,
DCCP_PKT_SYNCACK ) ;
/*
* From the draft :
*
* As with DCCP - Ack packets , DCCP - Sync and DCCP - SyncAck packets
* MAY have non - zero - length application data areas , whose
* contents * receivers MUST ignore .
*/
goto discard ;
2005-08-10 07:14:34 +04:00
}
DCCP_INC_STATS_BH ( DCCP_MIB_INERRS ) ;
discard :
__kfree_skb ( skb ) ;
return 0 ;
}
static int dccp_rcv_request_sent_state_process ( struct sock * sk ,
struct sk_buff * skb ,
const struct dccp_hdr * dh ,
const unsigned len )
{
/*
* Step 4 : Prepare sequence numbers in REQUEST
* If S . state = = REQUEST ,
* If ( P . type = = Response or P . type = = Reset )
* and S . AWL < = P . ackno < = S . AWH ,
* / * Set sequence number variables corresponding to the
* other endpoint , so P will pass the tests in Step 6 * /
* Set S . GSR , S . ISR , S . SWL , S . SWH
* / * Response processing continues in Step 10 ; Reset
* processing continues in Step 9 * /
*/
if ( dh - > dccph_type = = DCCP_PKT_RESPONSE ) {
const struct inet_connection_sock * icsk = inet_csk ( sk ) ;
struct dccp_sock * dp = dccp_sk ( sk ) ;
/* Stop the REQUEST timer */
inet_csk_clear_xmit_timer ( sk , ICSK_TIME_RETRANS ) ;
BUG_TRAP ( sk - > sk_send_head ! = NULL ) ;
__kfree_skb ( sk - > sk_send_head ) ;
sk - > sk_send_head = NULL ;
2005-08-14 03:34:54 +04:00
if ( ! between48 ( DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ,
dp - > dccps_awl , dp - > dccps_awh ) ) {
dccp_pr_debug ( " invalid ackno: S.AWL=%llu, "
" P.ackno=%llu, S.AWH=%llu \n " ,
( unsigned long long ) dp - > dccps_awl ,
( unsigned long long ) DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ,
( unsigned long long ) dp - > dccps_awh ) ;
2005-08-10 07:14:34 +04:00
goto out_invalid_packet ;
}
dp - > dccps_isr = DCCP_SKB_CB ( skb ) - > dccpd_seq ;
2005-08-21 12:36:45 +04:00
dccp_update_gsr ( sk , dp - > dccps_isr ) ;
/*
* SWL and AWL are initially adjusted so that they are not less than
* the initial Sequence Numbers received and sent , respectively :
* SWL : = max ( GSR + 1 - floor ( W / 4 ) , ISR ) ,
* AWL : = max ( GSS - W ' + 1 , ISS ) .
* These adjustments MUST be applied only at the beginning of the
* connection .
*
* AWL was adjusted in dccp_v4_connect - acme
*/
dccp_set_seqno ( & dp - > dccps_swl ,
max48 ( dp - > dccps_swl , dp - > dccps_isr ) ) ;
2005-08-10 07:14:34 +04:00
if ( ccid_hc_rx_init ( dp - > dccps_hc_rx_ccid , sk ) ! = 0 | |
ccid_hc_tx_init ( dp - > dccps_hc_tx_ccid , sk ) ! = 0 ) {
ccid_hc_rx_exit ( dp - > dccps_hc_rx_ccid , sk ) ;
ccid_hc_tx_exit ( dp - > dccps_hc_tx_ccid , sk ) ;
/* FIXME: send appropriate RESET code */
goto out_invalid_packet ;
}
dccp_sync_mss ( sk , dp - > dccps_pmtu_cookie ) ;
/*
* Step 10 : Process REQUEST state ( second part )
* If S . state = = REQUEST ,
2005-08-14 03:34:54 +04:00
* / * If we get here , P is a valid Response from the
* server ( see Step 4 ) , and we should move to
* PARTOPEN state . PARTOPEN means send an Ack ,
* don ' t send Data packets , retransmit Acks
* periodically , and always include any Init Cookie
* from the Response * /
2005-08-10 07:14:34 +04:00
* S . state : = PARTOPEN
* Set PARTOPEN timer
* Continue with S . state = = PARTOPEN
2005-08-14 03:34:54 +04:00
* / * Step 12 will send the Ack completing the
* three - way handshake * /
2005-08-10 07:14:34 +04:00
*/
dccp_set_state ( sk , DCCP_PARTOPEN ) ;
/* Make sure socket is routed, for correct metrics. */
inet_sk_rebuild_header ( sk ) ;
if ( ! sock_flag ( sk , SOCK_DEAD ) ) {
sk - > sk_state_change ( sk ) ;
sk_wake_async ( sk , 0 , POLL_OUT ) ;
}
if ( sk - > sk_write_pending | | icsk - > icsk_ack . pingpong | |
icsk - > icsk_accept_queue . rskq_defer_accept ) {
/* Save one ACK. Data will be ready after
* several ticks , if write_pending is set .
*
* It may be deleted , but with this feature tcpdumps
* look so _wonderfully_ clever , that I was not able
* to stand against the temptation 8 ) - - ANK
*/
/*
* OK , in DCCP we can as well do a similar trick , its
* even in the draft , but there is no need for us to
* schedule an ack here , as dccp_sendmsg does this for
* us , also stated in the draft . - acme
*/
__kfree_skb ( skb ) ;
return 0 ;
}
dccp_send_ack ( sk ) ;
return - 1 ;
}
out_invalid_packet :
return 1 ; /* dccp_v4_do_rcv will send a reset, but...
2005-08-14 03:34:54 +04:00
FIXME : the reset code should be
DCCP_RESET_CODE_PACKET_ERROR */
2005-08-10 07:14:34 +04:00
}
static int dccp_rcv_respond_partopen_state_process ( struct sock * sk ,
struct sk_buff * skb ,
const struct dccp_hdr * dh ,
const unsigned len )
{
int queued = 0 ;
switch ( dh - > dccph_type ) {
case DCCP_PKT_RESET :
inet_csk_clear_xmit_timer ( sk , ICSK_TIME_DACK ) ;
break ;
case DCCP_PKT_DATAACK :
case DCCP_PKT_ACK :
/*
2005-08-14 03:34:54 +04:00
* FIXME : we should be reseting the PARTOPEN ( DELACK ) timer
* here but only if we haven ' t used the DELACK timer for
* something else , like sending a delayed ack for a TIMESTAMP
* echo , etc , for now were not clearing it , sending an extra
* ACK when there is nothing else to do in DELACK is not a big
* deal after all .
2005-08-10 07:14:34 +04:00
*/
/* Stop the PARTOPEN timer */
if ( sk - > sk_state = = DCCP_PARTOPEN )
inet_csk_clear_xmit_timer ( sk , ICSK_TIME_DACK ) ;
dccp_sk ( sk ) - > dccps_osr = DCCP_SKB_CB ( skb ) - > dccpd_seq ;
dccp_set_state ( sk , DCCP_OPEN ) ;
if ( dh - > dccph_type = = DCCP_PKT_DATAACK ) {
dccp_rcv_established ( sk , skb , dh , len ) ;
2005-08-14 03:34:54 +04:00
queued = 1 ; /* packet was queued
( by dccp_rcv_established ) */
2005-08-10 07:14:34 +04:00
}
break ;
}
return queued ;
}
int dccp_rcv_state_process ( struct sock * sk , struct sk_buff * skb ,
struct dccp_hdr * dh , unsigned len )
{
struct dccp_sock * dp = dccp_sk ( sk ) ;
const int old_state = sk - > sk_state ;
int queued = 0 ;
2005-08-14 03:36:01 +04:00
/*
* Step 3 : Process LISTEN state
* ( Continuing from dccp_v4_do_rcv and dccp_v6_do_rcv )
*
* If S . state = = LISTEN ,
* If P . type = = Request or P contains a valid Init Cookie
* option ,
* * Must scan the packet ' s options to check for an Init
* Cookie . Only the Init Cookie is processed here ,
* however ; other options are processed in Step 8. This
* scan need only be performed if the endpoint uses Init
* Cookies *
* * Generate a new socket and switch to that socket *
* Set S : = new socket for this port pair
* S . state = RESPOND
* Choose S . ISS ( initial seqno ) or set from Init Cookie
* Set S . ISR , S . GSR , S . SWL , S . SWH from packet or Init Cookie
* Continue with S . state = = RESPOND
* * A Response packet will be generated in Step 11 *
* Otherwise ,
* Generate Reset ( No Connection ) unless P . type = = Reset
* Drop packet and return
*
* NOTE : the check for the packet types is done in
* dccp_rcv_state_process
*/
if ( sk - > sk_state = = DCCP_LISTEN ) {
if ( dh - > dccph_type = = DCCP_PKT_REQUEST ) {
if ( dccp_v4_conn_request ( sk , skb ) < 0 )
return 1 ;
/* FIXME: do congestion control initialization */
goto discard ;
}
if ( dh - > dccph_type = = DCCP_PKT_RESET )
goto discard ;
/* Caller (dccp_v4_do_rcv) will send Reset(No Connection)*/
return 1 ;
}
if ( sk - > sk_state ! = DCCP_REQUESTING ) {
2005-08-10 07:14:34 +04:00
if ( dccp_check_seqno ( sk , skb ) )
goto discard ;
/*
* Step 8 : Process options and mark acknowledgeable
*/
if ( dccp_parse_options ( sk , skb ) )
goto discard ;
2005-08-14 03:34:54 +04:00
if ( DCCP_SKB_CB ( skb ) - > dccpd_ack_seq ! =
DCCP_PKT_WITHOUT_ACK_SEQ )
2005-08-10 07:14:34 +04:00
dccp_event_ack_recv ( sk , skb ) ;
ccid_hc_rx_packet_recv ( dp - > dccps_hc_rx_ccid , sk , skb ) ;
ccid_hc_tx_packet_recv ( dp - > dccps_hc_tx_ccid , sk , skb ) ;
/*
* FIXME : check ECN to see if we should use
* DCCP_ACKPKTS_STATE_ECN_MARKED
*/
if ( dp - > dccps_options . dccpo_send_ack_vector ) {
if ( dccp_ackpkts_add ( dp - > dccps_hc_rx_ackpkts ,
DCCP_SKB_CB ( skb ) - > dccpd_seq ,
DCCP_ACKPKTS_STATE_RECEIVED ) )
goto discard ;
/*
2005-08-14 03:34:54 +04:00
* FIXME : this activation is probably wrong , have to
* study more TCP delack machinery and how it fits into
* DCCP draft , but for now it kinda " works " 8 )
2005-08-10 07:14:34 +04:00
*/
2005-08-14 03:34:54 +04:00
if ( ( dp - > dccps_hc_rx_ackpkts - > dccpap_ack_seqno = =
DCCP_MAX_SEQNO + 1 ) & &
2005-08-10 07:14:34 +04:00
! inet_csk_ack_scheduled ( sk ) ) {
inet_csk_schedule_ack ( sk ) ;
2005-08-14 03:34:54 +04:00
inet_csk_reset_xmit_timer ( sk , ICSK_TIME_DACK ,
TCP_DELACK_MIN ,
DCCP_RTO_MAX ) ;
2005-08-10 07:14:34 +04:00
}
}
}
/*
* Step 9 : Process Reset
* If P . type = = Reset ,
* Tear down connection
* S . state : = TIMEWAIT
* Set TIMEWAIT timer
* Drop packet and return
*/
if ( dh - > dccph_type = = DCCP_PKT_RESET ) {
2005-08-14 03:34:54 +04:00
/*
* Queue the equivalent of TCP fin so that dccp_recvmsg
* exits the loop
*/
2005-08-10 07:14:34 +04:00
dccp_fin ( sk , skb ) ;
dccp_time_wait ( sk , DCCP_TIME_WAIT , 0 ) ;
return 0 ;
/*
* Step 7 : Check for unexpected packet types
* If ( S . is_server and P . type = = CloseReq )
* or ( S . is_server and P . type = = Response )
* or ( S . is_client and P . type = = Request )
* or ( S . state = = RESPOND and P . type = = Data ) ,
* Send Sync packet acknowledging P . seqno
* Drop packet and return
*/
} else if ( ( dp - > dccps_role ! = DCCP_ROLE_CLIENT & &
2005-08-14 03:34:54 +04:00
( dh - > dccph_type = = DCCP_PKT_RESPONSE | |
dh - > dccph_type = = DCCP_PKT_CLOSEREQ ) ) | |
2005-08-10 07:14:34 +04:00
( dp - > dccps_role = = DCCP_ROLE_CLIENT & &
dh - > dccph_type = = DCCP_PKT_REQUEST ) | |
2005-08-14 03:34:54 +04:00
( sk - > sk_state = = DCCP_RESPOND & &
dh - > dccph_type = = DCCP_PKT_DATA ) ) {
2005-08-17 10:10:59 +04:00
dccp_send_sync ( sk , DCCP_SKB_CB ( skb ) - > dccpd_seq ,
DCCP_PKT_SYNC ) ;
2005-08-10 07:14:34 +04:00
goto discard ;
2005-08-24 08:50:06 +04:00
} else if ( dh - > dccph_type = = DCCP_PKT_CLOSEREQ ) {
dccp_rcv_closereq ( sk , skb ) ;
goto discard ;
} else if ( dh - > dccph_type = = DCCP_PKT_CLOSE ) {
dccp_rcv_close ( sk , skb ) ;
return 0 ;
2005-08-10 07:14:34 +04:00
}
switch ( sk - > sk_state ) {
case DCCP_CLOSED :
return 1 ;
case DCCP_REQUESTING :
/* FIXME: do congestion control initialization */
queued = dccp_rcv_request_sent_state_process ( sk , skb , dh , len ) ;
if ( queued > = 0 )
return queued ;
__kfree_skb ( skb ) ;
return 0 ;
case DCCP_RESPOND :
case DCCP_PARTOPEN :
2005-08-14 03:34:54 +04:00
queued = dccp_rcv_respond_partopen_state_process ( sk , skb ,
dh , len ) ;
2005-08-10 07:14:34 +04:00
break ;
}
2005-08-14 03:34:54 +04:00
if ( dh - > dccph_type = = DCCP_PKT_ACK | |
dh - > dccph_type = = DCCP_PKT_DATAACK ) {
2005-08-10 07:14:34 +04:00
switch ( old_state ) {
case DCCP_PARTOPEN :
sk - > sk_state_change ( sk ) ;
sk_wake_async ( sk , 0 , POLL_OUT ) ;
break ;
}
}
if ( ! queued ) {
discard :
__kfree_skb ( skb ) ;
}
return 0 ;
}