Commit 229e0840 authored by David S. Miller's avatar David S. Miller

Merge nuts.ninka.net:/home/davem/src/BK/network-2.5

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents 02debc0e 10880106
...@@ -39,16 +39,16 @@ ...@@ -39,16 +39,16 @@
* An X.121 address, it is held as ASCII text, null terminated, up to 15 * An X.121 address, it is held as ASCII text, null terminated, up to 15
* digits and a null terminator. * digits and a null terminator.
*/ */
typedef struct { struct x25_address {
char x25_addr[16]; char x25_addr[16];
} x25_address; };
/* /*
* Linux X.25 Address structure, used for bind, and connect mostly. * Linux X.25 Address structure, used for bind, and connect mostly.
*/ */
struct sockaddr_x25 { struct sockaddr_x25 {
sa_family_t sx25_family; /* Must be AF_X25 */ sa_family_t sx25_family; /* Must be AF_X25 */
x25_address sx25_addr; /* X.121 Address */ struct x25_address sx25_addr; /* X.121 Address */
}; };
/* /*
...@@ -78,7 +78,7 @@ struct x25_subscrip_struct { ...@@ -78,7 +78,7 @@ struct x25_subscrip_struct {
* Routing table control structure. * Routing table control structure.
*/ */
struct x25_route_struct { struct x25_route_struct {
x25_address address; struct x25_address address;
unsigned int sigdigits; unsigned int sigdigits;
char device[200]; char device[200];
}; };
......
...@@ -110,38 +110,14 @@ ...@@ -110,38 +110,14 @@
#define LLC_CONN_EV_QFY_S_FLAG_EQ_0 11 #define LLC_CONN_EV_QFY_S_FLAG_EQ_0 11
#define LLC_CONN_EV_QFY_INIT_P_F_CYCLE 12 #define LLC_CONN_EV_QFY_INIT_P_F_CYCLE 12
/* Event data interface; what is sent in an event package */
/* Event LLC_CONN_EV_TYPE_SIMPLE interface */
struct llc_conn_ev_simple_if {
u8 ev;
};
/* Event LLC_CONN_EV_TYPE_PRIM interface */
struct llc_conn_ev_prim_if {
u8 prim; /* connect, disconnect, reset, ... */
u8 type; /* request, indicate, response, conf */
struct llc_prim_if_block *data;
};
/* Event LLC_CONN_EV_TYPE_PDU interface */
struct llc_conn_ev_pdu_if {
u8 ev;
};
union llc_conn_ev_if {
struct llc_conn_ev_simple_if a; /* 'a' for simple, easy ... */
struct llc_conn_ev_prim_if prim;
struct llc_conn_ev_pdu_if pdu;
};
struct llc_conn_state_ev { struct llc_conn_state_ev {
u8 type; u8 type;
u8 prim;
u8 prim_type;
u8 reason; u8 reason;
u8 status; u8 status;
u8 flag; u8 ind_prim;
struct llc_prim_if_block *ind_prim; u8 cfm_prim;
struct llc_prim_if_block *cfm_prim;
union llc_conn_ev_if data;
}; };
static __inline__ struct llc_conn_state_ev *llc_conn_ev(struct sk_buff *skb) static __inline__ struct llc_conn_state_ev *llc_conn_ev(struct sk_buff *skb)
......
...@@ -66,18 +66,10 @@ struct llc_opt { ...@@ -66,18 +66,10 @@ struct llc_opt {
u32 rx_pdu_hdr; /* used for saving header of last pdu u32 rx_pdu_hdr; /* used for saving header of last pdu
received and caused sending FRMR. received and caused sending FRMR.
Used for resending FRMR */ Used for resending FRMR */
#ifdef DEBUG_LLC_CONN_ALLOC
char *f_alloc, /* function that allocated this connection */
*f_free; /* function that freed this connection */
int l_alloc, /* line that allocated this connection */
l_free; /* line that freed this connection */
#endif
}; };
#define llc_sk(__sk) ((struct llc_opt *)(__sk)->protinfo) #define llc_sk(__sk) ((struct llc_opt *)(__sk)->protinfo)
struct llc_conn_state_ev;
extern struct sock *llc_sk_alloc(int family, int priority); extern struct sock *llc_sk_alloc(int family, int priority);
extern void llc_sk_free(struct sock *sk); extern void llc_sk_free(struct sock *sk);
...@@ -100,6 +92,9 @@ extern struct sock *llc_lookup_established(struct llc_sap *sap, ...@@ -100,6 +92,9 @@ extern struct sock *llc_lookup_established(struct llc_sap *sap,
struct llc_addr *laddr); struct llc_addr *laddr);
extern struct sock *llc_lookup_listener(struct llc_sap *sap, extern struct sock *llc_lookup_listener(struct llc_sap *sap,
struct llc_addr *laddr); struct llc_addr *laddr);
extern struct sock *llc_lookup_dgram(struct llc_sap *sap,
struct llc_addr *laddr);
extern void llc_save_primitive(struct sk_buff* skb, u8 prim);
extern u8 llc_data_accept_state(u8 state); extern u8 llc_data_accept_state(u8 state);
extern void llc_build_offset_table(void); extern void llc_build_offset_table(void);
#endif /* LLC_CONN_H */ #endif /* LLC_CONN_H */
...@@ -31,25 +31,11 @@ ...@@ -31,25 +31,11 @@
#define LLC_STATION_EV_RX_NULL_DSAP_TEST_C 8 #define LLC_STATION_EV_RX_NULL_DSAP_TEST_C 8
#define LLC_STATION_EV_DISABLE_REQ 9 #define LLC_STATION_EV_DISABLE_REQ 9
/* Interfaces for various types of supported events */
struct llc_stat_ev_simple_if {
u8 ev;
};
struct llc_stat_ev_prim_if {
u8 prim; /* connect, disconnect, reset, ... */
u8 type; /* request, indicate, response, confirm */
};
union llc_stat_ev_if {
struct llc_stat_ev_simple_if a; /* 'a' for simple, easy ... */
struct llc_stat_ev_prim_if prim;
};
struct llc_station_state_ev { struct llc_station_state_ev {
u8 type; u8 type;
u8 prim;
u8 prim_type;
u8 reason; u8 reason;
union llc_stat_ev_if data;
struct list_head node; /* node in station->ev_q.list */ struct list_head node; /* node in station->ev_q.list */
}; };
......
/* if_ether.h needed for definition of ETH_DATA_LEN and ETH_ALEN
*/
#include "linux/if_ether.h"
/* frame layout based on par3.2 "LLC PDU format"
*/
typedef union { /* pdu layout from pages 40 & 44 */
struct { /* general header, all pdu types */
unsigned dsap : 8; /* dest service access point */
unsigned ssap : 8; /* source service access point */
unsigned f1 : 1; /* I- U- or S- format id bits */
unsigned f2 : 1;
unsigned : 6;
unsigned : 8;
} pdu_hdr;
struct {
char dummy1[2]; /* dsap + ssap */
char byte1;
char byte2;
} pdu_cntl; /* unformatted control bytes */
struct { /* header of an Information pdu */
unsigned char dummy2[2];
unsigned : 1;
unsigned ns : 7;
unsigned i_pflag : 1; /* poll/final bit */
unsigned nr : 7; /* N(R) */
unsigned char is_info[ ETH_DATA_LEN ];
} i_hdr;
struct { /* header of a Supervisory pdu */
unsigned char dummy3[2];
unsigned : 2;
unsigned ss : 2; /* supervisory function bits */
unsigned : 4;
unsigned s_pflag : 1; /* poll/final bit */
unsigned nr : 7; /* N(R) */
} s_hdr;
/* when accessing the P/F bit or the N(R) field there's no need to distinguish
I pdus from S pdus i_pflag and s_pflag / i_nr and s_nr map to the same
physical location.
*/
struct { /* header of an Unnumbered pdu */
unsigned char dummy4[2];
unsigned : 2;
unsigned mm1 : 2; /* modifier function part1 */
unsigned u_pflag : 1; /* P/F for U- pdus */
unsigned mm2 : 3; /* modifier function part2 */
unsigned char u_info[ ETH_DATA_LEN-1];
} u_hdr;
struct { /* mm field in an Unnumbered pdu */
unsigned char dummy5[2];
unsigned : 2;
unsigned mm : 6; /* must be masked to get ridd of P/F ! */
} u_mm;
} frame_type, *frameptr;
/* frame format test macros: */
#define IS_UFRAME( fr ) ( ( (fr)->pdu_hdr.f1) & ( (fr)->pdu_hdr.f2) )
#define IS_IFRAME( fr ) ( !( (fr)->pdu_hdr.f1) )
#define IS_SFRAME( fr ) ( ( (fr)->pdu_hdr.f1) & !( (fr)->pdu_hdr.f2) )
#define IS_RSP( fr ) ( fr->pdu_hdr.ssap & 0x01 )
/* The transition table, the _encode tables and some tests in the
source code depend on the numeric order of these values.
Think twice before changing.
*/
/* frame names for TYPE 2 operation: */
#define I_CMD 0
#define RR_CMD 1
#define RNR_CMD 2
#define REJ_CMD 3
#define DISC_CMD 4
#define SABME_CMD 5
#define I_RSP 6
#define RR_RSP 7
#define RNR_RSP 8
#define REJ_RSP 9
#define UA_RSP 10
#define DM_RSP 11
#define FRMR_RSP 12
/* junk frame name: */
#define BAD_FRAME 13
#define NO_FRAME 13
/* frame names for TYPE 1 operation: */
#define UI_CMD 14
#define XID_CMD 15
#define TEST_CMD 16
#define XID_RSP 17
#define TEST_RSP 18
...@@ -17,17 +17,17 @@ ...@@ -17,17 +17,17 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/llc.h> #include <linux/llc.h>
#define LLC_DATAUNIT_PRIM 0 #define LLC_DATAUNIT_PRIM 1
#define LLC_CONN_PRIM 1 #define LLC_CONN_PRIM 2
#define LLC_DATA_PRIM 2 #define LLC_DATA_PRIM 3
#define LLC_DISC_PRIM 3 #define LLC_DISC_PRIM 4
#define LLC_RESET_PRIM 4 #define LLC_RESET_PRIM 5
#define LLC_FLOWCONTROL_PRIM 5 /* Not supported at this time */ #define LLC_FLOWCONTROL_PRIM 6 /* Not supported at this time */
#define LLC_DISABLE_PRIM 6 #define LLC_DISABLE_PRIM 7
#define LLC_XID_PRIM 7 #define LLC_XID_PRIM 8
#define LLC_TEST_PRIM 8 #define LLC_TEST_PRIM 9
#define LLC_SAP_ACTIVATION 9 #define LLC_SAP_ACTIVATION 10
#define LLC_SAP_DEACTIVATION 10 #define LLC_SAP_DEACTIVATION 11
#define LLC_NBR_PRIMITIVES 11 #define LLC_NBR_PRIMITIVES 11
...@@ -67,66 +67,22 @@ struct llc_addr { ...@@ -67,66 +67,22 @@ struct llc_addr {
u8 mac[IFHWADDRLEN]; u8 mac[IFHWADDRLEN];
}; };
struct llc_prim_reset {
struct sock *sk;
u16 link;
};
/* Sending data in conection-less mode */
struct llc_prim_unit_data {
struct llc_addr saddr;
struct llc_addr daddr;
u8 pri;
struct sk_buff *skb; /* pointer to frame */
u8 lfb; /* largest frame bit (TR) */
};
struct llc_prim_xid {
struct llc_addr saddr;
struct llc_addr daddr;
u8 pri;
struct sk_buff *skb;
};
struct llc_prim_test {
struct llc_addr saddr;
struct llc_addr daddr;
u8 pri;
struct sk_buff *skb; /* pointer to frame */
};
union llc_u_prim_data {
struct llc_prim_reset res;
struct llc_prim_unit_data udata; /* unit data */
struct llc_prim_xid xid;
struct llc_prim_test test;
};
struct llc_sap; struct llc_sap;
/* Information block passed with all called primitives */ extern struct llc_sap *llc_sap_open(u8 lsap,
struct llc_prim_if_block { int (*func)(struct sk_buff *skb,
struct llc_sap *sap; struct net_device *dev,
u8 prim; struct packet_type *pt));
union llc_u_prim_data *data;
};
typedef int (*llc_prim_call_t)(struct llc_prim_if_block *prim_if);
extern struct llc_sap *llc_sap_open(llc_prim_call_t network_indicate,
llc_prim_call_t network_confirm, u8 lsap);
extern void llc_sap_close(struct llc_sap *sap); extern void llc_sap_close(struct llc_sap *sap);
extern int llc_establish_connection(struct sock *sk, u8 *lmac, extern int llc_establish_connection(struct sock *sk, u8 *lmac,
u8 *dmac, u8 dsap); u8 *dmac, u8 dsap);
extern int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb); extern int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb);
extern void llc_build_and_send_ui_pkt(struct llc_sap *sap, extern void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
struct sk_buff *skb,
u8 *dmac, u8 dsap); u8 *dmac, u8 dsap);
extern void llc_build_and_send_xid_pkt(struct llc_sap *sap, extern void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb,
struct sk_buff *skb,
u8 *dmac, u8 dsap); u8 *dmac, u8 dsap);
extern void llc_build_and_send_test_pkt(struct llc_sap *sap, extern void llc_build_and_send_test_pkt(struct llc_sap *sap, struct sk_buff *skb,
struct sk_buff *skb,
u8 *dmac, u8 dsap); u8 *dmac, u8 dsap);
extern int llc_send_disc(struct sock *sk); extern int llc_send_disc(struct sock *sk);
#endif /* LLC_IF_H */ #endif /* LLC_IF_H */
...@@ -43,7 +43,7 @@ struct llc_station { ...@@ -43,7 +43,7 @@ struct llc_station {
u8 maximum_retry; u8 maximum_retry;
u8 mac_sa[6]; u8 mac_sa[6];
struct { struct {
spinlock_t lock; rwlock_t lock;
struct list_head list; struct list_head list;
} sap_list; } sap_list;
struct { struct {
...@@ -52,7 +52,6 @@ struct llc_station { ...@@ -52,7 +52,6 @@ struct llc_station {
} ev_q; } ev_q;
struct sk_buff_head mac_pdu_q; struct sk_buff_head mac_pdu_q;
}; };
struct llc_station_state_ev;
extern struct llc_sap *llc_sap_alloc(void); extern struct llc_sap *llc_sap_alloc(void);
extern void llc_sap_save(struct llc_sap *sap); extern void llc_sap_save(struct llc_sap *sap);
......
char *frame_names[] =
{"I_CMD","RR_CMD","RNR_CMD","REJ_CMD","DISC_CMD",
"SABME_CMD","I_RSP","RR_RSP","RNR_RSP","REJ_RSP",
"UA_RSP","DM_RSP","FRMR_RSP","BAD_FRAME","UI_CMD",
"XID_CMD","TEST_CMD","XID_RSP","TEST_RSP"
};
...@@ -34,37 +34,14 @@ ...@@ -34,37 +34,14 @@
#define LLC_SAP_EV_RX_TEST_R 9 #define LLC_SAP_EV_RX_TEST_R 9
#define LLC_SAP_EV_DEACTIVATION_REQ 10 #define LLC_SAP_EV_DEACTIVATION_REQ 10
/* Interfaces for various types of supported events */
struct llc_sap_ev_simple_if {
u8 ev;
};
struct llc_prim_if_block;
struct llc_sap_ev_prim_if {
u8 prim; /* connect, disconnect, reset, ... */
u8 type; /* request, indicate, response, conf */
struct llc_prim_if_block *data;
};
struct llc_sap_ev_pdu_if {
u8 ev;
};
union llc_sap_ev_if {
struct llc_sap_ev_simple_if a; /* 'a' for simple, easy ... */
struct llc_sap_ev_prim_if prim;
struct llc_sap_ev_pdu_if pdu;
};
struct llc_prim_if_block;
struct llc_sap_state_ev { struct llc_sap_state_ev {
u8 prim;
u8 prim_type;
u8 type; u8 type;
u8 reason; u8 reason;
u8 ind_cfm_flag; u8 ind_cfm_flag;
struct llc_prim_if_block *prim; struct llc_addr saddr;
union llc_sap_ev_if data; struct llc_addr daddr;
}; };
static __inline__ struct llc_sap_state_ev *llc_sap_ev(struct sk_buff *skb) static __inline__ struct llc_sap_state_ev *llc_sap_ev(struct sk_buff *skb)
......
...@@ -12,36 +12,33 @@ ...@@ -12,36 +12,33 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/llc_if.h>
/** /**
* struct llc_sap - Defines the SAP component * struct llc_sap - Defines the SAP component
* *
* @station - station this sap belongs to
* @state - sap state
* @p_bit - only lowest-order bit used * @p_bit - only lowest-order bit used
* @f_bit - only lowest-order bit used * @f_bit - only lowest-order bit used
* @ind - provided by network layer
* @conf - provided by network layer
* @laddr - SAP value in this 'lsap' * @laddr - SAP value in this 'lsap'
* @node - entry in station sap_list * @node - entry in station sap_list
* @sk_list - LLC sockets this one manages * @sk_list - LLC sockets this one manages
* @mac_pdu_q - PDUs ready to send to MAC
*/ */
struct llc_sap { struct llc_sap {
struct llc_station *parent_station; struct llc_station *station;
u8 state; u8 state;
u8 p_bit; u8 p_bit;
u8 f_bit; u8 f_bit;
llc_prim_call_t ind; int (*rcv_func)(struct sk_buff *skb,
llc_prim_call_t conf; struct net_device *dev,
struct llc_prim_if_block llc_ind_prim, llc_cfm_prim; struct packet_type *pt);
union llc_u_prim_data llc_ind_data_prim, llc_cfm_data_prim;
struct llc_addr laddr; struct llc_addr laddr;
struct list_head node; struct list_head node;
struct { struct {
spinlock_t lock; rwlock_t lock;
struct list_head list; struct sock *list;
} sk_list; } sk_list;
struct sk_buff_head mac_pdu_q;
}; };
struct llc_sap_state_ev;
extern void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk); extern void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk);
extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk); extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk);
......
char *state_names[] = {
"ADM","CONN","RESET_WAIT","RESET_CHECK","SETUP",
"RESET","D_CONN","ERROR","NORMAL"
};
...@@ -51,6 +51,25 @@ struct ra_msg { ...@@ -51,6 +51,25 @@ struct ra_msg {
__u32 retrans_timer; __u32 retrans_timer;
}; };
struct nd_opt_hdr {
__u8 nd_opt_type;
__u8 nd_opt_len;
} __attribute__((__packed__));
struct ndisc_options {
struct nd_opt_hdr *nd_opt_array[7];
struct nd_opt_hdr *nd_opt_piend;
};
#define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
#define nd_opts_tgt_lladdr nd_opt_array[ND_OPT_TARGET_LL_ADDR]
#define nd_opts_pi nd_opt_array[ND_OPT_PREFIX_INFO]
#define nd_opts_pi_end nd_opt_piend
#define nd_opts_rh nd_opt_array[ND_OPT_REDIRECT_HDR]
#define nd_opts_mtu nd_opt_array[ND_OPT_MTU]
extern struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, struct nd_opt_hdr *end);
extern struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, struct ndisc_options *ndopts);
extern int ndisc_init(struct net_proto_family *ops); extern int ndisc_init(struct net_proto_family *ops);
......
#ifndef _NET_P8022_H #ifndef _NET_P8022_H
#define _NET_P8022_H #define _NET_P8022_H
#include <net/llc_if.h> extern struct datalink_proto *
register_8022_client(unsigned char type,
extern struct datalink_proto *register_8022_client(unsigned char type, int (*func)(struct sk_buff *skb,
int (*indicate)(struct llc_prim_if_block *prim)); struct net_device *dev,
struct packet_type *pt));
extern void unregister_8022_client(struct datalink_proto *proto); extern void unregister_8022_client(struct datalink_proto *proto);
#endif #endif
...@@ -112,6 +112,7 @@ typedef enum { ...@@ -112,6 +112,7 @@ typedef enum {
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN,
SCTP_EVENT_TIMEOUT_T3_RTX, SCTP_EVENT_TIMEOUT_T3_RTX,
SCTP_EVENT_TIMEOUT_T4_RTO, SCTP_EVENT_TIMEOUT_T4_RTO,
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD,
SCTP_EVENT_TIMEOUT_HEARTBEAT, SCTP_EVENT_TIMEOUT_HEARTBEAT,
SCTP_EVENT_TIMEOUT_SACK, SCTP_EVENT_TIMEOUT_SACK,
SCTP_EVENT_TIMEOUT_AUTOCLOSE, SCTP_EVENT_TIMEOUT_AUTOCLOSE,
......
...@@ -114,7 +114,8 @@ extern sctp_protocol_t sctp_proto; ...@@ -114,7 +114,8 @@ extern sctp_protocol_t sctp_proto;
extern struct sock *sctp_get_ctl_sock(void); extern struct sock *sctp_get_ctl_sock(void);
extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *, extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *,
sctp_scope_t, int priority, int flags); sctp_scope_t, int priority, int flags);
extern sctp_pf_t *sctp_get_pf_specific(int family);
extern void sctp_set_pf_specific(int family, sctp_pf_t *);
/* /*
* sctp_socket.c * sctp_socket.c
......
...@@ -107,6 +107,9 @@ sctp_state_fn_t sctp_sf_timer_ignore; ...@@ -107,6 +107,9 @@ sctp_state_fn_t sctp_sf_timer_ignore;
sctp_state_fn_t sctp_sf_do_9_1_abort; sctp_state_fn_t sctp_sf_do_9_1_abort;
sctp_state_fn_t sctp_sf_cookie_wait_abort; sctp_state_fn_t sctp_sf_cookie_wait_abort;
sctp_state_fn_t sctp_sf_cookie_echoed_abort; sctp_state_fn_t sctp_sf_cookie_echoed_abort;
sctp_state_fn_t sctp_sf_shutdown_pending_abort;
sctp_state_fn_t sctp_sf_shutdown_sent_abort;
sctp_state_fn_t sctp_sf_shutdown_ack_sent_abort;
sctp_state_fn_t sctp_sf_do_5_1B_init; sctp_state_fn_t sctp_sf_do_5_1B_init;
sctp_state_fn_t sctp_sf_do_5_1C_ack; sctp_state_fn_t sctp_sf_do_5_1C_ack;
sctp_state_fn_t sctp_sf_do_5_1D_ce; sctp_state_fn_t sctp_sf_do_5_1D_ce;
...@@ -119,6 +122,7 @@ sctp_state_fn_t sctp_sf_tabort_8_4_8; ...@@ -119,6 +122,7 @@ sctp_state_fn_t sctp_sf_tabort_8_4_8;
sctp_state_fn_t sctp_sf_operr_notify; sctp_state_fn_t sctp_sf_operr_notify;
sctp_state_fn_t sctp_sf_t1_timer_expire; sctp_state_fn_t sctp_sf_t1_timer_expire;
sctp_state_fn_t sctp_sf_t2_timer_expire; sctp_state_fn_t sctp_sf_t2_timer_expire;
sctp_state_fn_t sctp_sf_t5_timer_expire;
sctp_state_fn_t sctp_sf_sendbeat_8_3; sctp_state_fn_t sctp_sf_sendbeat_8_3;
sctp_state_fn_t sctp_sf_beat_8_3; sctp_state_fn_t sctp_sf_beat_8_3;
sctp_state_fn_t sctp_sf_backbeat_8_3; sctp_state_fn_t sctp_sf_backbeat_8_3;
...@@ -134,6 +138,7 @@ sctp_state_fn_t sctp_sf_discard_chunk; ...@@ -134,6 +138,7 @@ sctp_state_fn_t sctp_sf_discard_chunk;
sctp_state_fn_t sctp_sf_do_5_2_1_siminit; sctp_state_fn_t sctp_sf_do_5_2_1_siminit;
sctp_state_fn_t sctp_sf_do_5_2_2_dupinit; sctp_state_fn_t sctp_sf_do_5_2_2_dupinit;
sctp_state_fn_t sctp_sf_do_5_2_4_dupcook; sctp_state_fn_t sctp_sf_do_5_2_4_dupcook;
sctp_state_fn_t sctp_sf_unk_chunk;
/* Prototypes for primitive event state functions. */ /* Prototypes for primitive event state functions. */
sctp_state_fn_t sctp_sf_do_prm_asoc; sctp_state_fn_t sctp_sf_do_prm_asoc;
...@@ -144,6 +149,9 @@ sctp_state_fn_t sctp_sf_cookie_echoed_prm_shutdown; ...@@ -144,6 +149,9 @@ sctp_state_fn_t sctp_sf_cookie_echoed_prm_shutdown;
sctp_state_fn_t sctp_sf_do_9_1_prm_abort; sctp_state_fn_t sctp_sf_do_9_1_prm_abort;
sctp_state_fn_t sctp_sf_cookie_wait_prm_abort; sctp_state_fn_t sctp_sf_cookie_wait_prm_abort;
sctp_state_fn_t sctp_sf_cookie_echoed_prm_abort; sctp_state_fn_t sctp_sf_cookie_echoed_prm_abort;
sctp_state_fn_t sctp_sf_shutdown_pending_prm_abort;
sctp_state_fn_t sctp_sf_shutdown_sent_prm_abort;
sctp_state_fn_t sctp_sf_shutdown_ack_sent_prm_abort;
sctp_state_fn_t sctp_sf_error_closed; sctp_state_fn_t sctp_sf_error_closed;
sctp_state_fn_t sctp_sf_error_shutdown; sctp_state_fn_t sctp_sf_error_shutdown;
sctp_state_fn_t sctp_sf_ignore_primitive; sctp_state_fn_t sctp_sf_ignore_primitive;
......
...@@ -255,6 +255,12 @@ typedef struct sctp_func { ...@@ -255,6 +255,12 @@ typedef struct sctp_func {
sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address); sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address);
/* Protocol family functions. */
typedef struct sctp_pf {
void (*event_msgname)(sctp_ulpevent_t *, char *, int *);
void (*skb_msgname)(struct sk_buff *, char *, int *);
} sctp_pf_t;
/* SCTP Socket type: UDP or TCP style. */ /* SCTP Socket type: UDP or TCP style. */
typedef enum { typedef enum {
SCTP_SOCKET_UDP = 0, SCTP_SOCKET_UDP = 0,
...@@ -280,6 +286,7 @@ struct sctp_opt { ...@@ -280,6 +286,7 @@ struct sctp_opt {
__u32 autoclose; __u32 autoclose;
__u8 nodelay; __u8 nodelay;
__u8 disable_fragments; __u8 disable_fragments;
sctp_pf_t *pf;
}; };
...@@ -845,6 +852,7 @@ int sctp_outqueue_set_output_handlers(sctp_outqueue_t *, ...@@ -845,6 +852,7 @@ int sctp_outqueue_set_output_handlers(sctp_outqueue_t *,
sctp_outqueue_ohandler_force_t force); sctp_outqueue_ohandler_force_t force);
void sctp_outqueue_restart(sctp_outqueue_t *); void sctp_outqueue_restart(sctp_outqueue_t *);
void sctp_retransmit(sctp_outqueue_t *, sctp_transport_t *, __u8); void sctp_retransmit(sctp_outqueue_t *, sctp_transport_t *, __u8);
void sctp_retransmit_mark(sctp_outqueue_t *, sctp_transport_t *, __u8);
/* These bind address data fields common between endpoints and associations */ /* These bind address data fields common between endpoints and associations */
...@@ -1128,6 +1136,11 @@ struct SCTP_association { ...@@ -1128,6 +1136,11 @@ struct SCTP_association {
*/ */
sctp_transport_t *primary_path; sctp_transport_t *primary_path;
/* Cache the primary path address here, when we
* need a an address for msg_name.
*/
sockaddr_storage_t primary_addr;
/* active_path /* active_path
* The path that we are currently using to * The path that we are currently using to
* transmit new data and most control chunks. * transmit new data and most control chunks.
...@@ -1183,7 +1196,7 @@ struct SCTP_association { ...@@ -1183,7 +1196,7 @@ struct SCTP_association {
int next_dup_tsn; int next_dup_tsn;
/* Do we need to sack the peer? */ /* Do we need to sack the peer? */
int sack_needed; uint8_t sack_needed;
/* These are capabilities which our peer advertised. */ /* These are capabilities which our peer advertised. */
__u8 ecn_capable; /* Can peer do ECN? */ __u8 ecn_capable; /* Can peer do ECN? */
......
...@@ -103,7 +103,7 @@ enum { ...@@ -103,7 +103,7 @@ enum {
struct x25_route { struct x25_route {
struct x25_route *next; struct x25_route *next;
x25_address address; /* Start of address range */ struct x25_address address; /* Start of address range */
unsigned int sigdigits; /* Number of sig digits */ unsigned int sigdigits; /* Number of sig digits */
struct net_device *dev; /* More than one for MLP */ struct net_device *dev; /* More than one for MLP */
}; };
...@@ -120,7 +120,7 @@ struct x25_neigh { ...@@ -120,7 +120,7 @@ struct x25_neigh {
}; };
typedef struct { typedef struct {
x25_address source_addr, dest_addr; struct x25_address source_addr, dest_addr;
struct x25_neigh *neighbour; struct x25_neigh *neighbour;
unsigned int lci; unsigned int lci;
unsigned char state, condition, qbitincl, intflag; unsigned char state, condition, qbitincl, intflag;
...@@ -148,8 +148,10 @@ extern int sysctl_x25_reset_request_timeout; ...@@ -148,8 +148,10 @@ extern int sysctl_x25_reset_request_timeout;
extern int sysctl_x25_clear_request_timeout; extern int sysctl_x25_clear_request_timeout;
extern int sysctl_x25_ack_holdback_timeout; extern int sysctl_x25_ack_holdback_timeout;
extern int x25_addr_ntoa(unsigned char *, x25_address *, x25_address *); extern int x25_addr_ntoa(unsigned char *, struct x25_address *,
extern int x25_addr_aton(unsigned char *, x25_address *, x25_address *); struct x25_address *);
extern int x25_addr_aton(unsigned char *, struct x25_address *,
struct x25_address *);
extern unsigned int x25_new_lci(struct x25_neigh *); extern unsigned int x25_new_lci(struct x25_neigh *);
extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *); extern struct sock *x25_find_socket(unsigned int, struct x25_neigh *);
extern void x25_destroy_socket(struct sock *); extern void x25_destroy_socket(struct sock *);
...@@ -194,7 +196,7 @@ extern void x25_kick(struct sock *); ...@@ -194,7 +196,7 @@ extern void x25_kick(struct sock *);
extern void x25_enquiry_response(struct sock *); extern void x25_enquiry_response(struct sock *);
/* x25_route.c */ /* x25_route.c */
extern struct net_device *x25_get_route(x25_address *); extern struct net_device *x25_get_route(struct x25_address *);
extern struct net_device *x25_dev_get(char *); extern struct net_device *x25_dev_get(char *);
extern void x25_route_device_down(struct net_device *); extern void x25_route_device_down(struct net_device *);
extern int x25_route_ioctl(unsigned int, void *); extern int x25_route_ioctl(unsigned int, void *);
......
...@@ -33,7 +33,9 @@ static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb, ...@@ -33,7 +33,9 @@ static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb,
} }
struct datalink_proto *register_8022_client(unsigned char type, struct datalink_proto *register_8022_client(unsigned char type,
int (*indicate)(struct llc_prim_if_block *prim)) int (*func)(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt))
{ {
struct datalink_proto *proto; struct datalink_proto *proto;
...@@ -42,7 +44,7 @@ struct datalink_proto *register_8022_client(unsigned char type, ...@@ -42,7 +44,7 @@ struct datalink_proto *register_8022_client(unsigned char type,
proto->type[0] = type; proto->type[0] = type;
proto->header_length = 3; proto->header_length = 3;
proto->request = p8022_request; proto->request = p8022_request;
proto->sap = llc_sap_open(indicate, NULL, type); proto->sap = llc_sap_open(type, func);
if (!proto->sap) { if (!proto->sap) {
kfree(proto); kfree(proto);
proto = NULL; proto = NULL;
......
...@@ -51,32 +51,26 @@ static struct datalink_proto *find_snap_client(unsigned char *desc) ...@@ -51,32 +51,26 @@ static struct datalink_proto *find_snap_client(unsigned char *desc)
/* /*
* A SNAP packet has arrived * A SNAP packet has arrived
*/ */
static int snap_indicate(struct llc_prim_if_block *prim) static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt)
{ {
struct sk_buff *skb;
struct datalink_proto *proto;
int rc = 1; int rc = 1;
static struct packet_type psnap_packet_type = { struct datalink_proto *proto = find_snap_client(skb->h.raw);
static struct packet_type snap_packet_type = {
.type = __constant_htons(ETH_P_SNAP), .type = __constant_htons(ETH_P_SNAP),
}; };
if (prim->prim != LLC_DATAUNIT_PRIM)
goto out;
skb = prim->data->udata.skb;
proto = find_snap_client(skb->h.raw);
if (proto) { if (proto) {
/* Pass the frame on. */ /* Pass the frame on. */
skb->h.raw += 5; skb->h.raw += 5;
skb_pull(skb, 5); skb_pull(skb, 5);
rc = proto->rcvfunc(skb, skb->dev, &psnap_packet_type); rc = proto->rcvfunc(skb, dev, &snap_packet_type);
} else { } else {
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb); kfree_skb(skb);
rc = 1; rc = 1;
} }
out:
return rc; return rc;
} }
...@@ -99,7 +93,7 @@ EXPORT_SYMBOL(unregister_snap_client); ...@@ -99,7 +93,7 @@ EXPORT_SYMBOL(unregister_snap_client);
static int __init snap_init(void) static int __init snap_init(void)
{ {
snap_sap = llc_sap_open(snap_indicate, NULL, 0xAA); snap_sap = llc_sap_open(0xAA, snap_rcv);
if (!snap_sap) if (!snap_sap)
printk(KERN_CRIT "SNAP - unable to register with 802.2\n"); printk(KERN_CRIT "SNAP - unable to register with 802.2\n");
......
...@@ -1252,7 +1252,7 @@ static struct ip_fwkernel *convert_ipfw(struct ip_fwuser *fwuser, int *errno) ...@@ -1252,7 +1252,7 @@ static struct ip_fwkernel *convert_ipfw(struct ip_fwuser *fwuser, int *errno)
return NULL; return NULL;
} }
fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_KERNEL); fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_ATOMIC);
if (!fwkern) { if (!fwkern) {
duprintf("convert_ipfw: kmalloc failed!\n"); duprintf("convert_ipfw: kmalloc failed!\n");
*errno = ENOMEM; *errno = ENOMEM;
......
...@@ -159,6 +159,67 @@ static u8 *ndisc_fill_option(u8 *opt, int type, void *data, int data_len) ...@@ -159,6 +159,67 @@ static u8 *ndisc_fill_option(u8 *opt, int type, void *data, int data_len)
return opt + space; return opt + space;
} }
struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
struct nd_opt_hdr *end)
{
int type;
if (!cur || !end || cur >= end)
return NULL;
type = cur->nd_opt_type;
do {
cur = ((void *)cur) + (cur->nd_opt_len << 3);
} while(cur < end && cur->nd_opt_type != type);
return (cur <= end && cur->nd_opt_type == type ? cur : NULL);
}
struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
struct ndisc_options *ndopts)
{
struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
if (!nd_opt || opt_len < 0 || !ndopts)
return NULL;
memset(ndopts, 0, sizeof(*ndopts));
while (opt_len) {
int l;
if (opt_len < sizeof(struct nd_opt_hdr))
return NULL;
l = nd_opt->nd_opt_len << 3;
if (opt_len < l || l == 0)
return NULL;
switch (nd_opt->nd_opt_type) {
case ND_OPT_SOURCE_LL_ADDR:
case ND_OPT_TARGET_LL_ADDR:
case ND_OPT_MTU:
case ND_OPT_REDIRECT_HDR:
if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
ND_PRINTK2((KERN_WARNING
"ndisc_parse_options(): duplicated ND6 option found: type=%d\n",
nd_opt->nd_opt_type));
} else {
ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
}
break;
case ND_OPT_PREFIX_INFO:
ndopts->nd_opts_pi_end = nd_opt;
if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0)
ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
break;
default:
/*
* Unknown options must be silently ignored,
* to accomodate future extension to the protocol.
*/
ND_PRINTK2(KERN_WARNING
"ndisc_parse_options(): ignored unsupported option; type=%d, len=%d\n",
nd_opt->nd_opt_type, nd_opt->nd_opt_len);
}
opt_len -= l;
nd_opt = ((void *)nd_opt) + l;
}
return ndopts;
}
int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir) int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir)
{ {
switch (dev->type) { switch (dev->type) {
...@@ -489,27 +550,6 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, ...@@ -489,27 +550,6 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
} }
static u8 * ndisc_find_option(u8 *opt, int opt_len, int len, int option)
{
while (opt_len <= len) {
int l = opt[1]<<3;
if (opt[0] == option && l >= opt_len)
return opt + 2;
if (l == 0) {
if (net_ratelimit())
printk(KERN_WARNING "ndisc: option has 0 len\n");
return NULL;
}
opt += l;
len -= l;
}
return NULL;
}
static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb) static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
{ {
/* /*
...@@ -547,13 +587,6 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) ...@@ -547,13 +587,6 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
} }
} }
static void ndisc_update(struct neighbour *neigh, u8* opt, int len, int type)
{
opt = ndisc_find_option(opt, neigh->dev->addr_len+2, len, type);
neigh_update(neigh, opt, NUD_STALE, 1, 1);
}
static void ndisc_router_discovery(struct sk_buff *skb) static void ndisc_router_discovery(struct sk_buff *skb)
{ {
struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw; struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
...@@ -561,6 +594,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -561,6 +594,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
struct inet6_dev *in6_dev; struct inet6_dev *in6_dev;
struct rt6_info *rt; struct rt6_info *rt;
int lifetime; int lifetime;
struct ndisc_options ndopts;
int optlen; int optlen;
__u8 * opt = (__u8 *)(ra_msg + 1); __u8 * opt = (__u8 *)(ra_msg + 1);
...@@ -592,6 +626,13 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -592,6 +626,13 @@ static void ndisc_router_discovery(struct sk_buff *skb)
return; return;
} }
if (!ndisc_parse_options(opt, optlen, &ndopts)) {
if (net_ratelimit())
ND_PRINTK2(KERN_WARNING
"ICMP6 RA: invalid ND option, ignored.\n");
return;
}
if (in6_dev->if_flags & IF_RS_SENT) { if (in6_dev->if_flags & IF_RS_SENT) {
/* /*
* flag that an RA was received after an RS was sent * flag that an RA was received after an RS was sent
...@@ -675,40 +716,42 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -675,40 +716,42 @@ static void ndisc_router_discovery(struct sk_buff *skb)
* Process options. * Process options.
*/ */
while (optlen > 0) { if (rt && (neigh = rt->rt6i_nexthop) != NULL) {
int len = (opt[1] << 3); u8 *lladdr = NULL;
int lladdrlen;
if (len == 0) { if (ndopts.nd_opts_src_lladdr) {
ND_PRINTK0("RA: opt has 0 len\n"); lladdr = (u8*)((ndopts.nd_opts_src_lladdr)+1);
break; lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
if (net_ratelimit())
ND_PRINTK2(KERN_WARNING
"ICMP6 RA: Invalid lladdr length.\n");
goto out;
}
}
neigh_update(neigh, lladdr, NUD_STALE, 1, 1);
} }
switch(*opt) { if (ndopts.nd_opts_pi) {
case ND_OPT_SOURCE_LL_ADDR: struct nd_opt_hdr *p;
for (p = ndopts.nd_opts_pi;
if (rt == NULL) p;
break; p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) {
addrconf_prefix_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3);
if ((neigh = rt->rt6i_nexthop) != NULL && }
skb->dev->addr_len + 2 >= len) }
neigh_update(neigh, opt+2, NUD_STALE, 1, 1);
break;
case ND_OPT_PREFIX_INFO:
addrconf_prefix_rcv(skb->dev, opt, len);
break;
case ND_OPT_MTU: if (ndopts.nd_opts_mtu) {
{ u32 mtu;
int mtu;
mtu = htonl(*(__u32 *)(opt+4)); memcpy(&mtu, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
mtu = ntohl(mtu);
if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) { if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
ND_PRINTK0("NDISC: router " if (net_ratelimit()) {
"announcement with mtu = %d\n", ND_PRINTK0("NDISC: router announcement with mtu = %d\n",
mtu); mtu);
break; }
} }
if (in6_dev->cnf.mtu6 != mtu) { if (in6_dev->cnf.mtu6 != mtu) {
...@@ -720,18 +763,13 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -720,18 +763,13 @@ static void ndisc_router_discovery(struct sk_buff *skb)
rt6_mtu_change(skb->dev, mtu); rt6_mtu_change(skb->dev, mtu);
} }
} }
break;
case ND_OPT_TARGET_LL_ADDR: if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) {
case ND_OPT_REDIRECT_HDR: if (net_ratelimit())
ND_PRINTK0("got illegal option with RA"); ND_PRINTK0(KERN_WARNING
break; "ICMP6 RA: got illegal option with RA");
default:
ND_PRINTK0("unkown option in RA\n");
};
optlen -= len;
opt += len;
} }
out:
if (rt) if (rt)
dst_release(&rt->u.dst); dst_release(&rt->u.dst);
in6_dev_put(in6_dev); in6_dev_put(in6_dev);
...@@ -745,7 +783,10 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) ...@@ -745,7 +783,10 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
struct in6_addr *target; /* new first hop to destination */ struct in6_addr *target; /* new first hop to destination */
struct neighbour *neigh; struct neighbour *neigh;
int on_link = 0; int on_link = 0;
struct ndisc_options ndopts;
int optlen; int optlen;
u8 *lladdr = NULL;
int lladdrlen;
if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) { if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
if (net_ratelimit()) if (net_ratelimit())
...@@ -793,6 +834,24 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) ...@@ -793,6 +834,24 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
* first-hop router for the specified ICMP Destination Address. * first-hop router for the specified ICMP Destination Address.
*/ */
if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
if (net_ratelimit())
ND_PRINTK2(KERN_WARNING
"ICMP6 Redirect: invalid ND options, rejected.\n");
in6_dev_put(in6_dev);
return;
}
if (ndopts.nd_opts_tgt_lladdr) {
lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);
lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
if (net_ratelimit())
ND_PRINTK2(KERN_WARNING
"ICMP6 Redirect: invalid lladdr length.\n");
in6_dev_put(in6_dev);
return;
}
}
/* passed validation tests */ /* passed validation tests */
/* /*
...@@ -801,7 +860,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) ...@@ -801,7 +860,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
if (neigh) { if (neigh) {
ndisc_update(neigh, (u8*)(dest + 1), optlen, ND_OPT_TARGET_LL_ADDR); neigh_update(neigh, lladdr, NUD_STALE, 1, 1);
if (neigh->nud_state&NUD_VALID) if (neigh->nud_state&NUD_VALID)
rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, on_link); rt6_redirect(dest, &skb->nh.ipv6h->saddr, neigh, on_link);
else else
...@@ -927,31 +986,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, ...@@ -927,31 +986,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
ICMP6_INC_STATS(Icmp6OutMsgs); ICMP6_INC_STATS(Icmp6OutMsgs);
} }
static __inline__ struct neighbour *
ndisc_recv_ns(struct in6_addr *saddr, struct sk_buff *skb)
{
u8 *opt;
opt = skb->h.raw;
opt += sizeof(struct nd_msg);
opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_SOURCE_LL_ADDR);
return neigh_event_ns(&nd_tbl, opt, saddr, skb->dev);
}
static __inline__ int ndisc_recv_na(struct neighbour *neigh, struct sk_buff *skb)
{
u8 *opt;
struct nd_msg *msg = (struct nd_msg*) skb->h.raw;
opt = ndisc_find_option(msg->opt, skb->dev->addr_len+2,
skb->tail - msg->opt, ND_OPT_TARGET_LL_ADDR);
return neigh_update(neigh, opt,
msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
msg->icmph.icmp6_override, 1);
}
static void pndisc_redo(struct sk_buff *skb) static void pndisc_redo(struct sk_buff *skb)
{ {
ndisc_rcv(skb); ndisc_rcv(skb);
...@@ -983,13 +1017,15 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -983,13 +1017,15 @@ int ndisc_rcv(struct sk_buff *skb)
return 0; return 0;
} }
/* XXX: RFC2461 Validation of [all ndisc messages]:
* All included ndisc options MUST be of non-zero length
* (Some checking in ndisc_find_option)
*/
switch (msg->icmph.icmp6_type) { switch (msg->icmph.icmp6_type) {
case NDISC_NEIGHBOUR_SOLICITATION: case NDISC_NEIGHBOUR_SOLICITATION:
{
struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
u8 *lladdr = NULL;
int lladdrlen = 0;
u32 ndoptlen = skb->tail - msg->opt;
struct ndisc_options ndopts;
if (skb->len < sizeof(struct nd_msg)) { if (skb->len < sizeof(struct nd_msg)) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_WARNING "ICMP NS: packet too short\n"); printk(KERN_WARNING "ICMP NS: packet too short\n");
...@@ -1002,6 +1038,22 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1002,6 +1038,22 @@ int ndisc_rcv(struct sk_buff *skb)
return 0; return 0;
} }
if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
return 0;
}
if (ndopts.nd_opts_src_lladdr) {
lladdr = (u8*)(ndopts.nd_opts_src_lladdr + 1);
lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP NS: bad lladdr length.\n");
return 0;
}
}
/* XXX: RFC2461 7.1.1: /* XXX: RFC2461 7.1.1:
* If the IP source address is the unspecified address, there * If the IP source address is the unspecified address, there
* MUST NOT be source link-layer address option in the message. * MUST NOT be source link-layer address option in the message.
...@@ -1068,7 +1120,7 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1068,7 +1120,7 @@ int ndisc_rcv(struct sk_buff *skb)
* for the source adddress * for the source adddress
*/ */
neigh = ndisc_recv_ns(saddr, skb); neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
if (neigh || !dev->hard_header) { if (neigh || !dev->hard_header) {
ndisc_send_na(dev, neigh, saddr, &ifp->addr, ndisc_send_na(dev, neigh, saddr, &ifp->addr,
...@@ -1098,7 +1150,8 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1098,7 +1150,8 @@ int ndisc_rcv(struct sk_buff *skb)
else else
nd_tbl.stats.rcv_probes_ucast++; nd_tbl.stats.rcv_probes_ucast++;
neigh = ndisc_recv_ns(saddr, skb);
neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
if (neigh) { if (neigh) {
ndisc_send_na(dev, neigh, saddr, &msg->target, ndisc_send_na(dev, neigh, saddr, &msg->target,
...@@ -1118,8 +1171,16 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1118,8 +1171,16 @@ int ndisc_rcv(struct sk_buff *skb)
} }
return 0; return 0;
}
case NDISC_NEIGHBOUR_ADVERTISEMENT: case NDISC_NEIGHBOUR_ADVERTISEMENT:
{
struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
u8 *lladdr = NULL;
int lladdrlen = 0;
u32 ndoptlen = skb->tail - msg->opt;
struct ndisc_options ndopts;
if (skb->len < sizeof(struct nd_msg)) { if (skb->len < sizeof(struct nd_msg)) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_WARNING "ICMP NA: packet too short\n"); printk(KERN_WARNING "ICMP NA: packet too short\n");
...@@ -1138,6 +1199,20 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1138,6 +1199,20 @@ int ndisc_rcv(struct sk_buff *skb)
return 0; return 0;
} }
if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
return 0;
}
if (ndopts.nd_opts_tgt_lladdr) {
lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);
lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
if (net_ratelimit())
printk(KERN_WARNING "NDISC NA: invalid lladdr length.\n");
return 0;
}
}
if ((ifp = ipv6_get_ifaddr(&msg->target, dev))) { if ((ifp = ipv6_get_ifaddr(&msg->target, dev))) {
if (ifp->flags & IFA_F_TENTATIVE) { if (ifp->flags & IFA_F_TENTATIVE) {
addrconf_dad_failure(ifp); addrconf_dad_failure(ifp);
...@@ -1175,10 +1250,13 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1175,10 +1250,13 @@ int ndisc_rcv(struct sk_buff *skb)
neigh->flags |= NTF_ROUTER; neigh->flags |= NTF_ROUTER;
} }
ndisc_recv_na(neigh, skb); neigh_update(neigh, lladdr,
msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
msg->icmph.icmp6_override, 1);
neigh_release(neigh); neigh_release(neigh);
} }
break; break;
}
case NDISC_ROUTER_ADVERTISEMENT: case NDISC_ROUTER_ADVERTISEMENT:
ndisc_router_discovery(skb); ndisc_router_discovery(skb);
......
...@@ -2252,22 +2252,6 @@ drop: kfree_skb(skb); ...@@ -2252,22 +2252,6 @@ drop: kfree_skb(skb);
out: return ret; out: return ret;
} }
static int ipx_8022_indicate(struct llc_prim_if_block *prim)
{
int rc = 1;
static struct packet_type p8022_packet_type = {
.type = __constant_htons(ETH_P_802_2),
};
if (prim->prim == LLC_DATAUNIT_PRIM) {
struct sk_buff *skb = prim->data->udata.skb;
rc = ipx_rcv(skb, skb->dev, &p8022_packet_type);
}
return rc;
}
static int ipx_sendmsg(struct socket *sock, struct msghdr *msg, int len, static int ipx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct scm_cookie *scm) struct scm_cookie *scm)
{ {
...@@ -2560,7 +2544,7 @@ static int __init ipx_init(void) ...@@ -2560,7 +2544,7 @@ static int __init ipx_init(void)
else else
printk(ipx_8023_err_msg); printk(ipx_8023_err_msg);
p8022_datalink = register_8022_client(ipx_8022_type, ipx_8022_indicate); p8022_datalink = register_8022_client(ipx_8022_type, ipx_rcv);
if (!p8022_datalink) if (!p8022_datalink)
printk(ipx_llc_err_msg); printk(ipx_llc_err_msg);
......
...@@ -65,9 +65,7 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) ...@@ -65,9 +65,7 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
llc_pdu_decode_sa(skb, llc->daddr.mac); llc_pdu_decode_sa(skb, llc->daddr.mac);
llc_pdu_decode_da(skb, llc->laddr.mac); llc_pdu_decode_da(skb, llc->laddr.mac);
llc->dev = skb->dev; llc->dev = skb->dev;
/* FIXME: find better way to notify upper layer */ ev->ind_prim = LLC_CONN_PRIM;
ev->flag = LLC_CONN_PRIM + 1;
ev->ind_prim = (void *)1;
rc = 0; rc = 0;
} }
return rc; return rc;
...@@ -77,8 +75,7 @@ int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb) ...@@ -77,8 +75,7 @@ int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
ev->flag = LLC_CONN_PRIM + 1; ev->cfm_prim = LLC_CONN_PRIM;
ev->cfm_prim = (void *)1;
return 0; return 0;
} }
...@@ -86,12 +83,7 @@ static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb) ...@@ -86,12 +83,7 @@ static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
/* ev->cfm_prim = LLC_DATA_PRIM;
* FIXME: find better way to tell upper layer that the packet was
* confirmed by the other endpoint
*/
ev->flag = LLC_DATA_PRIM + 1;
ev->cfm_prim = (void *)1;
return 0; return 0;
} }
...@@ -130,8 +122,7 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb) ...@@ -130,8 +122,7 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb)
} }
if (!rc) { if (!rc) {
ev->reason = reason; ev->reason = reason;
ev->flag = LLC_DISC_PRIM + 1; ev->ind_prim = LLC_DISC_PRIM;
ev->ind_prim = (void *)1;
} }
return rc; return rc;
} }
...@@ -141,8 +132,7 @@ int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb) ...@@ -141,8 +132,7 @@ int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb)
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
ev->reason = ev->status; ev->reason = ev->status;
ev->flag = LLC_DISC_PRIM + 1; ev->cfm_prim = LLC_DISC_PRIM;
ev->cfm_prim = (void *)1;
return 0; return 0;
} }
...@@ -184,18 +174,8 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb) ...@@ -184,18 +174,8 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb)
break; break;
} }
if (!rc) { if (!rc) {
struct llc_sap *sap = llc->sap;
struct llc_prim_if_block *prim = &sap->llc_ind_prim;
union llc_u_prim_data *prim_data = prim->data;
prim_data->res.sk = sk;
prim_data->res.link = llc->link;
prim->data = prim_data;
prim->prim = LLC_RESET_PRIM;
prim->sap = sap;
ev->reason = reason; ev->reason = reason;
ev->flag = 1; ev->ind_prim = LLC_RESET_PRIM;
ev->ind_prim = prim;
} }
return rc; return rc;
} }
...@@ -203,18 +183,9 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb) ...@@ -203,18 +183,9 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb)
int llc_conn_ac_rst_confirm(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_rst_confirm(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; ev->reason = 0;
struct llc_prim_if_block *prim = &sap->llc_cfm_prim; ev->cfm_prim = LLC_RESET_PRIM;
union llc_u_prim_data *prim_data = prim->data;
prim_data->res.sk = sk;
prim_data->res.link = llc->link;
prim->data = prim_data;
prim->prim = LLC_RESET_PRIM;
prim->sap = sap;
ev->flag = 1;
ev->cfm_prim = prim;
return 0; return 0;
} }
......
...@@ -101,48 +101,48 @@ int llc_conn_ev_conn_req(struct sock *sk, struct sk_buff *skb) ...@@ -101,48 +101,48 @@ int llc_conn_ev_conn_req(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
return ev->data.prim.prim == LLC_CONN_PRIM && return ev->prim == LLC_CONN_PRIM &&
ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
} }
int llc_conn_ev_conn_resp(struct sock *sk, struct sk_buff *skb) int llc_conn_ev_conn_resp(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
return ev->data.prim.prim == LLC_CONN_PRIM && return ev->prim == LLC_CONN_PRIM &&
ev->data.prim.type == LLC_PRIM_TYPE_RESP ? 0 : 1; ev->prim_type == LLC_PRIM_TYPE_RESP ? 0 : 1;
} }
int llc_conn_ev_data_req(struct sock *sk, struct sk_buff *skb) int llc_conn_ev_data_req(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
return ev->data.prim.prim == LLC_DATA_PRIM && return ev->prim == LLC_DATA_PRIM &&
ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
} }
int llc_conn_ev_disc_req(struct sock *sk, struct sk_buff *skb) int llc_conn_ev_disc_req(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
return ev->data.prim.prim == LLC_DISC_PRIM && return ev->prim == LLC_DISC_PRIM &&
ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
} }
int llc_conn_ev_rst_req(struct sock *sk, struct sk_buff *skb) int llc_conn_ev_rst_req(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
return ev->data.prim.prim == LLC_RESET_PRIM && return ev->prim == LLC_RESET_PRIM &&
ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
} }
int llc_conn_ev_rst_resp(struct sock *sk, struct sk_buff *skb) int llc_conn_ev_rst_resp(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
return ev->data.prim.prim == LLC_RESET_PRIM && return ev->prim == LLC_RESET_PRIM &&
ev->data.prim.type == LLC_PRIM_TYPE_RESP ? 0 : 1; ev->prim_type == LLC_PRIM_TYPE_RESP ? 0 : 1;
} }
int llc_conn_ev_local_busy_detected(struct sock *sk, struct sk_buff *skb) int llc_conn_ev_local_busy_detected(struct sock *sk, struct sk_buff *skb)
...@@ -150,7 +150,7 @@ int llc_conn_ev_local_busy_detected(struct sock *sk, struct sk_buff *skb) ...@@ -150,7 +150,7 @@ int llc_conn_ev_local_busy_detected(struct sock *sk, struct sk_buff *skb)
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
return ev->type == LLC_CONN_EV_TYPE_SIMPLE && return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
ev->data.a.ev == LLC_CONN_EV_LOCAL_BUSY_DETECTED ? 0 : 1; ev->prim_type == LLC_CONN_EV_LOCAL_BUSY_DETECTED ? 0 : 1;
} }
int llc_conn_ev_local_busy_cleared(struct sock *sk, struct sk_buff *skb) int llc_conn_ev_local_busy_cleared(struct sock *sk, struct sk_buff *skb)
...@@ -158,7 +158,7 @@ int llc_conn_ev_local_busy_cleared(struct sock *sk, struct sk_buff *skb) ...@@ -158,7 +158,7 @@ int llc_conn_ev_local_busy_cleared(struct sock *sk, struct sk_buff *skb)
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
return ev->type == LLC_CONN_EV_TYPE_SIMPLE && return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
ev->data.a.ev == LLC_CONN_EV_LOCAL_BUSY_CLEARED ? 0 : 1; ev->prim_type == LLC_CONN_EV_LOCAL_BUSY_CLEARED ? 0 : 1;
} }
int llc_conn_ev_rx_bad_pdu(struct sock *sk, struct sk_buff *skb) int llc_conn_ev_rx_bad_pdu(struct sock *sk, struct sk_buff *skb)
...@@ -666,7 +666,7 @@ int llc_conn_ev_tx_buffer_full(struct sock *sk, struct sk_buff *skb) ...@@ -666,7 +666,7 @@ int llc_conn_ev_tx_buffer_full(struct sock *sk, struct sk_buff *skb)
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
return ev->type == LLC_CONN_EV_TYPE_SIMPLE && return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
ev->data.a.ev == LLC_CONN_EV_TX_BUFF_FULL ? 0 : 1; ev->prim_type == LLC_CONN_EV_TX_BUFF_FULL ? 0 : 1;
} }
/* Event qualifier functions /* Event qualifier functions
......
...@@ -39,12 +39,12 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk, ...@@ -39,12 +39,12 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
/* Offset table on connection states transition diagram */ /* Offset table on connection states transition diagram */
static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV]; static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim) void llc_save_primitive(struct sk_buff* skb, u8 prim)
{ {
struct sockaddr_llc *addr = llc_ui_skb_cb(skb); struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
/* save primitive for use by the user. */ /* save primitive for use by the user. */
addr->sllc_family = sk->family; addr->sllc_family = skb->sk->family;
addr->sllc_arphrd = skb->dev->type; addr->sllc_arphrd = skb->dev->type;
addr->sllc_test = prim == LLC_TEST_PRIM; addr->sllc_test = prim == LLC_TEST_PRIM;
addr->sllc_xid = prim == LLC_XID_PRIM; addr->sllc_xid = prim == LLC_XID_PRIM;
...@@ -67,48 +67,39 @@ void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim) ...@@ -67,48 +67,39 @@ void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim)
*/ */
int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
{ {
/* sending event to state machine */ int rc;
int rc = llc_conn_service(sk, skb);
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
u8 flag = ev->flag;
u8 status = ev->status;
struct llc_prim_if_block *ind_prim = ev->ind_prim;
struct llc_prim_if_block *cfm_prim = ev->cfm_prim;
/* ev->ind_prim = ev->cfm_prim = 0;
* FIXME: this will vanish as soon I get rid of the last prim crap rc = llc_conn_service(sk, skb); /* sending event to state machine */
*/ if (rc) {
if (flag != LLC_DATA_PRIM + 1 && flag != LLC_CONN_PRIM + 1 && printk(KERN_ERR "%s: llc_conn_service failed\n", __FUNCTION__);
flag != LLC_DISC_PRIM + 1) goto out_kfree_skb;
llc_conn_free_ev(skb); }
else if (ind_prim && cfm_prim)
skb_get(skb); if (!ev->ind_prim && !ev->cfm_prim) { /* indicate or confirm not required */
if (!flag) /* indicate or confirm not required */ if (!skb->list)
goto out_kfree_skb;
goto out; goto out;
rc = 0; }
if (ind_prim) { /* indication required */
/* if (ev->ind_prim && ev->cfm_prim)
* FIXME: this will be saner as soon I get rid of the double skb_get(skb);
* sock crap
*/ switch (ev->ind_prim) {
switch (flag) { case LLC_DATA_PRIM:
case LLC_DATA_PRIM + 1: llc_save_primitive(skb, LLC_DATA_PRIM);
llc_save_primitive(sk, skb, LLC_DATA_PRIM);
if (sock_queue_rcv_skb(sk, skb)) { if (sock_queue_rcv_skb(sk, skb)) {
/* /*
* FIXME: have to sync the LLC state * shouldn't happen
* machine wrt mem usage with
* sk->{r,w}mem_alloc, will do
* this soon 8)
*/ */
printk(KERN_ERR printk(KERN_ERR "%s: sock_queue_rcv_skb failed!\n",
"%s: sock_queue_rcv_skb failed!\n",
__FUNCTION__); __FUNCTION__);
kfree_skb(skb); kfree_skb(skb);
} }
break; break;
case LLC_CONN_PRIM + 1: { case LLC_CONN_PRIM: {
struct sock *parent = skb->sk; struct sock *parent = skb->sk;
skb->sk = sk; skb->sk = sk;
...@@ -116,7 +107,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -116,7 +107,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
sk->state_change(parent); sk->state_change(parent);
} }
break; break;
case LLC_DISC_PRIM + 1: case LLC_DISC_PRIM:
sock_hold(sk); sock_hold(sk);
if (sk->type == SOCK_STREAM && sk->state == TCP_ESTABLISHED) { if (sk->type == SOCK_STREAM && sk->state == TCP_ESTABLISHED) {
sk->shutdown = SHUTDOWN_MASK; sk->shutdown = SHUTDOWN_MASK;
...@@ -130,25 +121,34 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -130,25 +121,34 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
sock_put(sk); sock_put(sk);
break; break;
case LLC_RESET_PRIM:
/*
* FIXME:
* RESET is not being notified to upper layers for now
*/
printk(KERN_INFO "%s: received a reset ind!\n", __FUNCTION__);
kfree_skb(skb);
break;
default: default:
llc->sap->ind(ind_prim); if (ev->ind_prim) {
printk(KERN_INFO "%s: received unknown %d prim!\n",
__FUNCTION__, ev->ind_prim);
kfree_skb(skb);
} }
/* No indication */
break;
} }
if (!cfm_prim) /* confirmation not required */
goto out; switch (ev->cfm_prim) {
/* FIXME: see FIXMEs above */ case LLC_DATA_PRIM:
switch (flag) {
case LLC_DATA_PRIM + 1:
if (!llc_data_accept_state(llc->state)) if (!llc_data_accept_state(llc->state))
/* In this state, we can send I pdu */
sk->write_space(sk); sk->write_space(sk);
else else
rc = llc->failed_data_req = 1; rc = llc->failed_data_req = 1;
break; break;
case LLC_CONN_PRIM + 1: case LLC_CONN_PRIM:
if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT) if (sk->type == SOCK_STREAM && sk->state == TCP_SYN_SENT) {
goto out_kfree_skb; if (ev->status) {
if (status) {
sk->socket->state = SS_UNCONNECTED; sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
} else { } else {
...@@ -156,21 +156,31 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -156,21 +156,31 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
sk->state = TCP_ESTABLISHED; sk->state = TCP_ESTABLISHED;
} }
sk->state_change(sk); sk->state_change(sk);
}
break; break;
case LLC_DISC_PRIM + 1: case LLC_DISC_PRIM:
sock_hold(sk); sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING) { if (sk->type == SOCK_STREAM && sk->state == TCP_CLOSING) {
sock_put(sk);
goto out_kfree_skb;
}
sk->socket->state = SS_UNCONNECTED; sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
sk->state_change(sk); sk->state_change(sk);
}
sock_put(sk); sock_put(sk);
break; break;
case LLC_RESET_PRIM:
/*
* FIXME:
* RESET is not being notified to upper layers for now
*/
printk(KERN_INFO "%s: received a reset conf!\n", __FUNCTION__);
break;
default: default:
llc->sap->conf(cfm_prim); if (ev->cfm_prim) {
goto out; printk(KERN_INFO "%s: received unknown %d prim!\n",
__FUNCTION__, ev->cfm_prim);
break;
}
goto out; /* No confirmation */
} }
out_kfree_skb: out_kfree_skb:
kfree_skb(skb); kfree_skb(skb);
...@@ -198,9 +208,7 @@ void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb) ...@@ -198,9 +208,7 @@ void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
/* FIXME: indicate that we should send this to the upper layer */ ev->ind_prim = LLC_DATA_PRIM;
ev->flag = LLC_DATA_PRIM + 1;
ev->ind_prim = (void *)1;
} }
/** /**
...@@ -355,12 +363,14 @@ void llc_conn_free_ev(struct sk_buff *skb) ...@@ -355,12 +363,14 @@ void llc_conn_free_ev(struct sk_buff *skb)
/* free the frame that is bound to this event */ /* free the frame that is bound to this event */
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
if (LLC_PDU_TYPE_IS_I(pdu) || !ev->flag || !ev->ind_prim) if (LLC_PDU_TYPE_IS_I(pdu) || !ev->ind_prim)
kfree_skb(skb); kfree_skb(skb);
} else if (ev->type == LLC_CONN_EV_TYPE_PRIM && } else if (ev->type == LLC_CONN_EV_TYPE_PRIM &&
ev->data.prim.prim != LLC_DATA_PRIM) ev->prim != LLC_DATA_PRIM)
kfree_skb(skb); kfree_skb(skb);
else if (ev->type == LLC_CONN_EV_TYPE_P_TMR) else if (ev->type == LLC_CONN_EV_TYPE_P_TMR ||
ev->type == LLC_CONN_EV_TYPE_BUSY_TMR ||
ev->type == LLC_CONN_EV_TYPE_REJ_TMR)
kfree_skb(skb); kfree_skb(skb);
} }
...@@ -483,27 +493,21 @@ static int llc_exec_conn_trans_actions(struct sock *sk, ...@@ -483,27 +493,21 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr, struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr,
struct llc_addr *laddr) struct llc_addr *laddr)
{ {
struct sock *rc = NULL; struct sock *rc;
struct list_head *entry;
spin_lock_bh(&sap->sk_list.lock); read_lock_bh(&sap->sk_list.lock);
if (list_empty(&sap->sk_list.list)) for (rc = sap->sk_list.list; rc; rc = rc->next) {
goto out; struct llc_opt *llc = llc_sk(rc);
list_for_each(entry, &sap->sk_list.list) {
struct llc_opt *llc = list_entry(entry, struct llc_opt, node);
if (llc->laddr.lsap == laddr->lsap && if (llc->laddr.lsap == laddr->lsap &&
llc->daddr.lsap == daddr->lsap && llc->daddr.lsap == daddr->lsap &&
llc_mac_match(llc->laddr.mac, laddr->mac) && llc_mac_match(llc->laddr.mac, laddr->mac) &&
llc_mac_match(llc->daddr.mac, daddr->mac)) { llc_mac_match(llc->daddr.mac, daddr->mac))
rc = llc->sk;
break; break;
} }
}
if (rc) if (rc)
sock_hold(rc); sock_hold(rc);
out: read_unlock_bh(&sap->sk_list.lock);
spin_unlock_bh(&sap->sk_list.lock);
return rc; return rc;
} }
...@@ -518,28 +522,49 @@ struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr, ...@@ -518,28 +522,49 @@ struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr,
*/ */
struct sock *llc_lookup_listener(struct llc_sap *sap, struct llc_addr *laddr) struct sock *llc_lookup_listener(struct llc_sap *sap, struct llc_addr *laddr)
{ {
struct sock *rc = NULL; struct sock *rc;
struct list_head *entry;
spin_lock_bh(&sap->sk_list.lock); read_lock_bh(&sap->sk_list.lock);
if (list_empty(&sap->sk_list.list)) for (rc = sap->sk_list.list; rc; rc = rc->next) {
goto out; struct llc_opt *llc = llc_sk(rc);
list_for_each(entry, &sap->sk_list.list) {
struct llc_opt *llc = list_entry(entry, struct llc_opt, node); if (rc->type == SOCK_STREAM && rc->state == TCP_LISTEN &&
llc->laddr.lsap == laddr->lsap &&
if (llc->sk->type != SOCK_STREAM || llc->sk->state != TCP_LISTEN || llc_mac_match(llc->laddr.mac, laddr->mac))
llc->laddr.lsap != laddr->lsap || break;
!llc_mac_match(llc->laddr.mac, laddr->mac))
continue;
rc = llc->sk;
} }
if (rc) if (rc)
sock_hold(rc); sock_hold(rc);
out: read_unlock_bh(&sap->sk_list.lock);
spin_unlock_bh(&sap->sk_list.lock);
return rc; return rc;
} }
/**
* llc_lookup_dgram - Finds dgram socket for the local sap/mac
* @sap: SAP
* @laddr: address of local LLC (MAC + SAP)
*
* Search socket list of the SAP and finds connection using the local
* mac, and local sap. Returns pointer for socket found, %NULL otherwise.
*/
struct sock *llc_lookup_dgram(struct llc_sap *sap, struct llc_addr *laddr)
{
struct sock *rc;
read_lock_bh(&sap->sk_list.lock);
for (rc = sap->sk_list.list; rc; rc = rc->next) {
struct llc_opt *llc = llc_sk(rc);
if (rc->type == SOCK_DGRAM &&
llc->laddr.lsap == laddr->lsap &&
llc_mac_match(llc->laddr.mac, laddr->mac))
break;
}
if (rc)
sock_hold(rc);
read_unlock_bh(&sap->sk_list.lock);
return rc;
}
/** /**
* llc_data_accept_state - designates if in this state data can be sent. * llc_data_accept_state - designates if in this state data can be sent.
* @state: state of connection. * @state: state of connection.
......
...@@ -29,7 +29,7 @@ int llc_stat_ev_enable_with_dup_addr_check(struct llc_station *station, ...@@ -29,7 +29,7 @@ int llc_stat_ev_enable_with_dup_addr_check(struct llc_station *station,
struct llc_station_state_ev *ev = llc_station_ev(skb); struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_SIMPLE && return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
ev->data.a.ev == ev->prim_type ==
LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1; LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1;
} }
...@@ -39,7 +39,7 @@ int llc_stat_ev_enable_without_dup_addr_check(struct llc_station *station, ...@@ -39,7 +39,7 @@ int llc_stat_ev_enable_without_dup_addr_check(struct llc_station *station,
struct llc_station_state_ev *ev = llc_station_ev(skb); struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_SIMPLE && return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
ev->data.a.ev == ev->prim_type ==
LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1; LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1;
} }
...@@ -120,6 +120,6 @@ int llc_stat_ev_disable_req(struct llc_station *station, struct sk_buff *skb) ...@@ -120,6 +120,6 @@ int llc_stat_ev_disable_req(struct llc_station *station, struct sk_buff *skb)
struct llc_station_state_ev *ev = llc_station_ev(skb); struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_PRIM && return ev->type == LLC_STATION_EV_TYPE_PRIM &&
ev->data.prim.prim == LLC_DISABLE_PRIM && ev->prim == LLC_DISABLE_PRIM &&
ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
} }
...@@ -30,17 +30,16 @@ ...@@ -30,17 +30,16 @@
/** /**
* llc_sap_open - open interface to the upper layers. * llc_sap_open - open interface to the upper layers.
* @nw_indicate: pointer to indicate function of upper layer.
* @nw_confirm: pointer to confirm function of upper layer.
* @lsap: SAP number. * @lsap: SAP number.
* @sap: pointer to allocated SAP (output argument). * @func: rcv func for datalink protos
* *
* Interface function to upper layer. Each one who wants to get a SAP * Interface function to upper layer. Each one who wants to get a SAP
* (for example NetBEUI) should call this function. Returns the opened * (for example NetBEUI) should call this function. Returns the opened
* SAP for success, NULL for failure. * SAP for success, NULL for failure.
*/ */
struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate, struct llc_sap *llc_sap_open(u8 lsap, int (*func)(struct sk_buff *skb,
llc_prim_call_t nw_confirm, u8 lsap) struct net_device *dev,
struct packet_type *pt))
{ {
/* verify this SAP is not already open; if so, return error */ /* verify this SAP is not already open; if so, return error */
struct llc_sap *sap; struct llc_sap *sap;
...@@ -57,9 +56,8 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate, ...@@ -57,9 +56,8 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate,
goto err; goto err;
/* allocated a SAP; initialize it and clear out its memory pool */ /* allocated a SAP; initialize it and clear out its memory pool */
sap->laddr.lsap = lsap; sap->laddr.lsap = lsap;
sap->ind = nw_indicate; sap->rcv_func = func;
sap->conf = nw_confirm; sap->station = llc_station_get();
sap->parent_station = llc_station_get();
/* initialized SAP; add it to list of SAPs this station manages */ /* initialized SAP; add it to list of SAPs this station manages */
llc_sap_save(sap); llc_sap_save(sap);
out: out:
...@@ -99,24 +97,16 @@ void llc_sap_close(struct llc_sap *sap) ...@@ -99,24 +97,16 @@ void llc_sap_close(struct llc_sap *sap)
void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb, void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
u8 *dmac, u8 dsap) u8 *dmac, u8 dsap)
{ {
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
prim.data = &prim_data; ev->saddr.lsap = sap->laddr.lsap;
prim.sap = sap; ev->daddr.lsap = dsap;
prim.prim = LLC_DATAUNIT_PRIM; memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
memcpy(ev->daddr.mac, dmac, IFHWADDRLEN);
prim_data.udata.skb = skb;
prim_data.udata.saddr.lsap = sap->laddr.lsap;
prim_data.udata.daddr.lsap = dsap;
memcpy(prim_data.udata.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
memcpy(prim_data.udata.daddr.mac, dmac, IFHWADDRLEN);
ev->type = LLC_SAP_EV_TYPE_PRIM; ev->type = LLC_SAP_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_DATAUNIT_PRIM; ev->prim = LLC_DATAUNIT_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->prim_type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = &prim;
llc_sap_state_process(sap, skb); llc_sap_state_process(sap, skb);
} }
...@@ -130,27 +120,19 @@ void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb, ...@@ -130,27 +120,19 @@ void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
* This function is called when upper layer wants to send a TEST pdu. * This function is called when upper layer wants to send a TEST pdu.
* Returns 0 for success, 1 otherwise. * Returns 0 for success, 1 otherwise.
*/ */
void llc_build_and_send_test_pkt(struct llc_sap *sap, struct sk_buff *skb, void llc_build_and_send_test_pkt(struct llc_sap *sap,
u8 *dmac, u8 dsap) struct sk_buff *skb, u8 *dmac, u8 dsap)
{ {
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
prim.data = &prim_data; ev->saddr.lsap = sap->laddr.lsap;
prim.sap = sap; ev->daddr.lsap = dsap;
prim.prim = LLC_TEST_PRIM; memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
memcpy(ev->daddr.mac, dmac, IFHWADDRLEN);
prim_data.test.skb = skb;
prim_data.test.saddr.lsap = sap->laddr.lsap;
prim_data.test.daddr.lsap = dsap;
memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
memcpy(prim_data.test.daddr.mac, dmac, IFHWADDRLEN);
ev->type = LLC_SAP_EV_TYPE_PRIM; ev->type = LLC_SAP_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_TEST_PRIM; ev->prim = LLC_TEST_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->prim_type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = &prim;
llc_sap_state_process(sap, skb); llc_sap_state_process(sap, skb);
} }
...@@ -167,24 +149,16 @@ void llc_build_and_send_test_pkt(struct llc_sap *sap, struct sk_buff *skb, ...@@ -167,24 +149,16 @@ void llc_build_and_send_test_pkt(struct llc_sap *sap, struct sk_buff *skb,
void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb, void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb,
u8 *dmac, u8 dsap) u8 *dmac, u8 dsap)
{ {
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
prim.data = &prim_data; ev->saddr.lsap = sap->laddr.lsap;
prim.sap = sap; ev->daddr.lsap = dsap;
prim.prim = LLC_XID_PRIM; memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
memcpy(ev->daddr.mac, dmac, IFHWADDRLEN);
prim_data.xid.skb = skb;
prim_data.xid.saddr.lsap = sap->laddr.lsap;
prim_data.xid.daddr.lsap = dsap;
memcpy(prim_data.xid.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
memcpy(prim_data.xid.daddr.mac, dmac, IFHWADDRLEN);
ev->type = LLC_SAP_EV_TYPE_PRIM; ev->type = LLC_SAP_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_XID_PRIM; ev->prim = LLC_XID_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->prim_type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = &prim;
llc_sap_state_process(sap, skb); llc_sap_state_process(sap, skb);
} }
...@@ -220,9 +194,8 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb) ...@@ -220,9 +194,8 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
} }
ev = llc_conn_ev(skb); ev = llc_conn_ev(skb);
ev->type = LLC_CONN_EV_TYPE_PRIM; ev->type = LLC_CONN_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_DATA_PRIM; ev->prim = LLC_DATA_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->prim_type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = NULL;
skb->dev = llc->dev; skb->dev = llc->dev;
rc = llc_conn_state_process(sk, skb); rc = llc_conn_state_process(sk, skb);
out: out:
...@@ -269,9 +242,8 @@ int llc_establish_connection(struct sock *sk, u8 *lmac, u8 *dmac, u8 dsap) ...@@ -269,9 +242,8 @@ int llc_establish_connection(struct sock *sk, u8 *lmac, u8 *dmac, u8 dsap)
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
ev->type = LLC_CONN_EV_TYPE_PRIM; ev->type = LLC_CONN_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_CONN_PRIM; ev->prim = LLC_CONN_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->prim_type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = NULL;
rc = llc_conn_state_process(sk, skb); rc = llc_conn_state_process(sk, skb);
} }
out_put: out_put:
...@@ -309,9 +281,8 @@ int llc_send_disc(struct sock *sk) ...@@ -309,9 +281,8 @@ int llc_send_disc(struct sock *sk)
sk->state = TCP_CLOSING; sk->state = TCP_CLOSING;
ev = llc_conn_ev(skb); ev = llc_conn_ev(skb);
ev->type = LLC_CONN_EV_TYPE_PRIM; ev->type = LLC_CONN_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_DISC_PRIM; ev->prim = LLC_DISC_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->prim_type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = NULL;
rc = llc_conn_state_process(sk, skb); rc = llc_conn_state_process(sk, skb);
out: out:
sock_put(sk); sock_put(sk);
...@@ -327,8 +298,7 @@ int llc_send_disc(struct sock *sk) ...@@ -327,8 +298,7 @@ int llc_send_disc(struct sock *sk)
* it to connection component state machine. Returns 0 for success, 1 * it to connection component state machine. Returns 0 for success, 1
* otherwise. * otherwise.
*/ */
int llc_build_and_send_reset_pkt(struct sock *sk, int llc_build_and_send_reset_pkt(struct sock *sk)
struct llc_prim_if_block *prim)
{ {
int rc = 1; int rc = 1;
struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
...@@ -337,9 +307,8 @@ int llc_build_and_send_reset_pkt(struct sock *sk, ...@@ -337,9 +307,8 @@ int llc_build_and_send_reset_pkt(struct sock *sk,
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
ev->type = LLC_CONN_EV_TYPE_PRIM; ev->type = LLC_CONN_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_RESET_PRIM; ev->prim = LLC_RESET_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->prim_type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = prim;
rc = llc_conn_state_process(sk, skb); rc = llc_conn_state_process(sk, skb);
} }
return rc; return rc;
......
...@@ -113,8 +113,22 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -113,8 +113,22 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
} }
llc_decode_pdu_type(skb, &dest); llc_decode_pdu_type(skb, &dest);
if (dest == LLC_DEST_SAP) { /* type 1 services */ if (dest == LLC_DEST_SAP) { /* type 1 services */
dprintk("%s: calling llc_sap_rcv!\n", __FUNCTION__); if (sap->rcv_func)
sap->rcv_func(skb, dev, pt);
else {
struct llc_addr laddr;
struct sock *sk;
llc_pdu_decode_da(skb, laddr.mac);
llc_pdu_decode_dsap(skb, &laddr.lsap);
sk = llc_lookup_dgram(sap, &laddr);
if (!sk)
goto drop;
skb->sk = sk;
llc_sap_rcv(sap, skb); llc_sap_rcv(sap, skb);
sock_put(sk);
}
} else if (dest == LLC_DEST_CONN) { } else if (dest == LLC_DEST_CONN) {
struct llc_addr saddr, daddr; struct llc_addr saddr, daddr;
struct sock *sk; struct sock *sk;
......
...@@ -71,10 +71,6 @@ struct llc_sap *llc_sap_alloc(void) ...@@ -71,10 +71,6 @@ struct llc_sap *llc_sap_alloc(void)
sap->state = LLC_SAP_STATE_ACTIVE; sap->state = LLC_SAP_STATE_ACTIVE;
memcpy(sap->laddr.mac, llc_main_station.mac_sa, ETH_ALEN); memcpy(sap->laddr.mac, llc_main_station.mac_sa, ETH_ALEN);
spin_lock_init(&sap->sk_list.lock); spin_lock_init(&sap->sk_list.lock);
INIT_LIST_HEAD(&sap->sk_list.list);
skb_queue_head_init(&sap->mac_pdu_q);
sap->llc_ind_prim.data = &sap->llc_ind_data_prim;
sap->llc_cfm_prim.data = &sap->llc_cfm_data_prim;
} }
return sap; return sap;
} }
...@@ -88,12 +84,10 @@ struct llc_sap *llc_sap_alloc(void) ...@@ -88,12 +84,10 @@ struct llc_sap *llc_sap_alloc(void)
*/ */
void llc_free_sap(struct llc_sap *sap) void llc_free_sap(struct llc_sap *sap)
{ {
struct llc_station *station = sap->parent_station;
llc_rtn_all_conns(sap); llc_rtn_all_conns(sap);
spin_lock_bh(&station->sap_list.lock); write_lock_bh(&sap->station->sap_list.lock);
list_del(&sap->node); list_del(&sap->node);
spin_unlock_bh(&station->sap_list.lock); write_unlock_bh(&sap->station->sap_list.lock);
kfree(sap); kfree(sap);
} }
...@@ -105,9 +99,9 @@ void llc_free_sap(struct llc_sap *sap) ...@@ -105,9 +99,9 @@ void llc_free_sap(struct llc_sap *sap)
*/ */
void llc_sap_save(struct llc_sap *sap) void llc_sap_save(struct llc_sap *sap)
{ {
spin_lock_bh(&llc_main_station.sap_list.lock); write_lock_bh(&llc_main_station.sap_list.lock);
list_add_tail(&sap->node, &llc_main_station.sap_list.list); list_add_tail(&sap->node, &llc_main_station.sap_list.list);
spin_unlock_bh(&llc_main_station.sap_list.lock); write_unlock_bh(&llc_main_station.sap_list.lock);
} }
/** /**
...@@ -122,7 +116,7 @@ struct llc_sap *llc_sap_find(u8 sap_value) ...@@ -122,7 +116,7 @@ struct llc_sap *llc_sap_find(u8 sap_value)
struct llc_sap* sap = NULL; struct llc_sap* sap = NULL;
struct list_head *entry; struct list_head *entry;
spin_lock_bh(&llc_main_station.sap_list.lock); read_lock_bh(&llc_main_station.sap_list.lock);
list_for_each(entry, &llc_main_station.sap_list.list) { list_for_each(entry, &llc_main_station.sap_list.list) {
sap = list_entry(entry, struct llc_sap, node); sap = list_entry(entry, struct llc_sap, node);
if (sap->laddr.lsap == sap_value) if (sap->laddr.lsap == sap_value)
...@@ -130,7 +124,7 @@ struct llc_sap *llc_sap_find(u8 sap_value) ...@@ -130,7 +124,7 @@ struct llc_sap *llc_sap_find(u8 sap_value)
} }
if (entry == &llc_main_station.sap_list.list) /* not found */ if (entry == &llc_main_station.sap_list.list) /* not found */
sap = NULL; sap = NULL;
spin_unlock_bh(&llc_main_station.sap_list.lock); read_unlock_bh(&llc_main_station.sap_list.lock);
return sap; return sap;
} }
...@@ -328,20 +322,18 @@ void llc_sk_reset(struct sock *sk) ...@@ -328,20 +322,18 @@ void llc_sk_reset(struct sock *sk)
static int llc_rtn_all_conns(struct llc_sap *sap) static int llc_rtn_all_conns(struct llc_sap *sap)
{ {
int rc = 0; int rc = 0;
struct list_head *entry, *tmp; struct sock *sk;
spin_lock_bh(&sap->sk_list.lock); write_lock_bh(&sap->sk_list.lock);
if (list_empty(&sap->sk_list.list))
goto out;
list_for_each_safe(entry, tmp, &sap->sk_list.list) {
struct llc_opt *llc = list_entry(entry, struct llc_opt, node);
llc->state = LLC_CONN_STATE_TEMP; for (sk = sap->sk_list.list; sk; sk = sk->next) {
if (llc_send_disc(llc->sk)) llc_sk(sk)->state = LLC_CONN_STATE_TEMP;
if (llc_send_disc(sk))
rc = 1; rc = 1;
} }
out:
spin_unlock_bh(&sap->sk_list.lock); write_unlock_bh(&sap->sk_list.lock);
return rc; return rc;
} }
...@@ -564,19 +556,19 @@ static char *llc_conn_state_names[] = { ...@@ -564,19 +556,19 @@ static char *llc_conn_state_names[] = {
static int llc_proc_get_info(char *bf, char **start, off_t offset, int length) static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
{ {
struct llc_opt *llc; struct list_head *sap_entry;
struct list_head *sap_entry, *llc_entry; struct sock *sk;
off_t begin = 0, pos = 0; off_t begin = 0, pos = 0;
int len = 0; int len = 0;
spin_lock_bh(&llc_main_station.sap_list.lock); read_lock_bh(&llc_main_station.sap_list.lock);
list_for_each(sap_entry, &llc_main_station.sap_list.list) { list_for_each(sap_entry, &llc_main_station.sap_list.list) {
struct llc_sap *sap = list_entry(sap_entry, struct llc_sap, struct llc_sap *sap = list_entry(sap_entry, struct llc_sap,
node); node);
len += sprintf(bf + len, "lsap=%02X\n", sap->laddr.lsap); len += sprintf(bf + len, "lsap=%02X\n", sap->laddr.lsap);
spin_lock_bh(&sap->sk_list.lock); read_lock_bh(&sap->sk_list.lock);
if (list_empty(&sap->sk_list.list)) { if (!sap->sk_list.list) {
len += sprintf(bf + len, "no connections\n"); len += sprintf(bf + len, "no connections\n");
goto unlock; goto unlock;
} }
...@@ -584,8 +576,9 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length) ...@@ -584,8 +576,9 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
"dsap state retr txw rxw " "dsap state retr txw rxw "
"pf ff sf df rs cs " "pf ff sf df rs cs "
"tack tpfc trs tbs blog busr\n"); "tack tpfc trs tbs blog busr\n");
list_for_each(llc_entry, &sap->sk_list.list) { for (sk = sap->sk_list.list; sk; sk = sk->next) {
llc = list_entry(llc_entry, struct llc_opt, node); struct llc_opt *llc = llc_sk(sk);
len += sprintf(bf + len, " %02X %-10s %3d %3d %3d " len += sprintf(bf + len, " %02X %-10s %3d %3d %3d "
"%2d %2d %2d " "%2d %2d %2d "
"%2d %2d %2d " "%2d %2d %2d "
...@@ -600,11 +593,10 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length) ...@@ -600,11 +593,10 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
timer_pending(&llc->pf_cycle_timer.timer), timer_pending(&llc->pf_cycle_timer.timer),
timer_pending(&llc->rej_sent_timer.timer), timer_pending(&llc->rej_sent_timer.timer),
timer_pending(&llc->busy_state_timer.timer), timer_pending(&llc->busy_state_timer.timer),
!!llc->sk->backlog.tail, !!sk->backlog.tail, sk->lock.users);
llc->sk->lock.users);
} }
unlock: unlock:
spin_unlock_bh(&sap->sk_list.lock); read_unlock_bh(&sap->sk_list.lock);
pos = begin + len; pos = begin + len;
if (pos < offset) { if (pos < offset) {
len = 0; /* Keep dumping into the buffer start */ len = 0; /* Keep dumping into the buffer start */
...@@ -613,7 +605,7 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length) ...@@ -613,7 +605,7 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
if (pos > offset + length) /* We have dumped enough */ if (pos > offset + length) /* We have dumped enough */
break; break;
} }
spin_unlock_bh(&llc_main_station.sap_list.lock); read_unlock_bh(&llc_main_station.sap_list.lock);
/* The data in question runs from begin to begin + len */ /* The data in question runs from begin to begin + len */
*start = bf + (offset - begin); /* Start of wanted data */ *start = bf + (offset - begin); /* Start of wanted data */
...@@ -634,8 +626,8 @@ static struct packet_type llc_tr_packet_type = { ...@@ -634,8 +626,8 @@ static struct packet_type llc_tr_packet_type = {
}; };
static char llc_banner[] __initdata = static char llc_banner[] __initdata =
KERN_INFO "LLC 2.0 by Procom, 1997, Arnaldo C. Melo, 2001\n" KERN_INFO "LLC 2.0 by Procom, 1997, Arnaldo C. Melo, 2001, 2002\n"
KERN_INFO "NET4.0 IEEE 802.2 extended support\n"; KERN_INFO "NET 4.0 IEEE 802.2 extended support\n";
static char llc_error_msg[] __initdata = static char llc_error_msg[] __initdata =
KERN_ERR "LLC install NOT successful.\n"; KERN_ERR "LLC install NOT successful.\n";
...@@ -669,7 +661,7 @@ static int __init llc_init(void) ...@@ -669,7 +661,7 @@ static int __init llc_init(void)
llc_main_station.maximum_retry = 1; llc_main_station.maximum_retry = 1;
llc_main_station.state = LLC_STATION_STATE_DOWN; llc_main_station.state = LLC_STATION_STATE_DOWN;
ev->type = LLC_STATION_EV_TYPE_SIMPLE; ev->type = LLC_STATION_EV_TYPE_SIMPLE;
ev->data.a.ev = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK; ev->prim_type = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK;
rc = llc_station_next_state(&llc_main_station, skb); rc = llc_station_next_state(&llc_main_station, skb);
proc_net_create("802.2", 0, llc_proc_get_info); proc_net_create("802.2", 0, llc_proc_get_info);
llc_ui_init(); llc_ui_init();
...@@ -695,5 +687,5 @@ module_init(llc_init); ...@@ -695,5 +687,5 @@ module_init(llc_init);
module_exit(llc_exit); module_exit(llc_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Procom, 1997, Arnaldo C. Melo, Jay Schullist, 2001"); MODULE_AUTHOR("Procom, 1997, Arnaldo C. Melo, Jay Schullist, 2001, 2002");
MODULE_DESCRIPTION("LLC 2.0, NET4.0 IEEE 802.2 extended support"); MODULE_DESCRIPTION("LLC 2.0, NET4.0 IEEE 802.2 extended support");
...@@ -51,14 +51,12 @@ int llc_sap_action_unitdata_ind(struct llc_sap *sap, struct sk_buff *skb) ...@@ -51,14 +51,12 @@ int llc_sap_action_unitdata_ind(struct llc_sap *sap, struct sk_buff *skb)
int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb) int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb)
{ {
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
struct llc_prim_if_block *prim = ev->data.prim.data;
struct llc_prim_unit_data *prim_data = &prim->data->udata;
int rc; int rc;
llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap,
prim_data->daddr.lsap, LLC_PDU_CMD); ev->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_ui_cmd(skb); llc_pdu_init_as_ui_cmd(skb);
rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); rc = lan_hdrs_init(skb, ev->saddr.mac, ev->daddr.mac);
if (!rc) if (!rc)
llc_sap_send_pdu(sap, skb); llc_sap_send_pdu(sap, skb);
return rc; return rc;
...@@ -76,14 +74,12 @@ int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb) ...@@ -76,14 +74,12 @@ int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb)
int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb) int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb)
{ {
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
struct llc_prim_if_block *prim = ev->data.prim.data;
struct llc_prim_xid *prim_data = &prim->data->xid;
int rc; int rc;
llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap,
prim_data->daddr.lsap, LLC_PDU_CMD); ev->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0); llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0);
rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); rc = lan_hdrs_init(skb, ev->saddr.mac, ev->daddr.mac);
if (!rc) if (!rc)
llc_sap_send_pdu(sap, skb); llc_sap_send_pdu(sap, skb);
return rc; return rc;
...@@ -132,14 +128,12 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb) ...@@ -132,14 +128,12 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb)
int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb) int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb)
{ {
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
struct llc_prim_if_block *prim = ev->data.prim.data;
struct llc_prim_test *prim_data = &prim->data->test;
int rc; int rc;
llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap,
prim_data->daddr.lsap, LLC_PDU_CMD); ev->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_test_cmd(skb); llc_pdu_init_as_test_cmd(skb);
rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); rc = lan_hdrs_init(skb, ev->saddr.mac, ev->daddr.mac);
if (!rc) if (!rc)
llc_sap_send_pdu(sap, skb); llc_sap_send_pdu(sap, skb);
return rc; return rc;
......
...@@ -25,7 +25,7 @@ int llc_sap_ev_activation_req(struct llc_sap *sap, struct sk_buff *skb) ...@@ -25,7 +25,7 @@ int llc_sap_ev_activation_req(struct llc_sap *sap, struct sk_buff *skb)
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
return ev->type == LLC_SAP_EV_TYPE_SIMPLE && return ev->type == LLC_SAP_EV_TYPE_SIMPLE &&
ev->data.a.ev == LLC_SAP_EV_ACTIVATION_REQ ? 0 : 1; ev->prim_type == LLC_SAP_EV_ACTIVATION_REQ ? 0 : 1;
} }
int llc_sap_ev_rx_ui(struct llc_sap *sap, struct sk_buff *skb) int llc_sap_ev_rx_ui(struct llc_sap *sap, struct sk_buff *skb)
...@@ -43,8 +43,8 @@ int llc_sap_ev_unitdata_req(struct llc_sap *sap, struct sk_buff *skb) ...@@ -43,8 +43,8 @@ int llc_sap_ev_unitdata_req(struct llc_sap *sap, struct sk_buff *skb)
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
return ev->type == LLC_SAP_EV_TYPE_PRIM && return ev->type == LLC_SAP_EV_TYPE_PRIM &&
ev->data.prim.prim == LLC_DATAUNIT_PRIM && ev->prim == LLC_DATAUNIT_PRIM &&
ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
} }
...@@ -53,8 +53,8 @@ int llc_sap_ev_xid_req(struct llc_sap *sap, struct sk_buff *skb) ...@@ -53,8 +53,8 @@ int llc_sap_ev_xid_req(struct llc_sap *sap, struct sk_buff *skb)
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
return ev->type == LLC_SAP_EV_TYPE_PRIM && return ev->type == LLC_SAP_EV_TYPE_PRIM &&
ev->data.prim.prim == LLC_XID_PRIM && ev->prim == LLC_XID_PRIM &&
ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
} }
int llc_sap_ev_rx_xid_c(struct llc_sap *sap, struct sk_buff *skb) int llc_sap_ev_rx_xid_c(struct llc_sap *sap, struct sk_buff *skb)
...@@ -82,8 +82,8 @@ int llc_sap_ev_test_req(struct llc_sap *sap, struct sk_buff *skb) ...@@ -82,8 +82,8 @@ int llc_sap_ev_test_req(struct llc_sap *sap, struct sk_buff *skb)
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
return ev->type == LLC_SAP_EV_TYPE_PRIM && return ev->type == LLC_SAP_EV_TYPE_PRIM &&
ev->data.prim.prim == LLC_TEST_PRIM && ev->prim == LLC_TEST_PRIM &&
ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1; ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
} }
int llc_sap_ev_rx_test_c(struct llc_sap *sap, struct sk_buff *skb) int llc_sap_ev_rx_test_c(struct llc_sap *sap, struct sk_buff *skb)
...@@ -111,5 +111,5 @@ int llc_sap_ev_deactivation_req(struct llc_sap *sap, struct sk_buff *skb) ...@@ -111,5 +111,5 @@ int llc_sap_ev_deactivation_req(struct llc_sap *sap, struct sk_buff *skb)
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
return ev->type == LLC_SAP_EV_TYPE_SIMPLE && return ev->type == LLC_SAP_EV_TYPE_SIMPLE &&
ev->data.a.ev == LLC_SAP_EV_DEACTIVATION_REQ ? 0 : 1; ev->prim_type == LLC_SAP_EV_DEACTIVATION_REQ ? 0 : 1;
} }
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <net/llc_s_ac.h> #include <net/llc_s_ac.h>
#include <net/llc_s_st.h> #include <net/llc_s_st.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/tcp.h>
#include <net/llc_main.h> #include <net/llc_main.h>
#include <net/llc_mac.h> #include <net/llc_mac.h>
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
...@@ -39,11 +40,15 @@ static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap, ...@@ -39,11 +40,15 @@ static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
*/ */
void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk) void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk)
{ {
spin_lock_bh(&sap->sk_list.lock); write_lock_bh(&sap->sk_list.lock);
llc_sk(sk)->sap = sap; llc_sk(sk)->sap = sap;
list_add_tail(&llc_sk(sk)->node, &sap->sk_list.list); sk->next = sap->sk_list.list;
if (sk->next)
sap->sk_list.list->pprev = &sk->next;
sap->sk_list.list = sk;
sk->pprev = &sap->sk_list.list;
sock_hold(sk); sock_hold(sk);
spin_unlock_bh(&sap->sk_list.lock); write_unlock_bh(&sap->sk_list.lock);
} }
/** /**
...@@ -55,28 +60,53 @@ void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk) ...@@ -55,28 +60,53 @@ void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk)
*/ */
void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk)
{ {
spin_lock_bh(&sap->sk_list.lock); write_lock_bh(&sap->sk_list.lock);
list_del(&llc_sk(sk)->node); if (sk->pprev) {
if (sk->next)
sk->next->pprev = sk->pprev;
*sk->pprev = sk->next;
sk->pprev = NULL;
/*
* This only makes sense if the socket was inserted on the
* list, if sk->pprev is NULL it wasn't
*/
sock_put(sk); sock_put(sk);
spin_unlock_bh(&sap->sk_list.lock); }
write_unlock_bh(&sap->sk_list.lock);
} }
/** /**
* llc_sap_state_process - sends event to SAP state machine * llc_sap_state_process - sends event to SAP state machine
* @sap: pointer to SAP * @sap: sap to use
* @skb: pointer to occurred event * @skb: pointer to occurred event
* *
* After executing actions of the event, upper layer will be indicated * After executing actions of the event, upper layer will be indicated
* if needed(on receiving an UI frame). * if needed(on receiving an UI frame). sk can be null for the
* datalink_proto case.
*/ */
void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb) void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
{ {
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
/*
* We have to hold the skb, because llc_sap_next_state
* will kfree it in the sending path and we need to
* look at the skb->cb, where we encode llc_sap_state_ev.
*/
skb_get(skb);
ev->ind_cfm_flag = 0;
llc_sap_next_state(sap, skb); llc_sap_next_state(sap, skb);
if (ev->ind_cfm_flag == LLC_IND) if (ev->ind_cfm_flag == LLC_IND) {
sap->ind(ev->prim); if (skb->sk->state == TCP_LISTEN)
else if (ev->type == LLC_SAP_EV_TYPE_PDU) kfree_skb(skb);
else {
llc_save_primitive(skb, ev->prim);
/* queue skb to the user. */
if (sock_queue_rcv_skb(skb->sk, skb))
kfree_skb(skb);
}
}
kfree_skb(skb); kfree_skb(skb);
} }
...@@ -89,43 +119,17 @@ void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb) ...@@ -89,43 +119,17 @@ void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb)
{ {
struct llc_pdu_un *pdu; struct llc_pdu_un *pdu;
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
struct llc_prim_if_block *prim = &sap->llc_ind_prim;
union llc_u_prim_data *prim_data = prim->data;
u8 lfb;
llc_pdu_decode_sa(skb, prim_data->udata.saddr.mac);
llc_pdu_decode_da(skb, prim_data->udata.daddr.mac);
llc_pdu_decode_dsap(skb, &prim_data->udata.daddr.lsap);
llc_pdu_decode_ssap(skb, &prim_data->udata.saddr.lsap);
prim_data->udata.pri = 0;
prim_data->udata.skb = skb;
pdu = llc_pdu_un_hdr(skb); pdu = llc_pdu_un_hdr(skb);
switch (LLC_U_PDU_RSP(pdu)) { switch (LLC_U_PDU_RSP(pdu)) {
case LLC_1_PDU_CMD_TEST: case LLC_1_PDU_CMD_TEST:
prim->prim = LLC_TEST_PRIM; ev->prim = LLC_TEST_PRIM; break;
break;
case LLC_1_PDU_CMD_XID: case LLC_1_PDU_CMD_XID:
prim->prim = LLC_XID_PRIM; ev->prim = LLC_XID_PRIM; break;
break;
case LLC_1_PDU_CMD_UI: case LLC_1_PDU_CMD_UI:
if (skb->protocol == ntohs(ETH_P_TR_802_2)) { ev->prim = LLC_DATAUNIT_PRIM; break;
if (((struct trh_hdr *)skb->mac.raw)->rcf) {
lfb = ntohs(((struct trh_hdr *)
skb->mac.raw)->rcf) &
0x0070;
prim_data->udata.lfb = lfb >> 4;
} else {
lfb = 0xFF;
prim_data->udata.lfb = 0xFF;
}
}
prim->prim = LLC_DATAUNIT_PRIM;
break;
} }
prim->data = prim_data;
prim->sap = sap;
ev->ind_cfm_flag = LLC_IND; ev->ind_cfm_flag = LLC_IND;
ev->prim = prim;
} }
/** /**
......
...@@ -51,11 +51,7 @@ static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START; ...@@ -51,11 +51,7 @@ static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
static u16 llc_ui_sap_link_no_max[256]; static u16 llc_ui_sap_link_no_max[256];
static struct sockaddr_llc llc_ui_addrnull; static struct sockaddr_llc llc_ui_addrnull;
static struct proto_ops llc_ui_ops; static struct proto_ops llc_ui_ops;
static struct sock *llc_ui_sockets;
static rwlock_t llc_ui_sockets_lock = RW_LOCK_UNLOCKED;
static int llc_ui_indicate(struct llc_prim_if_block *prim);
static int llc_ui_confirm(struct llc_prim_if_block *prim);
static int llc_ui_wait_for_conn(struct sock *sk, int timeout); static int llc_ui_wait_for_conn(struct sock *sk, int timeout);
static int llc_ui_wait_for_disc(struct sock *sk, int timeout); static int llc_ui_wait_for_disc(struct sock *sk, int timeout);
static int llc_ui_wait_for_data(struct sock *sk, int timeout); static int llc_ui_wait_for_data(struct sock *sk, int timeout);
...@@ -145,103 +141,6 @@ static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock) ...@@ -145,103 +141,6 @@ static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock)
return rc; return rc;
} }
/**
* __llc_ui_find_sk_by_addr - return socket matching local mac + sap.
* @addr: Local address to match.
*
* Search the local socket list and return the socket which has a matching
* local (mac + sap) address (allows null mac). This search will work on
* unconnected and connected sockets, though find_by_link_no is recommend
* for connected sockets.
* Returns sock upon match, %NULL otherwise.
*/
static struct sock *__llc_ui_find_sk_by_addr(struct llc_addr *laddr,
struct llc_addr *daddr,
struct net_device *dev)
{
struct sock *sk;
for (sk = llc_ui_sockets; sk; sk = sk->next) {
struct llc_opt *llc = llc_sk(sk);
if (llc->addr.sllc_ssap != laddr->lsap)
continue;
if (llc_mac_null(llc->addr.sllc_smac)) {
if (!llc_mac_null(llc->addr.sllc_mmac) &&
!llc_mac_match(llc->addr.sllc_mmac,
laddr->mac))
continue;
break;
}
if (dev && !llc_mac_null(llc->addr.sllc_mmac) &&
llc_mac_match(llc->addr.sllc_mmac, laddr->mac) &&
llc_mac_match(llc->addr.sllc_smac, dev->dev_addr))
break;
if (dev->flags & IFF_LOOPBACK)
break;
if (!llc_mac_match(llc->addr.sllc_smac, laddr->mac))
continue;
if (llc_mac_null(llc->addr.sllc_dmac))
break;
}
return sk;
}
static struct sock *llc_ui_find_sk_by_addr(struct llc_addr *addr,
struct llc_addr *daddr,
struct net_device *dev)
{
struct sock *sk;
read_lock(&llc_ui_sockets_lock);
sk = __llc_ui_find_sk_by_addr(addr, daddr, dev);
if (sk)
sock_hold(sk);
read_unlock(&llc_ui_sockets_lock);
return sk;
}
/**
* llc_ui_insert_socket - insert socket into list
* @sk: Socket to insert.
*
* Insert a socket into the local llc socket list.
*/
static __inline__ void llc_ui_insert_socket(struct sock *sk)
{
write_lock_bh(&llc_ui_sockets_lock);
sk->next = llc_ui_sockets;
if (sk->next)
llc_ui_sockets->pprev = &sk->next;
llc_ui_sockets = sk;
sk->pprev = &llc_ui_sockets;
sock_hold(sk);
write_unlock_bh(&llc_ui_sockets_lock);
}
/**
* llc_ui_remove_socket - remove socket from list
* @sk: Socket to remove.
*
* Remove a socket from the local llc socket list.
*/
static __inline__ void llc_ui_remove_socket(struct sock *sk)
{
write_lock_bh(&llc_ui_sockets_lock);
if (sk->pprev) {
if (sk->next)
sk->next->pprev = sk->pprev;
*sk->pprev = sk->next;
sk->pprev = NULL;
/*
* This only makes sense if the socket was inserted on the
* list, if sk->pprev is NULL it wasn't
*/
sock_put(sk);
}
write_unlock_bh(&llc_ui_sockets_lock);
}
static void llc_ui_sk_init(struct socket *sock, struct sock *sk) static void llc_ui_sk_init(struct socket *sock, struct sock *sk)
{ {
sk->type = sock->type; sk->type = sock->type;
...@@ -296,12 +195,10 @@ static int llc_ui_release(struct socket *sock) ...@@ -296,12 +195,10 @@ static int llc_ui_release(struct socket *sock)
llc->laddr.lsap, llc->daddr.lsap); llc->laddr.lsap, llc->daddr.lsap);
if (!llc_send_disc(sk)) if (!llc_send_disc(sk))
llc_ui_wait_for_disc(sk, sk->rcvtimeo); llc_ui_wait_for_disc(sk, sk->rcvtimeo);
if (!sk->zapped) { if (!sk->zapped)
llc_sap_unassign_sock(llc->sap, sk); llc_sap_unassign_sock(llc->sap, sk);
llc_ui_remove_socket(sk);
}
release_sock(sk); release_sock(sk);
if (llc->sap && list_empty(&llc->sap->sk_list.list)) if (llc->sap && !llc->sap->sk_list.list)
llc_sap_close(llc->sap); llc_sap_close(llc->sap);
sock_put(sk); sock_put(sk);
llc_sk_free(sk); llc_sk_free(sk);
...@@ -384,8 +281,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) ...@@ -384,8 +281,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
} }
sap = llc_sap_find(addr->sllc_ssap); sap = llc_sap_find(addr->sllc_ssap);
if (!sap) { if (!sap) {
sap = llc_sap_open(llc_ui_indicate, llc_ui_confirm, sap = llc_sap_open(addr->sllc_ssap, NULL);
addr->sllc_ssap);
rc = -EBUSY; /* some other network layer is using the sap */ rc = -EBUSY; /* some other network layer is using the sap */
if (!sap) if (!sap)
goto out; goto out;
...@@ -420,7 +316,6 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) ...@@ -420,7 +316,6 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
llc->daddr.lsap = addr->sllc_dsap; llc->daddr.lsap = addr->sllc_dsap;
memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN); memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
memcpy(&llc->addr, addr, sizeof(llc->addr)); memcpy(&llc->addr, addr, sizeof(llc->addr));
llc_ui_insert_socket(sk);
/* assign new connection to it's SAP */ /* assign new connection to it's SAP */
llc_sap_assign_sock(sap, sk); llc_sap_assign_sock(sap, sk);
rc = sk->zapped = 0; rc = sk->zapped = 0;
...@@ -769,7 +664,6 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -769,7 +664,6 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
/* put original socket back into a clean listen state. */ /* put original socket back into a clean listen state. */
sk->state = TCP_LISTEN; sk->state = TCP_LISTEN;
sk->ack_backlog--; sk->ack_backlog--;
llc_ui_insert_socket(newsk);
skb->sk = NULL; skb->sk = NULL;
dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__, dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__,
llc_sk(sk)->addr.sllc_ssap, newllc->addr.sllc_dsap); llc_sk(sk)->addr.sllc_ssap, newllc->addr.sllc_dsap);
...@@ -1126,178 +1020,6 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname, ...@@ -1126,178 +1020,6 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
return rc; return rc;
} }
/**
* llc_ui_ind_test - handle TEST indication
* @prim: Primitive block provided by the llc layer.
*
* handle TEST indication.
*/
static void llc_ui_ind_test(struct llc_prim_if_block *prim)
{
struct llc_prim_test *prim_data = &prim->data->test;
struct sk_buff *skb = prim_data->skb;
struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
&prim_data->saddr, skb->dev);
if (!sk)
goto out;
if (sk->state == TCP_LISTEN)
goto out_put;
/* save primitive for use by the user. */
addr->sllc_family = AF_LLC;
addr->sllc_arphrd = skb->dev->type;
addr->sllc_test = 1;
addr->sllc_xid = 0;
addr->sllc_ua = 0;
addr->sllc_dsap = prim_data->daddr.lsap;
memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
addr->sllc_ssap = prim_data->saddr.lsap;
memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
/* queue skb to the user. */
if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb);
out_put:
sock_put(sk);
out:;
}
/**
* llc_ui_ind_xid - handle XID indication
* @prim: Primitive block provided by the llc layer.
*
* handle XID indication.
*/
static void llc_ui_ind_xid(struct llc_prim_if_block *prim)
{
struct llc_prim_xid *prim_data = &prim->data->xid;
struct sk_buff *skb = prim_data->skb;
struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
&prim_data->saddr, skb->dev);
if (!sk)
goto out;
if (sk->state == TCP_LISTEN)
goto out_put;
/* save primitive for use by the user. */
addr->sllc_family = AF_LLC;
addr->sllc_arphrd = 0;
addr->sllc_test = 0;
addr->sllc_xid = 1;
addr->sllc_ua = 0;
addr->sllc_dsap = prim_data->daddr.lsap;
memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
addr->sllc_ssap = prim_data->saddr.lsap;
memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
/* queue skb to the user. */
if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb);
out_put:
sock_put(sk);
out:;
}
/**
* llc_ui_ind_dataunit - handle DATAUNIT indication
* @prim: Primitive block provided by the llc layer.
*
* handle DATAUNIT indication.
*/
static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim)
{
struct llc_prim_unit_data *prim_data = &prim->data->udata;
struct sk_buff *skb = prim_data->skb;
struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
&prim_data->saddr, skb->dev);
if (!sk)
goto out;
if (sk->state == TCP_LISTEN)
goto out_put;
/* save primitive for use by the user. */
addr->sllc_family = AF_LLC;
addr->sllc_arphrd = skb->dev->type;
addr->sllc_test = 0;
addr->sllc_xid = 0;
addr->sllc_ua = 1;
addr->sllc_dsap = prim_data->daddr.lsap;
memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
addr->sllc_ssap = prim_data->saddr.lsap;
memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
/* queue skb to the user. */
if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb);
out_put:
sock_put(sk);
out:;
}
/**
* llc_ui_indicate - LLC user interface hook into the LLC layer.
* @prim: Primitive block provided by the llc layer.
*
* LLC user interface hook into the LLC layer, every llc_ui sap references
* this function as its indicate handler.
* Always returns 0 to indicate reception of primitive.
*/
static int llc_ui_indicate(struct llc_prim_if_block *prim)
{
switch (prim->prim) {
case LLC_TEST_PRIM:
llc_ui_ind_test(prim); break;
case LLC_XID_PRIM:
llc_ui_ind_xid(prim); break;
case LLC_DATAUNIT_PRIM:
llc_ui_ind_dataunit(prim); break;
case LLC_CONN_PRIM:
dprintk("%s: shouldn't happen, LLC_CONN_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_DATA_PRIM:
dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_DISC_PRIM:
dprintk("%s: shouldn't happen, LLC_DISC_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_RESET_PRIM:
default: break;
}
return 0;
}
/**
* llc_ui_confirm - LLC user interface hook into the LLC layer
* @prim: Primitive block provided by the llc layer.
*
* LLC user interface hook into the LLC layer, every llc_ui sap references
* this function as its confirm handler.
* Always returns 0 to indicate reception of primitive.
*/
static int llc_ui_confirm(struct llc_prim_if_block *prim)
{
switch (prim->prim) {
case LLC_CONN_PRIM:
dprintk("%s: shouldn't happen, LLC_CONN_PRIM "
"is gone for ->conf()...\n", __FUNCTION__);
break;
case LLC_DATA_PRIM:
dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
"is gone for ->conf()...\n", __FUNCTION__);
break;
case LLC_DISC_PRIM:
dprintk("%s: shouldn't happen, LLC_DISC_PRIM "
"is gone for ->conf()...\n", __FUNCTION__);
break;
case LLC_RESET_PRIM: break;
default:
printk(KERN_ERR "%s: prim not supported%d\n", __FUNCTION__,
prim->prim);
break;
}
return 0;
}
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
#define MAC_FORMATTED_SIZE 17 #define MAC_FORMATTED_SIZE 17
static void llc_ui_format_mac(char *bf, unsigned char *mac) static void llc_ui_format_mac(char *bf, unsigned char *mac)
...@@ -1320,25 +1042,24 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1320,25 +1042,24 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length)
{ {
off_t pos = 0; off_t pos = 0;
off_t begin = 0; off_t begin = 0;
struct llc_opt *llc;
struct llc_sap *sap; struct llc_sap *sap;
struct list_head *sap_entry, *llc_entry; struct sock *sk;
struct list_head *sap_entry;
struct llc_station *station = llc_station_get(); struct llc_station *station = llc_station_get();
int len = sprintf(buffer, "SKt Mc local_mac_sap " int len = sprintf(buffer, "SKt Mc local_mac_sap "
"remote_mac_sap tx_queue rx_queue st uid " "remote_mac_sap tx_queue rx_queue st uid "
"link\n"); "link\n");
/* Output the LLC socket data for the /proc filesystem */ /* Output the LLC socket data for the /proc filesystem */
spin_lock_bh(&station->sap_list.lock); read_lock_bh(&station->sap_list.lock);
list_for_each(sap_entry, &station->sap_list.list) { list_for_each(sap_entry, &station->sap_list.list) {
sap = list_entry(sap_entry, struct llc_sap, node); sap = list_entry(sap_entry, struct llc_sap, node);
spin_lock_bh(&sap->sk_list.lock); read_lock_bh(&sap->sk_list.lock);
list_for_each(llc_entry, &sap->sk_list.list) { for (sk = sap->sk_list.list; sk; sk = sk->next) {
llc = list_entry(llc_entry, struct llc_opt, node); struct llc_opt *llc = llc_sk(sk);
len += sprintf(buffer + len, "%2X %2X ", len += sprintf(buffer + len, "%2X %2X ", sk->type,
llc->sk->type,
!llc_mac_null(llc->addr.sllc_mmac)); !llc_mac_null(llc->addr.sllc_mmac));
if (llc->dev && llc_mac_null(llc->addr.sllc_mmac)) if (llc->dev && llc_mac_null(llc->addr.sllc_mmac))
llc_ui_format_mac(buffer + len, llc_ui_format_mac(buffer + len,
...@@ -1358,12 +1079,11 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1358,12 +1079,11 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length)
len += sprintf(buffer + len, len += sprintf(buffer + len,
"@%02X %8d %8d %2d %3d ", "@%02X %8d %8d %2d %3d ",
llc->addr.sllc_dsap, llc->addr.sllc_dsap,
atomic_read(&llc->sk->wmem_alloc), atomic_read(&sk->wmem_alloc),
atomic_read(&llc->sk->rmem_alloc), atomic_read(&sk->rmem_alloc),
llc->sk->state, sk->state,
llc->sk->socket ? sk->socket ?
SOCK_INODE(llc->sk->socket)->i_uid : SOCK_INODE(sk->socket)->i_uid : -1);
-1);
len += sprintf(buffer + len, "%4d\n", llc->link); len += sprintf(buffer + len, "%4d\n", llc->link);
/* Are we still dumping unwanted data then discard the record */ /* Are we still dumping unwanted data then discard the record */
pos = begin + len; pos = begin + len;
...@@ -1375,9 +1095,9 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1375,9 +1095,9 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length) /* We have dumped enough */ if (pos > offset + length) /* We have dumped enough */
break; break;
} }
spin_unlock_bh(&sap->sk_list.lock); read_unlock_bh(&sap->sk_list.lock);
} }
spin_unlock_bh(&station->sap_list.lock); read_unlock_bh(&station->sap_list.lock);
/* The data in question runs from begin to begin + len */ /* The data in question runs from begin to begin + len */
*start = buffer + offset - begin; /* Start of wanted data */ *start = buffer + offset - begin; /* Start of wanted data */
...@@ -1393,7 +1113,7 @@ static struct net_proto_family llc_ui_family_ops = { ...@@ -1393,7 +1113,7 @@ static struct net_proto_family llc_ui_family_ops = {
.create = llc_ui_create, .create = llc_ui_create,
}; };
static struct proto_ops SOCKOPS_WRAPPED(llc_ui_ops) = { static struct proto_ops llc_ui_ops = {
.family = PF_LLC, .family = PF_LLC,
.release = llc_ui_release, .release = llc_ui_release,
.bind = llc_ui_bind, .bind = llc_ui_bind,
...@@ -1413,9 +1133,6 @@ static struct proto_ops SOCKOPS_WRAPPED(llc_ui_ops) = { ...@@ -1413,9 +1133,6 @@ static struct proto_ops SOCKOPS_WRAPPED(llc_ui_ops) = {
.sendpage = sock_no_sendpage, .sendpage = sock_no_sendpage,
}; };
#include <linux/smp_lock.h>
SOCKOPS_WRAP(llc_ui, PF_LLC);
static char llc_ui_banner[] __initdata = static char llc_ui_banner[] __initdata =
KERN_INFO "NET4.0 IEEE 802.2 BSD sockets, Jay Schulist, 2001, Arnaldo C. Melo, 2002\n"; KERN_INFO "NET4.0 IEEE 802.2 BSD sockets, Jay Schulist, 2001, Arnaldo C. Melo, 2002\n";
......
...@@ -1163,6 +1163,8 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt) ...@@ -1163,6 +1163,8 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt)
skb_queue_head_init(&q->direct_queue); skb_queue_head_init(&q->direct_queue);
q->direct_qlen = sch->dev->tx_queue_len; q->direct_qlen = sch->dev->tx_queue_len;
if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */
q->direct_qlen = 2;
q->timer.function = htb_timer; q->timer.function = htb_timer;
q->timer.data = (unsigned long)sch; q->timer.data = (unsigned long)sch;
...@@ -1429,6 +1431,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, ...@@ -1429,6 +1431,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
if (!rtab || !ctab) goto failure; if (!rtab || !ctab) goto failure;
if (!cl) { /* new class */ if (!cl) { /* new class */
/* check for valid classid */
if (!classid || TC_H_MAJ(classid^sch->handle) || htb_find(classid,sch))
goto failure;
/* check maximal depth */ /* check maximal depth */
if (parent && parent->parent && parent->parent->level < 2) { if (parent && parent->parent && parent->parent->level < 2) {
printk(KERN_ERR "htb: tree is too deep\n"); printk(KERN_ERR "htb: tree is too deep\n");
......
...@@ -96,7 +96,7 @@ unsigned long update_adler32(unsigned long adler, ...@@ -96,7 +96,7 @@ unsigned long update_adler32(unsigned long adler,
* one subtract at the MOST, since buf[n] * one subtract at the MOST, since buf[n]
* is a max of 255. * is a max of 255.
*/ */
if(s1 >= BASE) if (s1 >= BASE)
s1 -= BASE; s1 -= BASE;
/* s2 = (s2 + s1) % BASE */ /* s2 = (s2 + s1) % BASE */
......
...@@ -288,7 +288,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -288,7 +288,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
return NULL; return NULL;
} }
/* Free this association if possible. There may still be users, so /* Free this association if possible. There may still be users, so
* the actual deallocation may be delayed. * the actual deallocation may be delayed.
*/ */
...@@ -330,6 +329,11 @@ void sctp_association_free(sctp_association_t *asoc) ...@@ -330,6 +329,11 @@ void sctp_association_free(sctp_association_t *asoc)
sctp_association_put(asoc); sctp_association_put(asoc);
} }
/* Free peer's cached cookie. */
if (asoc->peer.cookie) {
kfree(asoc->peer.cookie);
}
/* Release the transport structures. */ /* Release the transport structures. */
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, sctp_transport_t, transports); transport = list_entry(pos, sctp_transport_t, transports);
...@@ -342,7 +346,6 @@ void sctp_association_free(sctp_association_t *asoc) ...@@ -342,7 +346,6 @@ void sctp_association_free(sctp_association_t *asoc)
sctp_association_put(asoc); sctp_association_put(asoc);
} }
/* Cleanup and free up an association. */ /* Cleanup and free up an association. */
static void sctp_association_destroy(sctp_association_t *asoc) static void sctp_association_destroy(sctp_association_t *asoc)
{ {
...@@ -387,8 +390,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -387,8 +390,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
asoc->peer.port = *port; asoc->peer.port = *port;
} }
SCTP_ASSERT(*port == asoc->peer.port, ":Invalid port\n", SCTP_ASSERT(*port == asoc->peer.port, ":Invalid port\n", return NULL);
return NULL);
/* Check to see if this is a duplicate. */ /* Check to see if this is a duplicate. */
peer = sctp_assoc_lookup_paddr(asoc, addr); peer = sctp_assoc_lookup_paddr(asoc, addr);
...@@ -464,6 +466,16 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -464,6 +466,16 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
/* Attach the remote transport to our asoc. */ /* Attach the remote transport to our asoc. */
list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); list_add_tail(&peer->transports, &asoc->peer.transport_addr_list);
/* If we do not yet have a primary path, set one. */
if (NULL == asoc->peer.primary_path) {
asoc->peer.primary_path = peer;
/* Set a default msg_name for events. */
memcpy(&asoc->peer.primary_addr, &peer->ipaddr,
sizeof(sockaddr_storage_t));
asoc->peer.active_path = peer;
asoc->peer.retran_path = peer;
}
/* If we do not yet have a primary path, set one. */ /* If we do not yet have a primary path, set one. */
if (NULL == asoc->peer.primary_path) { if (NULL == asoc->peer.primary_path) {
asoc->peer.primary_path = peer; asoc->peer.primary_path = peer;
......
...@@ -198,6 +198,7 @@ static const char *sctp_timer_tbl[] = { ...@@ -198,6 +198,7 @@ static const char *sctp_timer_tbl[] = {
"TIMEOUT_T2_SHUTDOWN", "TIMEOUT_T2_SHUTDOWN",
"TIMEOUT_T3_RTX", "TIMEOUT_T3_RTX",
"TIMEOUT_T4_RTO", "TIMEOUT_T4_RTO",
"TIMEOUT_T5_SHUTDOWN_GUARD",
"TIMEOUT_HEARTBEAT", "TIMEOUT_HEARTBEAT",
"TIMEOUT_SACK", "TIMEOUT_SACK",
"TIMEOUT_AUTOCLOSE", "TIMEOUT_AUTOCLOSE",
......
...@@ -92,6 +92,7 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto, ...@@ -92,6 +92,7 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
struct sock *sk, int priority) struct sock *sk, int priority)
{ {
sctp_opt_t *sp = sctp_sk(sk);
memset(ep, 0, sizeof(sctp_endpoint_t)); memset(ep, 0, sizeof(sctp_endpoint_t));
/* Initialize the base structure. */ /* Initialize the base structure. */
...@@ -129,22 +130,30 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, ...@@ -129,22 +130,30 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
/* Set up the base timeout information. */ /* Set up the base timeout information. */
ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] =
= SCTP_DEFAULT_TIMEOUT_T1_COOKIE; SCTP_DEFAULT_TIMEOUT_T1_COOKIE;
ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =
= SCTP_DEFAULT_TIMEOUT_T1_INIT; SCTP_DEFAULT_TIMEOUT_T1_INIT;
ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =
= sctp_sk(sk)->rtoinfo.srto_initial; sp->rtoinfo.srto_initial;
ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT]
= SCTP_DEFAULT_TIMEOUT_HEARTBEAT; /* sctpimpguide-05 Section 2.12.2
ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] * If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the
= SCTP_DEFAULT_TIMEOUT_SACK; * recommended value of 5 times 'RTO.Max'.
ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] */
= sctp_sk(sk)->autoclose * HZ; ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
ep->timeouts[SCTP_EVENT_TIMEOUT_PMTU_RAISE] = 5 * sp->rtoinfo.srto_max;
= SCTP_DEFAULT_TIMEOUT_PMTU_RAISE;
ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] =
SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
SCTP_DEFAULT_TIMEOUT_SACK;
ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
sp->autoclose * HZ;
ep->timeouts[SCTP_EVENT_TIMEOUT_PMTU_RAISE] =
SCTP_DEFAULT_TIMEOUT_PMTU_RAISE;
/* Set up the default send/receive buffer space. */ /* Set up the default send/receive buffer space. */
...@@ -251,7 +260,8 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, ...@@ -251,7 +260,8 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
* We do a linear search of the associations for this endpoint. * We do a linear search of the associations for this endpoint.
* We return the matching transport address too. * We return the matching transport address too.
*/ */
sctp_association_t *__sctp_endpoint_lookup_assoc(const sctp_endpoint_t *endpoint, sctp_association_t *__sctp_endpoint_lookup_assoc(
const sctp_endpoint_t *endpoint,
const sockaddr_storage_t *paddr, const sockaddr_storage_t *paddr,
sctp_transport_t **transport) sctp_transport_t **transport)
{ {
...@@ -360,10 +370,5 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -360,10 +370,5 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
/* Is this the right way to pass errors up to the ULP? */ /* Is this the right way to pass errors up to the ULP? */
if (error) if (error)
ep->base.sk->err = -error; ep->base.sk->err = -error;
out: out:
} }
...@@ -189,6 +189,80 @@ int sctp_v6_get_dst_mtu(const sockaddr_storage_t *address) ...@@ -189,6 +189,80 @@ int sctp_v6_get_dst_mtu(const sockaddr_storage_t *address)
return dst_mtu; return dst_mtu;
} }
/* Initialize a PF_INET6 socket msg_name. */
static void sctp_inet6_msgname(char *msgname, int *addr_len)
{
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)msgname;
sin6->sin6_family = AF_INET6;
sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0;
*addr_len = sizeof(struct sockaddr_in6);
}
/* Initialize a PF_INET msgname from a ulpevent. */
static void sctp_inet6_event_msgname(sctp_ulpevent_t *event, char *msgname, int *addrlen)
{
struct sockaddr_in6 *sin6, *sin6from;
if (msgname) {
sockaddr_storage_t *addr;
sctp_inet6_msgname(msgname, addrlen);
sin6 = (struct sockaddr_in6 *)msgname;
sin6->sin6_port = htons(event->asoc->peer.port);
addr = &event->asoc->peer.primary_addr;
/* Note: If we go to a common v6 format, this code
* will change.
*/
/* Map ipv4 address into v4-mapped-on-v6 address. */
if (AF_INET == addr->sa.sa_family) {
/* FIXME: Easy, but there was no way to test this
* yet.
*/
return;
}
sin6from = &event->asoc->peer.primary_addr.v6;
ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr);
}
}
/* Initialize a msg_name from an inbound skb. */
static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
int *addr_len)
{
struct sctphdr *sh;
struct sockaddr_in6 *sin6;
if (msgname) {
sctp_inet6_msgname(msgname, addr_len);
sin6 = (struct sockaddr_in6 *)msgname;
sh = (struct sctphdr *)skb->h.raw;
sin6->sin6_port = sh->source;
/* FIXME: Map ipv4 address into v4-mapped-on-v6 address. */
if (__constant_htons(ETH_P_IP) == skb->protocol) {
/* FIXME: Easy, but there was no way to test this
* yet.
*/
return;
}
/* Otherwise, just copy the v6 address. */
ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
struct inet6_skb_parm *opt =
(struct inet6_skb_parm *) skb->cb;
sin6->sin6_scope_id = opt->iif;
}
}
}
static struct proto_ops inet6_seqpacket_ops = { static struct proto_ops inet6_seqpacket_ops = {
.family = PF_INET6, .family = PF_INET6,
.release = inet6_release, .release = inet6_release,
...@@ -238,15 +312,22 @@ static sctp_func_t sctp_ipv6_specific = { ...@@ -238,15 +312,22 @@ static sctp_func_t sctp_ipv6_specific = {
.sa_family = AF_INET6, .sa_family = AF_INET6,
}; };
static sctp_pf_t sctp_pf_inet6_specific = {
.event_msgname = sctp_inet6_event_msgname,
.skb_msgname = sctp_inet6_skb_msgname,
};
/* Initialize IPv6 support and register with inet6 stack. */ /* Initialize IPv6 support and register with inet6 stack. */
int sctp_v6_init(void) int sctp_v6_init(void)
{ {
/* Add SCTPv6 to inetsw6 linked list. */ /* Add SCTPv6 to inetsw6 linked list. */
inet6_register_protosw(&sctpv6_protosw); inet6_register_protosw(&sctpv6_protosw);
/* Register inet6 protocol. */ /* Register inet6 protocol. */
inet6_add_protocol(&sctpv6_protocol); inet6_add_protocol(&sctpv6_protocol);
/* Register the SCTP specfic PF_INET6 functions. */
sctp_set_pf_specific(PF_INET6, &sctp_pf_inet6_specific);
/* Fill in address family info. */ /* Fill in address family info. */
INIT_LIST_HEAD(&sctp_ipv6_specific.list); INIT_LIST_HEAD(&sctp_ipv6_specific.list);
list_add_tail(&sctp_ipv6_specific.list, &sctp_proto.address_families); list_add_tail(&sctp_ipv6_specific.list, &sctp_proto.address_families);
......
...@@ -129,7 +129,8 @@ void sctp_packet_free(sctp_packet_t *packet) ...@@ -129,7 +129,8 @@ void sctp_packet_free(sctp_packet_t *packet)
* as it can fit in the packet, but any more data that does not fit in this * as it can fit in the packet, but any more data that does not fit in this
* packet can be sent only after receiving the COOKIE_ACK. * packet can be sent only after receiving the COOKIE_ACK.
*/ */
sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet,
sctp_chunk_t *chunk)
{ {
sctp_xmit_t retval; sctp_xmit_t retval;
int error = 0; int error = 0;
...@@ -181,8 +182,8 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) ...@@ -181,8 +182,8 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
/* Both control chunks and data chunks with TSNs are /* Both control chunks and data chunks with TSNs are
* non-fragmentable. * non-fragmentable.
*/ */
int fragmentable = sctp_chunk_is_data(chunk) int fragmentable = sctp_chunk_is_data(chunk) &&
&& (!chunk->has_tsn); (!chunk->has_tsn);
if (packet_empty) { if (packet_empty) {
if (fragmentable) { if (fragmentable) {
retval = SCTP_XMIT_MUST_FRAG; retval = SCTP_XMIT_MUST_FRAG;
...@@ -221,10 +222,8 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) ...@@ -221,10 +222,8 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
} }
/* It is OK to send this chunk. */ /* It is OK to send this chunk. */
skb_queue_tail(&packet->chunks, skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
(struct sk_buff *)chunk);
packet->size += chunk_len; packet->size += chunk_len;
finish: finish:
return retval; return retval;
} }
...@@ -337,7 +336,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -337,7 +336,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
} }
/* Build the SCTP header. */ /* Build the SCTP header. */
sh = (struct sctphdr *) skb_push(nskb, sizeof(struct sctphdr)); sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));
sh->source = htons(packet->source_port); sh->source = htons(packet->source_port);
sh->dest = htons(packet->destination_port); sh->dest = htons(packet->destination_port);
...@@ -467,7 +466,8 @@ static void sctp_packet_reset(sctp_packet_t *packet) ...@@ -467,7 +466,8 @@ static void sctp_packet_reset(sctp_packet_t *packet)
} }
/* This private function handles the specifics of appending DATA chunks. */ /* This private function handles the specifics of appending DATA chunks. */
static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *chunk) static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet,
sctp_chunk_t *chunk)
{ {
sctp_xmit_t retval = SCTP_XMIT_OK; sctp_xmit_t retval = SCTP_XMIT_OK;
size_t datasize, rwnd, inflight; size_t datasize, rwnd, inflight;
...@@ -502,12 +502,13 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t * ...@@ -502,12 +502,13 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *
} }
} }
/* sctpimpguide-05 2.14.2 D) When the time comes for the sender to /* sctpimpguide-05 2.14.2
* D) When the time comes for the sender to
* transmit new DATA chunks, the protocol parameter Max.Burst MUST * transmit new DATA chunks, the protocol parameter Max.Burst MUST
* first be applied to limit how many new DATA chunks may be sent. * first be applied to limit how many new DATA chunks may be sent.
* The limit is applied by adjusting cwnd as follows: * The limit is applied by adjusting cwnd as follows:
* if((flightsize + Max.Burst*MTU) < cwnd) * if ((flightsize + Max.Burst * MTU) < cwnd)
* cwnd = flightsize + Max.Burst*MTU * cwnd = flightsize + Max.Burst * MTU
*/ */
max_burst_bytes = transport->asoc->max_burst * transport->asoc->pmtu; max_burst_bytes = transport->asoc->max_burst * transport->asoc->pmtu;
if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { if ((transport->flight_size + max_burst_bytes) < transport->cwnd) {
...@@ -552,7 +553,3 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t * ...@@ -552,7 +553,3 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *
finish: finish:
return retval; return retval;
} }
...@@ -196,23 +196,14 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk) ...@@ -196,23 +196,14 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk)
return error; return error;
} }
/* Mark all the eligible packets on a transport for retransmission and force /* Mark all the eligible packets on a transport for retransmission. */
* one packet out. void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport,
*/
void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport,
__u8 fast_retransmit) __u8 fast_retransmit)
{ {
struct list_head *lchunk; struct list_head *lchunk;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
int error = 0;
struct list_head tlist; struct list_head tlist;
if (fast_retransmit) {
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
} else {
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX);
}
INIT_LIST_HEAD(&tlist); INIT_LIST_HEAD(&tlist);
while (!list_empty(&transport->transmitted)) { while (!list_empty(&transport->transmitted)) {
...@@ -276,7 +267,26 @@ void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport, ...@@ -276,7 +267,26 @@ void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport,
transport->flight_size, transport->flight_size,
transport->partial_bytes_acked); transport->partial_bytes_acked);
}
/* Mark all the eligible packets on a transport for retransmission and force
* one packet out.
*/
void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport,
__u8 fast_retransmit)
{
int error = 0;
if (fast_retransmit) {
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
} else {
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX);
}
sctp_retransmit_mark(q, transport, fast_retransmit);
error = sctp_flush_outqueue(q, /* rtx_timeout */ 1); error = sctp_flush_outqueue(q, /* rtx_timeout */ 1);
if (error) if (error)
q->asoc->base.sk->err = -error; q->asoc->base.sk->err = -error;
} }
...@@ -370,8 +380,7 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, ...@@ -370,8 +380,7 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt,
/* The append was successful, so add this chunk to /* The append was successful, so add this chunk to
* the transmitted list. * the transmitted list.
*/ */
list_add_tail(lchunk, list_add_tail(lchunk, &transport->transmitted);
&transport->transmitted);
*start_timer = 1; *start_timer = 1;
q->empty = 0; q->empty = 0;
...@@ -389,8 +398,7 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, ...@@ -389,8 +398,7 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt,
* chunk that is currently in the process of fragmentation. * chunk that is currently in the process of fragmentation.
*/ */
void sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos, void sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos,
sctp_packet_t *packet, sctp_packet_t *packet, sctp_chunk_t *frag, __u32 tsn)
sctp_chunk_t *frag, __u32 tsn)
{ {
sctp_transport_t *transport = packet->transport; sctp_transport_t *transport = packet->transport;
struct sk_buff_head *queue = &q->out; struct sk_buff_head *queue = &q->out;
...@@ -499,7 +507,8 @@ void sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet, ...@@ -499,7 +507,8 @@ void sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet,
* fragments. It returns the first fragment with the frag_list field holding * fragments. It returns the first fragment with the frag_list field holding
* the remaining fragments. * the remaining fragments.
*/ */
sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len) sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
size_t max_frag_data_len)
{ {
sctp_association_t *asoc = chunk->asoc; sctp_association_t *asoc = chunk->asoc;
void *data_ptr = chunk->subh.data_hdr; void *data_ptr = chunk->subh.data_hdr;
...@@ -533,11 +542,14 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len) ...@@ -533,11 +542,14 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len)
/* Make the middle fragments. */ /* Make the middle fragments. */
while (chunk_data_len > max_frag_data_len) { while (chunk_data_len > max_frag_data_len) {
frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len,
data_ptr, SCTP_DATA_MIDDLE_FRAG, ssn); data_ptr, SCTP_DATA_MIDDLE_FRAG,
ssn);
if (!frag) if (!frag)
goto err; goto err;
/* Add the middle fragment to the first fragment's frag_list. */ /* Add the middle fragment to the first fragment's
* frag_list.
*/
list_add_tail(&frag->frag_list, frag_list); list_add_tail(&frag->frag_list, frag_list);
chunk_data_len -= max_frag_data_len; chunk_data_len -= max_frag_data_len;
...@@ -674,7 +686,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -674,7 +686,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
(void) (*q->build_output)(&singleton, chunk); (void) (*q->build_output)(&singleton, chunk);
error = (*q->force_output)(&singleton); error = (*q->force_output)(&singleton);
if (error < 0) if (error < 0)
return(error); return error;
break; break;
case SCTP_CID_ABORT: case SCTP_CID_ABORT:
...@@ -705,10 +717,10 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -705,10 +717,10 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
/* Is it OK to send data chunks? */ /* Is it OK to send data chunks? */
switch (asoc->state) { switch (asoc->state) {
case SCTP_STATE_COOKIE_ECHOED: case SCTP_STATE_COOKIE_ECHOED:
/* Only allow bundling, if this packet has a COOKIE-ECHO /* Only allow bundling when this packet has a COOKIE-ECHO
* chunk. * chunk.
*/ */
if (packet && !packet->has_cookie_echo) if (!packet || !packet->has_cookie_echo)
break; break;
/* fallthru */ /* fallthru */
...@@ -748,6 +760,12 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -748,6 +760,12 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
if (start_timer) if (start_timer)
sctp_transport_reset_timers(transport); sctp_transport_reset_timers(transport);
/* This can happen on COOKIE-ECHO resend. Only
* one chunk can get bundled with a COOKIE-ECHO.
*/
if (packet->has_cookie_echo)
goto sctp_flush_out;
} }
/* Finally, transmit new packets. */ /* Finally, transmit new packets. */
...@@ -813,8 +831,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -813,8 +831,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
ntohl(chunk->subh.data_hdr->tsn), ntohl(chunk->subh.data_hdr->tsn),
chunk->skb ?chunk->skb->head : 0, chunk->skb ?chunk->skb->head : 0,
chunk->skb ? chunk->skb ?
atomic_read(&chunk->skb->users) : atomic_read(&chunk->skb->users) : -1);
-1);
/* Add the chunk to the packet. */ /* Add the chunk to the packet. */
status = (*q->build_output)(packet, chunk); status = (*q->build_output)(packet, chunk);
...@@ -827,7 +844,8 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -827,7 +844,8 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
*/ */
SCTP_DEBUG_PRINTK("sctp_flush_outqueue: could" SCTP_DEBUG_PRINTK("sctp_flush_outqueue: could"
"not transmit TSN: 0x%x, status: %d\n", "not transmit TSN: 0x%x, status: %d\n",
ntohl(chunk->subh.data_hdr->tsn), status); ntohl(chunk->subh.data_hdr->tsn),
status);
skb_queue_head(queue, (struct sk_buff *)chunk); skb_queue_head(queue, (struct sk_buff *)chunk);
goto sctp_flush_out; goto sctp_flush_out;
break; break;
...@@ -857,7 +875,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -857,7 +875,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
default: default:
BUG(); BUG();
}; }
/* BUG: We assume that the (*q->force_output()) /* BUG: We assume that the (*q->force_output())
* call below will succeed all the time and add the * call below will succeed all the time and add the
...@@ -875,13 +893,19 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -875,13 +893,19 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
sctp_transport_reset_timers(transport); sctp_transport_reset_timers(transport);
q->empty = 0; q->empty = 0;
/* Only let one DATA chunk get bundled with a
* COOKIE-ECHO chunk.
*/
if (packet->has_cookie_echo)
goto sctp_flush_out;
} }
break; break;
default: default:
/* Do nothing. */ /* Do nothing. */
break; break;
}; }
sctp_flush_out: sctp_flush_out:
/* Before returning, examine all the transports touched in /* Before returning, examine all the transports touched in
...@@ -986,8 +1010,7 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack) ...@@ -986,8 +1010,7 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack)
ctsn = q->asoc->ctsn_ack_point; ctsn = q->asoc->ctsn_ack_point;
SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n", SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n",
__FUNCTION__, __FUNCTION__, sack_ctsn);
sack_ctsn);
SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association " SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association "
"%p is 0x%x.\n", __FUNCTION__, q->asoc, ctsn); "%p is 0x%x.\n", __FUNCTION__, q->asoc, ctsn);
...@@ -1114,8 +1137,9 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1114,8 +1137,9 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
* 6.3.1 C5) Karn's algorithm: RTT measurements * 6.3.1 C5) Karn's algorithm: RTT measurements
* MUST NOT be made using packets that were * MUST NOT be made using packets that were
* retransmitted (and thus for which it is * retransmitted (and thus for which it is
* ambiguous whether the reply was for the first * ambiguous whether the reply was for the
* instance of the packet or a later instance). * first instance of the packet or a later
* instance).
*/ */
if ((!tchunk->tsn_gap_acked) && if ((!tchunk->tsn_gap_acked) &&
(1 == tchunk->num_times_sent) && (1 == tchunk->num_times_sent) &&
...@@ -1150,15 +1174,15 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1150,15 +1174,15 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
* 'Stray DATA chunk(s)' record the highest TSN * 'Stray DATA chunk(s)' record the highest TSN
* reported as newly acknowledged, call this * reported as newly acknowledged, call this
* value 'HighestTSNinSack'. A newly * value 'HighestTSNinSack'. A newly
* acknowledged DATA chunk is one not previously * acknowledged DATA chunk is one not
* acknowledged in a SACK. * previously acknowledged in a SACK.
* *
* When the SCTP sender of data receives a SACK * When the SCTP sender of data receives a SACK
* chunk that acknowledges, for the first time, * chunk that acknowledges, for the first time,
* the receipt of a DATA chunk, all the still * the receipt of a DATA chunk, all the still
* unacknowledged DATA chunks whose TSN is older * unacknowledged DATA chunks whose TSN is
* than that newly acknowledged DATA chunk, are * older than that newly acknowledged DATA
* qualified as 'Stray DATA chunks'. * chunk, are qualified as 'Stray DATA chunks'.
*/ */
if (!tchunk->tsn_gap_acked) { if (!tchunk->tsn_gap_acked) {
tchunk->tsn_gap_acked = 1; tchunk->tsn_gap_acked = 1;
...@@ -1217,8 +1241,8 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1217,8 +1241,8 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
} else { } else {
if (tchunk->tsn_gap_acked) { if (tchunk->tsn_gap_acked) {
SCTP_DEBUG_PRINTK("%s: Receiver reneged on data " SCTP_DEBUG_PRINTK("%s: Receiver reneged on "
"TSN: 0x%x\n", "data TSN: 0x%x\n",
__FUNCTION__, __FUNCTION__,
tsn); tsn);
tchunk->tsn_gap_acked = 0; tchunk->tsn_gap_acked = 0;
...@@ -1227,10 +1251,11 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1227,10 +1251,11 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
/* RFC 2960 6.3.2 Retransmission Timer Rules /* RFC 2960 6.3.2 Retransmission Timer Rules
* *
* R4) Whenever a SACK is received missing a TSN * R4) Whenever a SACK is received missing a
* that was previously acknowledged via a Gap Ack * TSN that was previously acknowledged via a
* Block, start T3-rtx for the destination * Gap Ack Block, start T3-rtx for the
* address to which the DATA chunk was originally * destination address to which the DATA
* chunk was originally
* transmitted if it is not already running. * transmitted if it is not already running.
*/ */
restart_timer = 1; restart_timer = 1;
...@@ -1306,7 +1331,8 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1306,7 +1331,8 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
* active if it is not so marked. * active if it is not so marked.
*/ */
if (!transport->state.active) { if (!transport->state.active) {
sctp_assoc_control_transport(transport->asoc, sctp_assoc_control_transport(
transport->asoc,
transport, transport,
SCTP_TRANSPORT_UP, SCTP_TRANSPORT_UP,
SCTP_RECEIVED_SACK); SCTP_RECEIVED_SACK);
...@@ -1398,8 +1424,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1398,8 +1424,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, " SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, "
"ssthresh: %d, flight_size: %d, pba: %d\n", "ssthresh: %d, flight_size: %d, pba: %d\n",
__FUNCTION__, __FUNCTION__, transport, transport->cwnd,
transport, transport->cwnd,
transport->ssthresh, transport->flight_size, transport->ssthresh, transport->flight_size,
transport->partial_bytes_acked); transport->partial_bytes_acked);
} }
......
...@@ -66,6 +66,9 @@ struct proc_dir_entry *proc_net_sctp; ...@@ -66,6 +66,9 @@ struct proc_dir_entry *proc_net_sctp;
*/ */
static struct socket *sctp_ctl_socket; static struct socket *sctp_ctl_socket;
static sctp_pf_t *sctp_pf_inet6_specific;
static sctp_pf_t *sctp_pf_inet_specific;
extern struct net_proto_family inet_family_ops; extern struct net_proto_family inet_family_ops;
/* Return the address of the control sock. */ /* Return the address of the control sock. */
...@@ -91,7 +94,7 @@ void sctp_proc_init(void) ...@@ -91,7 +94,7 @@ void sctp_proc_init(void)
void sctp_proc_exit(void) void sctp_proc_exit(void)
{ {
if (proc_net_sctp) { if (proc_net_sctp) {
proc_net_sctp= NULL; proc_net_sctp = NULL;
remove_proc_entry("net/sctp", 0); remove_proc_entry("net/sctp", 0);
} }
} }
...@@ -135,7 +138,8 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, ...@@ -135,7 +138,8 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
* the protocol structure. * the protocol structure.
* FIXME: Make this an address family function. * FIXME: Make this an address family function.
*/ */
static inline void sctp_v6_get_local_addr_list(sctp_protocol_t *proto, struct net_device *dev) static inline void sctp_v6_get_local_addr_list(sctp_protocol_t *proto,
struct net_device *dev)
{ {
#ifdef SCTP_V6_SUPPORT #ifdef SCTP_V6_SUPPORT
/* FIXME: The testframe doesn't support this function. */ /* FIXME: The testframe doesn't support this function. */
...@@ -239,8 +243,7 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp, ...@@ -239,8 +243,7 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp,
(((AF_INET6 == addr->a.sa.sa_family) && (((AF_INET6 == addr->a.sa.sa_family) &&
(copy_flags & SCTP_ADDR6_ALLOWED) && (copy_flags & SCTP_ADDR6_ALLOWED) &&
(copy_flags & SCTP_ADDR6_PEERSUPP)))) { (copy_flags & SCTP_ADDR6_PEERSUPP)))) {
error = sctp_add_bind_addr(bp, error = sctp_add_bind_addr(bp, &addr->a,
&addr->a,
priority); priority);
if (error) if (error)
goto end_copy; goto end_copy;
...@@ -286,7 +289,8 @@ int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) ...@@ -286,7 +289,8 @@ int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address)
/* Event handler for inet device events. /* Event handler for inet device events.
* Basically, whenever there is an event, we re-build our local address list. * Basically, whenever there is an event, we re-build our local address list.
*/ */
static int sctp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) static int sctp_netdev_event(struct notifier_block *this, unsigned long event,
void *ptr)
{ {
long flags __attribute__ ((unused)); long flags __attribute__ ((unused));
...@@ -347,6 +351,52 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address) ...@@ -347,6 +351,52 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address)
return retval; return retval;
} }
/* Common code to initialize a AF_INET msg_name. */
static void sctp_inet_msgname(char *msgname, int *addr_len)
{
struct sockaddr_in *sin;
sin = (struct sockaddr_in *)msgname;
*addr_len = sizeof(struct sockaddr_in);
sin->sin_family = AF_INET;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
}
/* Copy the primary address of the peer primary address as the msg_name. */
static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int *addr_len)
{
struct sockaddr_in *sin, *sinfrom;
if (msgname) {
sctp_inet_msgname(msgname, addr_len);
sin = (struct sockaddr_in *)msgname;
sinfrom = &event->asoc->peer.primary_addr.v4;
sin->sin_port = htons(event->asoc->peer.port);
sin->sin_addr.s_addr = sinfrom->sin_addr.s_addr;
}
}
/* Initialize and copy out a msgname from an inbound skb. */
static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_len)
{
struct sctphdr *sh;
struct sockaddr_in *sin;
if (msgname) {
sctp_inet_msgname(msgname, addr_len);
sin = (struct sockaddr_in *)msgname;
sh = (struct sctphdr *)skb->h.raw;
sin->sin_port = sh->source;
sin->sin_addr.s_addr = skb->nh.iph->saddr;
}
}
static sctp_pf_t sctp_pf_inet = {
.event_msgname = sctp_inet_event_msgname,
.skb_msgname = sctp_inet_skb_msgname,
};
/* Registration for netdev events. */ /* Registration for netdev events. */
struct notifier_block sctp_netdev_notifier = { struct notifier_block sctp_netdev_notifier = {
.notifier_call = sctp_netdev_event, .notifier_call = sctp_netdev_event,
...@@ -403,6 +453,34 @@ sctp_func_t sctp_ipv4_specific = { ...@@ -403,6 +453,34 @@ sctp_func_t sctp_ipv4_specific = {
.sa_family = AF_INET, .sa_family = AF_INET,
}; };
sctp_pf_t *sctp_get_pf_specific(int family) {
switch (family) {
case PF_INET:
return sctp_pf_inet_specific;
case PF_INET6:
return sctp_pf_inet6_specific;
default:
return NULL;
}
}
/* Set the PF specific function table. */
void sctp_set_pf_specific(int family, sctp_pf_t *pf)
{
switch (family) {
case PF_INET:
sctp_pf_inet_specific = pf;
break;
case PF_INET6:
sctp_pf_inet6_specific = pf;
break;
default:
BUG();
break;
}
}
/* Initialize the universe into something sensible. */ /* Initialize the universe into something sensible. */
int sctp_init(void) int sctp_init(void)
{ {
...@@ -421,6 +499,8 @@ int sctp_init(void) ...@@ -421,6 +499,8 @@ int sctp_init(void)
/* Initialize object count debugging. */ /* Initialize object count debugging. */
sctp_dbg_objcnt_init(); sctp_dbg_objcnt_init();
/* Initialize the SCTP specific PF functions. */
sctp_set_pf_specific(PF_INET, &sctp_pf_inet);
/* /*
* 14. Suggested SCTP Protocol Parameter Values * 14. Suggested SCTP Protocol Parameter Values
*/ */
...@@ -468,7 +548,7 @@ int sctp_init(void) ...@@ -468,7 +548,7 @@ int sctp_init(void)
sctp_proto.assoc_hashbucket = (sctp_hashbucket_t *) sctp_proto.assoc_hashbucket = (sctp_hashbucket_t *)
kmalloc(4096 * sizeof(sctp_hashbucket_t), GFP_KERNEL); kmalloc(4096 * sizeof(sctp_hashbucket_t), GFP_KERNEL);
if (!sctp_proto.assoc_hashbucket) { if (!sctp_proto.assoc_hashbucket) {
printk (KERN_ERR "SCTP: Failed association hash alloc.\n"); printk(KERN_ERR "SCTP: Failed association hash alloc.\n");
status = -ENOMEM; status = -ENOMEM;
goto err_ahash_alloc; goto err_ahash_alloc;
} }
...@@ -482,7 +562,7 @@ int sctp_init(void) ...@@ -482,7 +562,7 @@ int sctp_init(void)
sctp_proto.ep_hashbucket = (sctp_hashbucket_t *) sctp_proto.ep_hashbucket = (sctp_hashbucket_t *)
kmalloc(64 * sizeof(sctp_hashbucket_t), GFP_KERNEL); kmalloc(64 * sizeof(sctp_hashbucket_t), GFP_KERNEL);
if (!sctp_proto.ep_hashbucket) { if (!sctp_proto.ep_hashbucket) {
printk (KERN_ERR "SCTP: Failed endpoint_hash alloc.\n"); printk(KERN_ERR "SCTP: Failed endpoint_hash alloc.\n");
status = -ENOMEM; status = -ENOMEM;
goto err_ehash_alloc; goto err_ehash_alloc;
} }
...@@ -497,7 +577,7 @@ int sctp_init(void) ...@@ -497,7 +577,7 @@ int sctp_init(void)
sctp_proto.port_hashtable = (sctp_bind_hashbucket_t *) sctp_proto.port_hashtable = (sctp_bind_hashbucket_t *)
kmalloc(4096 * sizeof(sctp_bind_hashbucket_t), GFP_KERNEL); kmalloc(4096 * sizeof(sctp_bind_hashbucket_t), GFP_KERNEL);
if (!sctp_proto.port_hashtable) { if (!sctp_proto.port_hashtable) {
printk (KERN_ERR "SCTP: Failed bind hash alloc."); printk(KERN_ERR "SCTP: Failed bind hash alloc.");
status = -ENOMEM; status = -ENOMEM;
goto err_bhash_alloc; goto err_bhash_alloc;
} }
......
...@@ -1418,6 +1418,7 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1418,6 +1418,7 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
__u8 *end; __u8 *end;
sctp_transport_t *transport; sctp_transport_t *transport;
struct list_head *pos, *temp; struct list_head *pos, *temp;
char *cookie;
/* We must include the address that the INIT packet came from. /* We must include the address that the INIT packet came from.
* This is the only address that matters for an INIT packet. * This is the only address that matters for an INIT packet.
...@@ -1471,6 +1472,15 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1471,6 +1472,15 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
/* Peer Rwnd : Current calculated value of the peer's rwnd. */ /* Peer Rwnd : Current calculated value of the peer's rwnd. */
asoc->peer.rwnd = asoc->peer.i.a_rwnd; asoc->peer.rwnd = asoc->peer.i.a_rwnd;
/* Copy cookie in case we need to resend COOKIE-ECHO. */
cookie = asoc->peer.cookie;
if (cookie) {
asoc->peer.cookie = kmalloc(asoc->peer.cookie_len, priority);
if (!asoc->peer.cookie)
goto clean_up;
memcpy(asoc->peer.cookie, cookie, asoc->peer.cookie_len);
}
/* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily /* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily
* high (for example, implementations MAY use the size of the receiver * high (for example, implementations MAY use the size of the receiver
* advertised window). * advertised window).
...@@ -1560,7 +1570,7 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, ...@@ -1560,7 +1570,7 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
break; break;
case SCTP_PARAM_HOST_NAME_ADDRESS: case SCTP_PARAM_HOST_NAME_ADDRESS:
SCTP_DEBUG_PRINTK("unimplmented SCTP_HOST_NAME_ADDRESS\n"); SCTP_DEBUG_PRINTK("unimplemented SCTP_HOST_NAME_ADDRESS\n");
break; break;
case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES: case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES:
...@@ -1595,13 +1605,12 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, ...@@ -1595,13 +1605,12 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
case SCTP_PARAM_STATE_COOKIE: case SCTP_PARAM_STATE_COOKIE:
asoc->peer.cookie_len = asoc->peer.cookie_len =
ntohs(param.p->length) - ntohs(param.p->length) - sizeof(sctp_paramhdr_t);
sizeof(sctp_paramhdr_t);
asoc->peer.cookie = param.cookie->body; asoc->peer.cookie = param.cookie->body;
break; break;
case SCTP_PARAM_HEATBEAT_INFO: case SCTP_PARAM_HEATBEAT_INFO:
SCTP_DEBUG_PRINTK("unimplmented " SCTP_DEBUG_PRINTK("unimplemented "
"SCTP_PARAM_HEATBEAT_INFO\n"); "SCTP_PARAM_HEATBEAT_INFO\n");
break; break;
......
...@@ -253,6 +253,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -253,6 +253,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_chunk_t *new_obj; sctp_chunk_t *new_obj;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
sctp_packet_t *packet; sctp_packet_t *packet;
struct list_head *pos;
struct timer_list *timer; struct timer_list *timer;
unsigned long timeout; unsigned long timeout;
sctp_transport_t *t; sctp_transport_t *t;
...@@ -336,9 +337,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -336,9 +337,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_PEER_INIT: case SCTP_CMD_PEER_INIT:
/* Process a unified INIT from the peer. */ /* Process a unified INIT from the peer. */
sctp_cmd_process_init(commands, sctp_cmd_process_init(commands, asoc, chunk,
asoc, chunk, command->obj.ptr, command->obj.ptr, priority);
priority);
break; break;
case SCTP_CMD_GEN_COOKIE_ECHO: case SCTP_CMD_GEN_COOKIE_ECHO:
...@@ -462,6 +462,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -462,6 +462,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break; break;
case SCTP_CMD_INIT_RESTART: case SCTP_CMD_INIT_RESTART:
/* Do the needed accounting and updates /* Do the needed accounting and updates
* associated with restarting an initialization * associated with restarting an initialization
* timer. * timer.
...@@ -474,6 +475,15 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -474,6 +475,15 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
asoc->max_init_timeo; asoc->max_init_timeo;
} }
/* If we've sent any data bundled with
* COOKIE-ECHO we need to resend.
*/
list_for_each(pos, &asoc->peer.transport_addr_list) {
t = list_entry(pos, sctp_transport_t,
transports);
sctp_retransmit_mark(&asoc->outqueue, t, 0);
}
sctp_add_cmd_sf(commands, sctp_add_cmd_sf(commands,
SCTP_CMD_TIMER_RESTART, SCTP_CMD_TIMER_RESTART,
SCTP_TO(command->obj.to)); SCTP_TO(command->obj.to));
...@@ -867,6 +877,14 @@ void sctp_generate_t2_shutdown_event(unsigned long data) ...@@ -867,6 +877,14 @@ void sctp_generate_t2_shutdown_event(unsigned long data)
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
} }
void sctp_generate_t5_shutdown_guard_event(unsigned long data)
{
sctp_association_t *asoc = (sctp_association_t *)data;
sctp_generate_timeout_event(asoc,
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD);
} /* sctp_generate_t5_shutdown_guard_event() */
void sctp_generate_autoclose_event(unsigned long data) void sctp_generate_autoclose_event(unsigned long data)
{ {
sctp_association_t *asoc = (sctp_association_t *) data; sctp_association_t *asoc = (sctp_association_t *) data;
...@@ -932,6 +950,7 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = { ...@@ -932,6 +950,7 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
sctp_generate_t2_shutdown_event, sctp_generate_t2_shutdown_event,
NULL, NULL,
NULL, NULL,
sctp_generate_t5_shutdown_guard_event,
sctp_generate_heartbeat_event, sctp_generate_heartbeat_event,
sctp_generate_sack_event, sctp_generate_sack_event,
sctp_generate_autoclose_event, sctp_generate_autoclose_event,
...@@ -1023,6 +1042,9 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, ...@@ -1023,6 +1042,9 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
SCTP_ULPEVENT(event)); SCTP_ULPEVENT(event));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
/* FIXME: We need to handle data that could not be sent or was not /* FIXME: We need to handle data that could not be sent or was not
* acked, if the user has enabled SEND_FAILED notifications. * acked, if the user has enabled SEND_FAILED notifications.
*/ */
......
...@@ -149,6 +149,9 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep, ...@@ -149,6 +149,9 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED)); SCTP_STATE(SCTP_STATE_CLOSED));
...@@ -160,35 +163,6 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep, ...@@ -160,35 +163,6 @@ sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
} }
/*
* Discard the whole packet.
*
* Section: 8.4 2)
*
* 2) If the OOTB packet contains an ABORT chunk, the receiver MUST
* silently discard the OOTB packet and take no further action.
* Otherwise,
*
* Verification Tag: No verification necessary
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_pdiscard(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
return SCTP_DISPOSITION_CONSUME;
}
/* /*
* Respond to a normal INIT chunk. * Respond to a normal INIT chunk.
* We are the side that is being asked for an association. * We are the side that is being asked for an association.
...@@ -338,20 +312,17 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, ...@@ -338,20 +312,17 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
if (!reply) if (!reply)
goto nomem; goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
SCTP_CHUNK(reply));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED)); SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB; return SCTP_DISPOSITION_DELETE_TCB;
} }
/* Tag the variable length paramters. Note that we never /* Tag the variable length paramters. Note that we never
* convert the parameters in an INIT chunk. * convert the parameters in an INIT chunk.
*/ */
chunk->param_hdr.v = chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t));
skb_pull(chunk->skb, sizeof(sctp_inithdr_t));
initchunk = (sctp_init_chunk_t *) chunk->chunk_hdr; initchunk = (sctp_init_chunk_t *) chunk->chunk_hdr;
...@@ -460,8 +431,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep, ...@@ -460,8 +431,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
case -SCTP_IERROR_BAD_SIG: case -SCTP_IERROR_BAD_SIG:
default: default:
return sctp_sf_pdiscard(ep, asoc, type, return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
arg, commands);
}; };
} }
...@@ -625,8 +595,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, ...@@ -625,8 +595,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
if (!reply) if (!reply)
goto nomem; goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
SCTP_CHUNK(reply));
/* Set transport error counter and association error counter /* Set transport error counter and association error counter
* when sending heartbeat. * when sending heartbeat.
...@@ -779,8 +748,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, ...@@ -779,8 +748,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
* sent and mark the destination transport address as active if * sent and mark the destination transport address as active if
* it is not so marked. * it is not so marked.
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_ON, sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_ON, SCTP_TRANSPORT(link));
SCTP_TRANSPORT(link));
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
...@@ -875,8 +843,10 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc, ...@@ -875,8 +843,10 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc,
/* Common helper routine for both duplicate and simulataneous INIT /* Common helper routine for both duplicate and simulataneous INIT
* chunk handling. * chunk handling.
*/ */
static sctp_disposition_t sctp_sf_do_unexpected_init(const sctp_endpoint_t *ep, static sctp_disposition_t sctp_sf_do_unexpected_init(
const sctp_association_t *asoc, const sctp_subtype_t type, const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg, sctp_cmd_seq_t *commands) void *arg, sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *chunk = arg; sctp_chunk_t *chunk = arg;
...@@ -894,8 +864,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(const sctp_endpoint_t *ep, ...@@ -894,8 +864,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(const sctp_endpoint_t *ep,
chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
/* Tag the variable length parameters. */ /* Tag the variable length parameters. */
chunk->param_hdr.v = chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t));
skb_pull(chunk->skb, sizeof(sctp_inithdr_t));
/* /*
* Other parameters for the endpoint SHOULD be copied from the * Other parameters for the endpoint SHOULD be copied from the
...@@ -912,10 +881,9 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(const sctp_endpoint_t *ep, ...@@ -912,10 +881,9 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(const sctp_endpoint_t *ep,
* Verification Tag and Peers Verification tag into a reserved * Verification Tag and Peers Verification tag into a reserved
* place (local tie-tag and per tie-tag) within the state cookie. * place (local tie-tag and per tie-tag) within the state cookie.
*/ */
sctp_process_init(new_asoc, chunk->chunk_hdr->type, sctp_process_init(new_asoc, chunk->chunk_hdr->type, sctp_source(chunk),
sctp_source(chunk), (sctp_init_chunk_t *)chunk->chunk_hdr, GFP_ATOMIC);
(sctp_init_chunk_t *)chunk->chunk_hdr,
GFP_ATOMIC);
sctp_tietags_populate(new_asoc, asoc); sctp_tietags_populate(new_asoc, asoc);
/* B) "Z" shall respond immediately with an INIT ACK chunk. */ /* B) "Z" shall respond immediately with an INIT ACK chunk. */
...@@ -1323,10 +1291,9 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, ...@@ -1323,10 +1291,9 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
/* "Decode" the chunk. We have no optional parameters so we /* "Decode" the chunk. We have no optional parameters so we
* are in good shape. * are in good shape.
*/ */
chunk->subh.cookie_hdr = chunk->subh.cookie_hdr = (sctp_signed_cookie_t *)chunk->skb->data;
(sctp_signed_cookie_t *) chunk->skb->data; skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t));
/* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie
* of a duplicate COOKIE ECHO match the Verification Tags of the * of a duplicate COOKIE ECHO match the Verification Tags of the
...@@ -1351,8 +1318,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, ...@@ -1351,8 +1318,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
case -SCTP_IERROR_BAD_SIG: case -SCTP_IERROR_BAD_SIG:
default: default:
return sctp_sf_pdiscard(ep, asoc, type, return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
arg, commands);
}; };
} }
...@@ -1398,6 +1364,65 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep, ...@@ -1398,6 +1364,65 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
} }
/*
* Process an ABORT. (SHUTDOWN-PENDING state)
*
* See sctp_sf_do_9_1_abort().
*/
sctp_disposition_t sctp_sf_shutdown_pending_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* Stop the T5-shutdown guard timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
return sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
}
/*
* Process an ABORT. (SHUTDOWN-SENT state)
*
* See sctp_sf_do_9_1_abort().
*/
sctp_disposition_t sctp_sf_shutdown_sent_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* Stop the T2-shutdown timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
/* Stop the T5-shutdown guard timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
return sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
}
/*
* Process an ABORT. (SHUTDOWN-ACK-SENT state)
*
* See sctp_sf_do_9_1_abort().
*/
sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* The same T2 timer, so we should be able to use
* common function with the SHUTDOWN-SENT state.
*/
return sctp_sf_shutdown_sent_abort(ep, asoc, type, arg, commands);
}
#if 0 #if 0
/* /*
* Handle a Stale COOKIE Error * Handle a Stale COOKIE Error
...@@ -1540,11 +1565,8 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep, ...@@ -1540,11 +1565,8 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
/* Check the verification tag. */ /* ASSOC_FAILED will DELETE_TCB. */
/* BUG: WRITE ME. */ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
/* BUG? This does not look complete... */ /* BUG? This does not look complete... */
return SCTP_DISPOSITION_ABORT; return SCTP_DISPOSITION_ABORT;
...@@ -1561,15 +1583,19 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep, ...@@ -1561,15 +1583,19 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
/* Check the verification tag. */
/* BUG: WRITE ME. */
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED)); SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
/* CMD_INIT_FAILED will DELETE_TCB. */ /* CMD_INIT_FAILED will DELETE_TCB. */
sctp_add_cmd_sf(commands,SCTP_CMD_INIT_FAILED, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB; /* BUG? This does not look complete... */
return SCTP_DISPOSITION_ABORT;
} }
/* /*
...@@ -1589,67 +1615,6 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep, ...@@ -1589,67 +1615,6 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep,
return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands); return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands);
} }
#if 0
/*
* Handle a shutdown timeout or INIT during a shutdown phase.
*
* Section: 9.2
* If an endpoint is in SHUTDOWN-ACK-SENT state and receives an INIT chunk
* (e.g., if the SHUTDOWN COMPLETE was lost) with source and destination
* transport addresses (either in the IP addresses or in the INIT chunk)
* that belong to this association, it should discard the INIT chunk and
* retransmit the SHUTDOWN ACK chunk.
*...
* While in SHUTDOWN-SENT state ... If the timer expires, the endpoint
* must re-send the SHUTDOWN ACK.
*
* Verification Tag: Neither the INIT nor the timeout will have a
* valid verification tag, so it is safe to ignore.
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_do_9_2_reshutack(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = arg;
/* If this was a timeout (not an INIT), then do the counter
* work. We might need to just dump the association.
*/
if (!chunk) {
if (1 + asoc->counters[SctpCounterRetran] >
asoc->maxRetrans) {
sctp_add_cmd(commands, SCTP_CMD_DELETE_TCB,
SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
}
retval->counters[0] = SCTP_COUNTER_INCR;
retval->counters[0] = SctpCounterRetran;
retval->counters[1] = 0;
retval->counters[1] = 0;
}
reply = sctp_make_shutdown_ack(asoc, chunk);
if (!reply)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
#endif /* 0 */
/* /*
* sctp_sf_do_9_2_shut * sctp_sf_do_9_2_shut
* *
...@@ -1694,7 +1659,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, ...@@ -1694,7 +1659,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep,
sctp_disposition_t disposition; sctp_disposition_t disposition;
/* Convert the elaborate header. */ /* Convert the elaborate header. */
sdh = (sctp_shutdownhdr_t *) chunk->skb->data; sdh = (sctp_shutdownhdr_t *)chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t)); skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t));
chunk->subh.shutdown_hdr = sdh; chunk->subh.shutdown_hdr = sdh;
...@@ -1718,8 +1683,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, ...@@ -1718,8 +1683,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep,
disposition = SCTP_DISPOSITION_CONSUME; disposition = SCTP_DISPOSITION_CONSUME;
if (sctp_outqueue_is_empty(&asoc->outqueue)) { if (sctp_outqueue_is_empty(&asoc->outqueue)) {
disposition = disposition = sctp_sf_do_9_2_shutdown_ack(ep, asoc, type,
sctp_sf_do_9_2_shutdown_ack(ep, asoc, type,
arg, commands); arg, commands);
} }
...@@ -1732,6 +1696,42 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep, ...@@ -1732,6 +1696,42 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep,
return disposition; return disposition;
} }
/* RFC 2960 9.2
* If an endpoint is in SHUTDOWN-ACK-SENT state and receives an INIT chunk
* (e.g., if the SHUTDOWN COMPLETE was lost) with source and destination
* transport addresses (either in the IP addresses or in the INIT chunk)
* that belong to this association, it should discard the INIT chunk and
* retransmit the SHUTDOWN ACK chunk.
*/
sctp_disposition_t sctp_sf_do_9_2_reshutack(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *chunk = (sctp_chunk_t *) arg;
sctp_chunk_t *reply;
reply = sctp_make_shutdown_ack(asoc, chunk);
if (NULL == reply)
goto nomem;
/* Set the transport for the SHUTDOWN ACK chunk and the timeout for
* the T2-SHUTDOWN timer.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_SETUP_T2, SCTP_CHUNK(reply));
/* and restart the T2-shutdown timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
return SCTP_DISPOSITION_CONSUME;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/* /*
* sctp_sf_do_ecn_cwr * sctp_sf_do_ecn_cwr
* *
...@@ -1979,9 +1979,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, ...@@ -1979,9 +1979,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
* processing the rest of the chunks in the packet. * processing the rest of the chunks in the packet.
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
...@@ -2185,9 +2183,7 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep, ...@@ -2185,9 +2183,7 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
* processing the rest of the chunks in the packet. * processing the rest of the chunks in the packet.
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
SCTP_STATE(SCTP_STATE_CLOSED));
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
...@@ -2296,14 +2292,12 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep, ...@@ -2296,14 +2292,12 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep,
*/ */
if (TSN_lt(ctsn, asoc->ctsn_ack_point)) { if (TSN_lt(ctsn, asoc->ctsn_ack_point)) {
SCTP_DEBUG_PRINTK("ctsn %x\n", ctsn); SCTP_DEBUG_PRINTK("ctsn %x\n", ctsn);
SCTP_DEBUG_PRINTK("ctsn_ack_point %x\n", SCTP_DEBUG_PRINTK("ctsn_ack_point %x\n", asoc->ctsn_ack_point);
asoc->ctsn_ack_point);
return SCTP_DISPOSITION_DISCARD; return SCTP_DISPOSITION_DISCARD;
} }
/* Return this SACK for further processing. */ /* Return this SACK for further processing. */
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, SCTP_SACKH(sackh));
SCTP_SACKH(sackh));
/* Note: We do the rest of the work on the PROCESS_SACK /* Note: We do the rest of the work on the PROCESS_SACK
* sideeffect. * sideeffect.
...@@ -2410,7 +2404,8 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep, ...@@ -2410,7 +2404,8 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
sctp_ulpevent_t *ev; sctp_ulpevent_t *ev;
while (chunk->chunk_end > chunk->skb->data) { while (chunk->chunk_end > chunk->skb->data) {
ev = sctp_ulpevent_make_remote_error(asoc,chunk,0, GFP_ATOMIC); ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
GFP_ATOMIC);
if (!ev) if (!ev)
goto nomem; goto nomem;
...@@ -2464,6 +2459,9 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep, ...@@ -2464,6 +2459,9 @@ sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN)); SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
/* ...send a SHUTDOWN COMPLETE chunk to its peer, */ /* ...send a SHUTDOWN COMPLETE chunk to its peer, */
reply = sctp_make_shutdown_complete(asoc, chunk); reply = sctp_make_shutdown_complete(asoc, chunk);
if (!reply) if (!reply)
...@@ -2616,6 +2614,148 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, ...@@ -2616,6 +2614,148 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
nomem: nomem:
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
} }
/*
* Process an unknown chunk.
*
* Section: 3.2. Also, 2.1 in the implementor's guide.
*
* Chunk Types are encoded such that the highest-order two bits specify
* the action that must be taken if the processing endpoint does not
* recognize the Chunk Type.
*
* 00 - Stop processing this SCTP packet and discard it, do not process
* any further chunks within it.
*
* 01 - Stop processing this SCTP packet and discard it, do not process
* any further chunks within it, and report the unrecognized
* chunk in an 'Unrecognized Chunk Type'.
*
* 10 - Skip this chunk and continue processing.
*
* 11 - Skip this chunk and continue processing, but report in an ERROR
* Chunk using the 'Unrecognized Chunk Type' cause of error.
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_unk_chunk(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *unk_chunk = arg;
sctp_chunk_t *err_chunk;
sctp_chunkhdr_t *hdr;
SCTP_DEBUG_PRINTK("Processing the unknown chunk id %d.\n", type.chunk);
/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
* that the value in the Verification Tag field of the
* received SCTP packet matches its own Tag. If the received
* Verification Tag value does not match the receiver's own
* tag value, the receiver shall silently discard the packet.
*/
if (ntohl(unk_chunk->sctp_hdr->vtag) != asoc->c.my_vtag)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
switch (type.chunk & SCTP_CID_ACTION_MASK) {
case SCTP_CID_ACTION_DISCARD:
/* Discard the packet. */
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
break;
case SCTP_CID_ACTION_DISCARD_ERR:
/* Discard the packet. */
sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Generate an ERROR chunk as response. */
hdr = unk_chunk->chunk_hdr;
err_chunk = sctp_make_op_error(asoc, unk_chunk,
SCTP_ERROR_UNKNOWN_CHUNK, hdr,
WORD_ROUND(ntohs(hdr->length)));
if (err_chunk) {
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(err_chunk));
}
return SCTP_DISPOSITION_CONSUME;
break;
case SCTP_CID_ACTION_SKIP:
/* Skip the chunk. */
return SCTP_DISPOSITION_DISCARD;
break;
case SCTP_CID_ACTION_SKIP_ERR:
/* Generate an ERROR chunk as response. */
hdr = unk_chunk->chunk_hdr;
err_chunk = sctp_make_op_error(asoc, unk_chunk,
SCTP_ERROR_UNKNOWN_CHUNK, hdr,
WORD_ROUND(ntohs(hdr->length)));
if (err_chunk) {
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
SCTP_CHUNK(err_chunk));
}
/* Skip the chunk. */
return SCTP_DISPOSITION_CONSUME;
break;
default:
break;
}
return SCTP_DISPOSITION_DISCARD;
}
/*
* Discard the chunk.
*
* Section: 0.2, 5.2.3, 5.2.5, 5.2.6, 6.0, 8.4.6, 8.5.1c, 9.2
* [Too numerous to mention...]
* Verification Tag: No verification needed.
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk);
return SCTP_DISPOSITION_DISCARD;
}
/*
* Discard the whole packet.
*
* Section: 8.4 2)
*
* 2) If the OOTB packet contains an ABORT chunk, the receiver MUST
* silently discard the OOTB packet and take no further action.
* Otherwise,
*
* Verification Tag: No verification necessary
*
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t
sctp_sf_pdiscard(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
return SCTP_DISPOSITION_CONSUME;
}
#if 0 #if 0
/* /*
...@@ -2976,10 +3116,16 @@ sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep, ...@@ -2976,10 +3116,16 @@ sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING)); SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING));
/* sctpimpguide-05 Section 2.12.2
* The sender of the SHUTDOWN MAY also start an overall guard timer
* 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
disposition = SCTP_DISPOSITION_CONSUME; disposition = SCTP_DISPOSITION_CONSUME;
if (sctp_outqueue_is_empty(&asoc->outqueue)) { if (sctp_outqueue_is_empty(&asoc->outqueue)) {
disposition = disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
arg, commands); arg, commands);
} }
return disposition; return disposition;
...@@ -3042,12 +3188,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep, ...@@ -3042,12 +3188,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
* TCB. This is a departure from our typical NOMEM handling. * TCB. This is a departure from our typical NOMEM handling.
*/ */
/* Change to CLOSED state. */
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
/* Delete the established association. */ /* Delete the established association. */
sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
return retval; return retval;
} }
...@@ -3090,7 +3232,8 @@ sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep, ...@@ -3090,7 +3232,8 @@ sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep,
* Outputs * Outputs
* (timers) * (timers)
*/ */
sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(const sctp_endpoint_t *ep, sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc, const sctp_association_t *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
...@@ -3134,7 +3277,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown( ...@@ -3134,7 +3277,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown(
} }
/* /*
* sctp_cookie_wait_prm_abort * sctp_sf_cookie_wait_prm_abort
* *
* Section: 4 Note: 2 * Section: 4 Note: 2
* Verification Tag: * Verification Tag:
...@@ -3153,14 +3296,36 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep, ...@@ -3153,14 +3296,36 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_chunk_t *abort;
sctp_disposition_t retval;
/* Stop T1-init timer */ /* Stop T1-init timer */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
return sctp_sf_do_9_1_prm_abort(ep, asoc, type, arg, commands); retval = SCTP_DISPOSITION_CONSUME;
/* Generate ABORT chunk to send the peer */
abort = sctp_make_abort(asoc, NULL, 0);
if (!abort)
retval = SCTP_DISPOSITION_NOMEM;
else
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
/* Even if we can't send the ABORT due to low memory delete the
* TCB. This is a departure from our typical NOMEM handling.
*/
/* Delete the established association. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
return retval;
} }
/* /*
* sctp_cookie_echoed_prm_abort * sctp_sf_cookie_echoed_prm_abort
* *
* Section: 4 Note: 3 * Section: 4 Note: 3
* Verification Tag: * Verification Tag:
...@@ -3185,6 +3350,87 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep, ...@@ -3185,6 +3350,87 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep,
return sctp_sf_cookie_wait_prm_abort(ep, asoc, type, arg, commands); return sctp_sf_cookie_wait_prm_abort(ep, asoc, type, arg, commands);
} }
/*
* sctp_sf_shutdown_pending_prm_abort
*
* Inputs
* (endpoint, asoc)
*
* The RFC does not explicitly address this issue, but is the route through the
* state table when someone issues an abort while in SHUTDOWN-PENDING state.
*
* Outputs
* (timers)
*/
sctp_disposition_t sctp_sf_shutdown_pending_prm_abort(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* Stop the T5-shutdown guard timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
return sctp_sf_do_9_1_prm_abort(ep, asoc, type, arg, commands);
}
/*
* sctp_sf_shutdown_sent_prm_abort
*
* Inputs
* (endpoint, asoc)
*
* The RFC does not explicitly address this issue, but is the route through the
* state table when someone issues an abort while in SHUTDOWN-SENT state.
*
* Outputs
* (timers)
*/
sctp_disposition_t sctp_sf_shutdown_sent_prm_abort(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* Stop the T2-shutdown timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
/* Stop the T5-shutdown guard timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
return sctp_sf_do_9_1_prm_abort(ep, asoc, type, arg, commands);
}
/*
* sctp_sf_cookie_echoed_prm_abort
*
* Inputs
* (endpoint, asoc)
*
* The RFC does not explcitly address this issue, but is the route through the
* state table when someone issues an abort while in COOKIE_ECHOED state.
*
* Outputs
* (timers)
*/
sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
/* The same T2 timer, so we should be able to use
* common function with the SHUTDOWN-SENT state.
*/
return sctp_sf_shutdown_sent_prm_abort(ep, asoc, type, arg, commands);
}
/* /*
* Ignore the primitive event * Ignore the primitive event
* *
...@@ -3322,8 +3568,7 @@ sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep, ...@@ -3322,8 +3568,7 @@ sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
SCTP_DEBUG_PRINTK("The event other type %d is ignored\n", SCTP_DEBUG_PRINTK("The event other type %d is ignored\n", type.other);
type.other);
return SCTP_DISPOSITION_DISCARD; return SCTP_DISPOSITION_DISCARD;
} }
...@@ -3479,11 +3724,11 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep, ...@@ -3479,11 +3724,11 @@ sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep,
if (!repl) if (!repl)
goto nomem; goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
/* Issue a sideeffect to do the needed accounting. */ /* Issue a sideeffect to do the needed accounting. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_RESTART, sctp_add_cmd_sf(commands, SCTP_CMD_INIT_RESTART,
SCTP_TO(timer)); SCTP_TO(timer));
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
} else { } else {
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB; return SCTP_DISPOSITION_DELETE_TCB;
...@@ -3559,6 +3804,34 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep, ...@@ -3559,6 +3804,34 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep,
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
} }
/* sctpimpguide-05 Section 2.12.2
* The sender of the SHUTDOWN MAY also start an overall guard timer
* 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
* At the expiration of this timer the sender SHOULD abort the association
* by sending an ABORT chunk.
*/
sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_chunk_t *reply = NULL;
SCTP_DEBUG_PRINTK("Timer T5 expired.\n");
reply = sctp_make_abort(asoc, NULL, 0);
if (!reply)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
return SCTP_DISPOSITION_DELETE_TCB;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/* Handle expiration of AUTOCLOSE timer. When the autoclose timer expires, /* Handle expiration of AUTOCLOSE timer. When the autoclose timer expires,
* the association is automatically closed by starting the shutdown process. * the association is automatically closed by starting the shutdown process.
* The work that needs to be done is same as when SHUTDOWN is initiated by * The work that needs to be done is same as when SHUTDOWN is initiated by
...@@ -3583,10 +3856,15 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep, ...@@ -3583,10 +3856,15 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep,
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING)); SCTP_STATE(SCTP_STATE_SHUTDOWN_PENDING));
/* sctpimpguide-05 Section 2.12.2
* The sender of the SHUTDOWN MAY also start an overall guard timer
* 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
disposition = SCTP_DISPOSITION_CONSUME; disposition = SCTP_DISPOSITION_CONSUME;
if (sctp_outqueue_is_empty(&asoc->outqueue)) { if (sctp_outqueue_is_empty(&asoc->outqueue)) {
disposition = disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
arg, commands); arg, commands);
} }
return disposition; return disposition;
...@@ -3651,30 +3929,6 @@ sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep, ...@@ -3651,30 +3929,6 @@ sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep,
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
/*
* Discard the chunk.
*
* Section: 0.2, 5.2.3, 5.2.5, 5.2.6, 6.0, 8.4.6, 8.5.1c, 9.2
* [Too numerous to mention...]
* Verification Tag: No verification needed.
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (asoc, reply_msg, msg_up, timers, counters)
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk);
return SCTP_DISPOSITION_DISCARD;
}
/******************************************************************** /********************************************************************
* 2nd Level Abstractions * 2nd Level Abstractions
********************************************************************/ ********************************************************************/
......
...@@ -48,9 +48,10 @@ ...@@ -48,9 +48,10 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
sctp_sm_table_entry_t nop = {fn: sctp_sf_discard_chunk, sctp_sm_table_entry_t bug = {
name: "sctp_sf_discard_chunk"}; .fn = sctp_sf_bug,
sctp_sm_table_entry_t bug = {fn: sctp_sf_bug, name: "sctp_sf_bug"}; .name = "sctp_sf_bug"
};
#define DO_LOOKUP(_max, _type, _table) \ #define DO_LOOKUP(_max, _type, _table) \
if ((event_subtype._type > (_max))) { \ if ((event_subtype._type > (_max))) { \
...@@ -58,9 +59,9 @@ sctp_sm_table_entry_t bug = {fn: sctp_sf_bug, name: "sctp_sf_bug"}; ...@@ -58,9 +59,9 @@ sctp_sm_table_entry_t bug = {fn: sctp_sf_bug, name: "sctp_sf_bug"};
"sctp table %p possible attack:" \ "sctp table %p possible attack:" \
" event %d exceeds max %d\n", \ " event %d exceeds max %d\n", \
_table, event_subtype._type, _max); \ _table, event_subtype._type, _max); \
return(&bug); \ return &bug; \
} \ } \
return(&_table[event_subtype._type][(int)state]); return &_table[event_subtype._type][(int)state];
sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
sctp_state_t state, sctp_state_t state,
...@@ -92,320 +93,323 @@ sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, ...@@ -92,320 +93,323 @@ sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
#define TYPE_SCTP_DATA { \ #define TYPE_SCTP_DATA { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ {.fn = sctp_sf_tabort_8_4_8, .name = "sctp_sf_tabort_8_4_8"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_eat_data_6_2, name: "sctp_sf_eat_data_6_2"}, \ {.fn = sctp_sf_eat_data_6_2, .name = "sctp_sf_eat_data_6_2"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_eat_data_6_2, name: "sctp_sf_eat_data_6_2"}, \ {.fn = sctp_sf_eat_data_6_2, .name = "sctp_sf_eat_data_6_2"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_eat_data_fast_4_4, name: "sctp_sf_eat_data_fast_4_4"}, \ {.fn = sctp_sf_eat_data_fast_4_4, .name = "sctp_sf_eat_data_fast_4_4"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
} /* TYPE_SCTP_DATA */ } /* TYPE_SCTP_DATA */
#define TYPE_SCTP_INIT { \ #define TYPE_SCTP_INIT { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_do_5_1B_init, name: "sctp_sf_do_5_1B_init"}, \ {.fn = sctp_sf_do_5_1B_init, .name = "sctp_sf_do_5_1B_init"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_do_5_2_1_siminit, name: "sctp_sf_do_5_2_1_siminit"}, \ {.fn = sctp_sf_do_5_2_1_siminit, .name = "sctp_sf_do_5_2_1_siminit"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_do_5_2_1_siminit, name: "sctp_sf_do_5_2_1_siminit"}, \ {.fn = sctp_sf_do_5_2_1_siminit, .name = "sctp_sf_do_5_2_1_siminit"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ {.fn = sctp_sf_do_5_2_2_dupinit, .name = "sctp_sf_do_5_2_2_dupinit"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ {.fn = sctp_sf_do_5_2_2_dupinit, .name = "sctp_sf_do_5_2_2_dupinit"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ {.fn = sctp_sf_do_5_2_2_dupinit, .name = "sctp_sf_do_5_2_2_dupinit"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_do_5_2_2_dupinit, name: "sctp_sf_do_5_2_2_dupinit"}, \ {.fn = sctp_sf_do_5_2_2_dupinit, .name = "sctp_sf_do_5_2_2_dupinit"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_do_9_2_reshutack, .name = "sctp_sf_do_9_2_reshutack"}, \
} /* TYPE_SCTP_INIT */ } /* TYPE_SCTP_INIT */
#define TYPE_SCTP_INIT_ACK { \ #define TYPE_SCTP_INIT_ACK { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_do_5_1C_ack, name: "sctp_sf_do_5_1C_ack"}, \ {.fn = sctp_sf_do_5_1C_ack, .name = "sctp_sf_do_5_1C_ack"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
} /* TYPE_SCTP_INIT_ACK */ } /* TYPE_SCTP_INIT_ACK */
#define TYPE_SCTP_SACK { \ #define TYPE_SCTP_SACK { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ {.fn = sctp_sf_tabort_8_4_8, .name = "sctp_sf_tabort_8_4_8"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ {.fn = sctp_sf_eat_sack_6_2, .name = "sctp_sf_eat_sack_6_2"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ {.fn = sctp_sf_eat_sack_6_2, .name = "sctp_sf_eat_sack_6_2"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ {.fn = sctp_sf_eat_sack_6_2, .name = "sctp_sf_eat_sack_6_2"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_eat_sack_6_2, name: "sctp_sf_eat_sack_6_2"}, \ {.fn = sctp_sf_eat_sack_6_2, .name = "sctp_sf_eat_sack_6_2"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
} /* TYPE_SCTP_SACK */ } /* TYPE_SCTP_SACK */
#define TYPE_SCTP_HEARTBEAT { \ #define TYPE_SCTP_HEARTBEAT { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ {.fn = sctp_sf_tabort_8_4_8, .name = "sctp_sf_tabort_8_4_8"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ {.fn = sctp_sf_beat_8_3, .name = "sctp_sf_beat_8_3"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ {.fn = sctp_sf_beat_8_3, .name = "sctp_sf_beat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ {.fn = sctp_sf_beat_8_3, .name = "sctp_sf_beat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ {.fn = sctp_sf_beat_8_3, .name = "sctp_sf_beat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ {.fn = sctp_sf_beat_8_3, .name = "sctp_sf_beat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
/* This should not happen, but we are nice. */ \ /* This should not happen, but we are nice. */ \
{fn: sctp_sf_beat_8_3, name: "sctp_sf_beat_8_3"}, \ {.fn = sctp_sf_beat_8_3, .name = "sctp_sf_beat_8_3"}, \
} /* TYPE_SCTP_HEARTBEAT */ } /* TYPE_SCTP_HEARTBEAT */
#define TYPE_SCTP_HEARTBEAT_ACK { \ #define TYPE_SCTP_HEARTBEAT_ACK { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ {.fn = sctp_sf_tabort_8_4_8, .name = "sctp_sf_tabort_8_4_8"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ {.fn = sctp_sf_violation, .name = "sctp_sf_violation"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ {.fn = sctp_sf_backbeat_8_3, .name = "sctp_sf_backbeat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ {.fn = sctp_sf_backbeat_8_3, .name = "sctp_sf_backbeat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ {.fn = sctp_sf_backbeat_8_3, .name = "sctp_sf_backbeat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_backbeat_8_3, name: "sctp_sf_backbeat_8_3"}, \ {.fn = sctp_sf_backbeat_8_3, .name = "sctp_sf_backbeat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_HEARTBEAT_ACK */ } /* TYPE_SCTP_HEARTBEAT_ACK */
#define TYPE_SCTP_ABORT { \ #define TYPE_SCTP_ABORT { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_pdiscard, name: "sctp_sf_pdiscard"}, \ {.fn = sctp_sf_pdiscard, .name = "sctp_sf_pdiscard"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_cookie_wait_abort, name: "sctp_sf_cookie_wait_abort"}, \ {.fn = sctp_sf_cookie_wait_abort, .name = "sctp_sf_cookie_wait_abort"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_cookie_echoed_abort, \ {.fn = sctp_sf_cookie_echoed_abort, \
name: "sctp_sf_cookie_echoed_abort"}, \ .name = "sctp_sf_cookie_echoed_abort"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ {.fn = sctp_sf_do_9_1_abort, .name = "sctp_sf_do_9_1_abort"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ {.fn = sctp_sf_shutdown_pending_abort, \
.name = "sctp_sf_shutdown_pending_abort"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ {.fn = sctp_sf_shutdown_sent_abort, \
.name = "sctp_sf_shutdown_sent_abort"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ {.fn = sctp_sf_do_9_1_abort, .name = "sctp_sf_do_9_1_abort"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_do_9_1_abort, name: "sctp_sf_do_9_1_abort"}, \ {.fn = sctp_sf_shutdown_ack_sent_abort, \
.name = "sctp_sf_shutdown_ack_sent_abort"}, \
} /* TYPE_SCTP_ABORT */ } /* TYPE_SCTP_ABORT */
#define TYPE_SCTP_SHUTDOWN { \ #define TYPE_SCTP_SHUTDOWN { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ {.fn = sctp_sf_tabort_8_4_8, .name = "sctp_sf_tabort_8_4_8"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_9_2_shutdown, name: "sctp_sf_do_9_2_shutdown"}, \ {.fn = sctp_sf_do_9_2_shutdown, .name = "sctp_sf_do_9_2_shutdown"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_do_9_2_shutdown_ack, \ {.fn = sctp_sf_do_9_2_shutdown_ack, \
name: "sctp_sf_do_9_2_shutdown_ack"}, \ .name = "sctp_sf_do_9_2_shutdown_ack"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
} /* TYPE_SCTP_SHUTDOWN */ } /* TYPE_SCTP_SHUTDOWN */
#define TYPE_SCTP_SHUTDOWN_ACK { \ #define TYPE_SCTP_SHUTDOWN_ACK { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ {.fn = sctp_sf_violation, .name = "sctp_sf_violation"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ {.fn = sctp_sf_violation, .name = "sctp_sf_violation"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_do_9_2_final, name: "sctp_sf_do_9_2_final"}, \ {.fn = sctp_sf_do_9_2_final, .name = "sctp_sf_do_9_2_final"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_violation, name: "sctp_sf_violation"}, \ {.fn = sctp_sf_violation, .name = "sctp_sf_violation"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_do_9_2_final, name: "sctp_sf_do_9_2_final"}, \ {.fn = sctp_sf_do_9_2_final, .name = "sctp_sf_do_9_2_final"}, \
} /* TYPE_SCTP_SHUTDOWN_ACK */ } /* TYPE_SCTP_SHUTDOWN_ACK */
#define TYPE_SCTP_ERROR { \ #define TYPE_SCTP_ERROR { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_tabort_8_4_8, name: "sctp_sf_tabort_8_4_8"}, \ {.fn = sctp_sf_tabort_8_4_8, .name = "sctp_sf_tabort_8_4_8"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_operr_notify, name: "sctp_sf_operr_notify"}, \ {.fn = sctp_sf_operr_notify, .name = "sctp_sf_operr_notify"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_ERROR */ } /* TYPE_SCTP_ERROR */
#define TYPE_SCTP_COOKIE_ECHO { \ #define TYPE_SCTP_COOKIE_ECHO { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_do_5_1D_ce, name: "sctp_sf_do_5_1D_ce"}, \ {.fn = sctp_sf_do_5_1D_ce, .name = "sctp_sf_do_5_1D_ce"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ {.fn = sctp_sf_do_5_2_4_dupcook, .name = "sctp_sf_do_5_2_4_dupcook"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ {.fn = sctp_sf_do_5_2_4_dupcook, .name = "sctp_sf_do_5_2_4_dupcook"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ {.fn = sctp_sf_do_5_2_4_dupcook, .name = "sctp_sf_do_5_2_4_dupcook"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ {.fn = sctp_sf_do_5_2_4_dupcook, .name = "sctp_sf_do_5_2_4_dupcook"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ {.fn = sctp_sf_do_5_2_4_dupcook, .name = "sctp_sf_do_5_2_4_dupcook"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ {.fn = sctp_sf_do_5_2_4_dupcook, .name = "sctp_sf_do_5_2_4_dupcook"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_do_5_2_4_dupcook, name: "sctp_sf_do_5_2_4_dupcook"}, \ {.fn = sctp_sf_do_5_2_4_dupcook, .name = "sctp_sf_do_5_2_4_dupcook"}, \
} /* TYPE_SCTP_COOKIE_ECHO */ } /* TYPE_SCTP_COOKIE_ECHO */
#define TYPE_SCTP_COOKIE_ACK { \ #define TYPE_SCTP_COOKIE_ACK { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_do_5_1E_ca, name: "sctp_sf_do_5_1E_ca"}, \ {.fn = sctp_sf_do_5_1E_ca, .name = "sctp_sf_do_5_1E_ca"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
} /* TYPE_SCTP_COOKIE_ACK */ } /* TYPE_SCTP_COOKIE_ACK */
#define TYPE_SCTP_ECN_ECNE { \ #define TYPE_SCTP_ECN_ECNE { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_do_ecne, name: "sctp_sf_do_ecne"}, \ {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
} /* TYPE_SCTP_ECN_ECNE */ } /* TYPE_SCTP_ECN_ECNE */
#define TYPE_SCTP_ECN_CWR { \ #define TYPE_SCTP_ECN_CWR { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ {.fn = sctp_sf_do_ecn_cwr, .name = "sctp_sf_do_ecn_cwr"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ {.fn = sctp_sf_do_ecn_cwr, .name = "sctp_sf_do_ecn_cwr"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_do_ecn_cwr, name: "sctp_sf_do_ecn_cwr"}, \ {.fn = sctp_sf_do_ecn_cwr, .name = "sctp_sf_do_ecn_cwr"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
} /* TYPE_SCTP_ECN_CWR */ } /* TYPE_SCTP_ECN_CWR */
#define TYPE_SCTP_SHUTDOWN_COMPLETE { \ #define TYPE_SCTP_SHUTDOWN_COMPLETE { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_ootb, name: "sctp_sf_ootb"}, \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_do_4_C, name: "sctp_sf_do_4_C"}, \ {.fn = sctp_sf_do_4_C, .name = "sctp_sf_do_4_C"}, \
} /* TYPE_SCTP_SHUTDOWN_COMPLETE */ } /* TYPE_SCTP_SHUTDOWN_COMPLETE */
/* The primary index for this table is the chunk type. /* The primary index for this table is the chunk type.
...@@ -434,397 +438,415 @@ sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NU ...@@ -434,397 +438,415 @@ sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NU
static sctp_sm_table_entry_t static sctp_sm_table_entry_t
chunk_event_table_asconf[SCTP_STATE_NUM_STATES] = { chunk_event_table_asconf[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */ /* SCTP_STATE_EMPTY */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_CLOSED */ /* SCTP_STATE_CLOSED */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_COOKIE_WAIT */ /* SCTP_STATE_COOKIE_WAIT */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_COOKIE_ECHOED */ /* SCTP_STATE_COOKIE_ECHOED */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_ESTABLISHED */ /* SCTP_STATE_ESTABLISHED */
{fn: sctp_sf_discard_chunk, {.fn = sctp_sf_discard_chunk,
name: "sctp_sf_discard_chunk (will be sctp_addip_do_asconf)"}, .name = "sctp_sf_discard_chunk (will be sctp_addip_do_asconf)"},
/* SCTP_STATE_SHUTDOWN_PENDING */ /* SCTP_STATE_SHUTDOWN_PENDING */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_SENT */ /* SCTP_STATE_SHUTDOWN_SENT */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_RECEIVED */ /* SCTP_STATE_SHUTDOWN_RECEIVED */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ /* SCTP_STATE_SHUTDOWN_ACK_SENT */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
}; /* chunk asconf */ }; /* chunk asconf */
static sctp_sm_table_entry_t static sctp_sm_table_entry_t
chunk_event_table_asconf_ack[SCTP_STATE_NUM_STATES] = { chunk_event_table_asconf_ack[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */ /* SCTP_STATE_EMPTY */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_CLOSED */ /* SCTP_STATE_CLOSED */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_COOKIE_WAIT */ /* SCTP_STATE_COOKIE_WAIT */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_COOKIE_ECHOED */ /* SCTP_STATE_COOKIE_ECHOED */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_ESTABLISHED */ /* SCTP_STATE_ESTABLISHED */
{fn: sctp_sf_discard_chunk, {.fn = sctp_sf_discard_chunk,
name: "sctp_sf_discard_chunk (will be sctp_addip_do_asconf_ack)"}, .name = "sctp_sf_discard_chunk (will be sctp_addip_do_asconf_ack)"},
/* SCTP_STATE_SHUTDOWN_PENDING */ /* SCTP_STATE_SHUTDOWN_PENDING */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_SENT */ /* SCTP_STATE_SHUTDOWN_SENT */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_RECEIVED */ /* SCTP_STATE_SHUTDOWN_RECEIVED */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ /* SCTP_STATE_SHUTDOWN_ACK_SENT */
{fn: sctp_sf_discard_chunk, name: "sctp_sf_discard_chunk"}, {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
}; /* chunk asconf_ack */ }; /* chunk asconf_ack */
static sctp_sm_table_entry_t
chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */
{.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"},
/* SCTP_STATE_CLOSED */
{.fn = sctp_sf_tabort_8_4_8, .name = "sctp_sf_tabort_8_4_8"},
/* SCTP_STATE_COOKIE_WAIT */
{.fn = sctp_sf_unk_chunk, .name = "sctp_sf_unk_chunk"},
/* SCTP_STATE_COOKIE_ECHOED */
{.fn = sctp_sf_unk_chunk, .name = "sctp_sf_unk_chunk"},
/* SCTP_STATE_ESTABLISHED */
{.fn = sctp_sf_unk_chunk, .name = "sctp_sf_unk_chunk"},
/* SCTP_STATE_SHUTDOWN_PENDING */
{.fn = sctp_sf_unk_chunk, .name = "sctp_sf_unk_chunk"},
/* SCTP_STATE_SHUTDOWN_SENT */
{.fn = sctp_sf_unk_chunk, .name = "sctp_sf_unk_chunk"},
/* SCTP_STATE_SHUTDOWN_RECEIVED */
{.fn = sctp_sf_unk_chunk, .name = "sctp_sf_unk_chunk"},
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
{.fn = sctp_sf_unk_chunk, .name = "sctp_sf_unk_chunk"},
}; /* chunk unknown */
#define TYPE_SCTP_PRIMITIVE_INITIALIZE { \ #define TYPE_SCTP_PRIMITIVE_INITIALIZE { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_INITIALIZE */ } /* TYPE_SCTP_PRIMITIVE_INITIALIZE */
#define TYPE_SCTP_PRIMITIVE_ASSOCIATE { \ #define TYPE_SCTP_PRIMITIVE_ASSOCIATE { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_do_prm_asoc, name: "sctp_sf_do_prm_asoc"}, \ {.fn = sctp_sf_do_prm_asoc, .name = "sctp_sf_do_prm_asoc"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_ASSOCIATE */ } /* TYPE_SCTP_PRIMITIVE_ASSOCIATE */
#define TYPE_SCTP_PRIMITIVE_SHUTDOWN { \ #define TYPE_SCTP_PRIMITIVE_SHUTDOWN { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ {.fn = sctp_sf_error_closed, .name = "sctp_sf_error_closed"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_cookie_wait_prm_shutdown, \ {.fn = sctp_sf_cookie_wait_prm_shutdown, \
name: "sctp_sf_cookie_wait_prm_shutdown"}, \ .name = "sctp_sf_cookie_wait_prm_shutdown"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_cookie_echoed_prm_shutdown, \ {.fn = sctp_sf_cookie_echoed_prm_shutdown, \
name:"sctp_sf_cookie_echoed_prm_shutdown"},\ name:"sctp_sf_cookie_echoed_prm_shutdown"},\
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_9_2_prm_shutdown, \ {.fn = sctp_sf_do_9_2_prm_shutdown, \
name: "sctp_sf_do_9_2_prm_shutdown"}, \ .name = "sctp_sf_do_9_2_prm_shutdown"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ {.fn = sctp_sf_ignore_primitive, .name = "sctp_sf_ignore_primitive"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ {.fn = sctp_sf_ignore_primitive, .name = "sctp_sf_ignore_primitive"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ {.fn = sctp_sf_ignore_primitive, .name = "sctp_sf_ignore_primitive"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_ignore_primitive, name: "sctp_sf_ignore_primitive"}, \ {.fn = sctp_sf_ignore_primitive, .name = "sctp_sf_ignore_primitive"}, \
} /* TYPE_SCTP_PRIMITIVE_SHUTDOWN */ } /* TYPE_SCTP_PRIMITIVE_SHUTDOWN */
#define TYPE_SCTP_PRIMITIVE_ABORT { \ #define TYPE_SCTP_PRIMITIVE_ABORT { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ {.fn = sctp_sf_error_closed, .name = "sctp_sf_error_closed"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_cookie_wait_prm_abort, \ {.fn = sctp_sf_cookie_wait_prm_abort, \
name: "sctp_sf_cookie_wait_prm_abort"}, \ .name = "sctp_sf_cookie_wait_prm_abort"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_cookie_echoed_prm_abort, \ {.fn = sctp_sf_cookie_echoed_prm_abort, \
name: "sctp_sf_cookie_echoed_prm_abort"}, \ .name = "sctp_sf_cookie_echoed_prm_abort"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_9_1_prm_abort, \ {.fn = sctp_sf_do_9_1_prm_abort, \
name: "sctp_sf_do_9_1_prm_abort"}, \ .name = "sctp_sf_do_9_1_prm_abort"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_do_9_1_prm_abort, \ {.fn = sctp_sf_shutdown_pending_prm_abort, \
name: "sctp_sf_do_9_1_prm_abort"}, \ .name = "sctp_sf_shutdown_pending_prm_abort"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_do_9_1_prm_abort, \ {.fn = sctp_sf_shutdown_sent_prm_abort, \
name: "sctp_sf_do_9_1_prm_abort"}, \ .name = "sctp_sf_shutdown_sent_prm_abort"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_do_9_1_prm_abort, \ {.fn = sctp_sf_do_9_1_prm_abort, \
name: "sctp_sf_do_9_1_prm_abort"}, \ .name = "sctp_sf_do_9_1_prm_abort"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_do_9_1_prm_abort, \ {.fn = sctp_sf_shutdown_ack_sent_prm_abort, \
name: "sctp_sf_do_9_1_prm_abort"}, \ .name = "sctp_sf_shutdown_ack_sent_prm_abort"}, \
} /* TYPE_SCTP_PRIMITIVE_ABORT */ } /* TYPE_SCTP_PRIMITIVE_ABORT */
#define TYPE_SCTP_PRIMITIVE_SEND { \ #define TYPE_SCTP_PRIMITIVE_SEND { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_error_closed, name: "sctp_sf_error_closed"}, \ {.fn = sctp_sf_error_closed, .name = "sctp_sf_error_closed"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ {.fn = sctp_sf_do_prm_send, .name = "sctp_sf_do_prm_send"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ {.fn = sctp_sf_do_prm_send, .name = "sctp_sf_do_prm_send"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_prm_send, name: "sctp_sf_do_prm_send"}, \ {.fn = sctp_sf_do_prm_send, .name = "sctp_sf_do_prm_send"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ {.fn = sctp_sf_error_shutdown, .name = "sctp_sf_error_shutdown"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ {.fn = sctp_sf_error_shutdown, .name = "sctp_sf_error_shutdown"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ {.fn = sctp_sf_error_shutdown, .name = "sctp_sf_error_shutdown"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_error_shutdown, name: "sctp_sf_error_shutdown"}, \ {.fn = sctp_sf_error_shutdown, .name = "sctp_sf_error_shutdown"}, \
} /* TYPE_SCTP_PRIMITIVE_SEND */ } /* TYPE_SCTP_PRIMITIVE_SEND */
#define TYPE_SCTP_PRIMITIVE_SETPRIMARY { \ #define TYPE_SCTP_PRIMITIVE_SETPRIMARY { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_SETPRIMARY */ } /* TYPE_SCTP_PRIMITIVE_SETPRIMARY */
#define TYPE_SCTP_PRIMITIVE_RECEIVE { \ #define TYPE_SCTP_PRIMITIVE_RECEIVE { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_RECEIVE */ } /* TYPE_SCTP_PRIMITIVE_RECEIVE */
#define TYPE_SCTP_PRIMITIVE_STATUS { \ #define TYPE_SCTP_PRIMITIVE_STATUS { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_STATUS */ } /* TYPE_SCTP_PRIMITIVE_STATUS */
#define TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT { \ #define TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT */ } /* TYPE_SCTP_PRIMITIVE_CHANGEHEARTBEAT */
#define TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT { \ #define TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */ } /* TYPE_SCTP_PRIMITIVE_REQUESTHEARTBEAT */
#define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \ #define TYPE_SCTP_PRIMITIVE_GETSRTTREPORT { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_GETSRTTREPORT */ } /* TYPE_SCTP_PRIMITIVE_GETSRTTREPORT */
#define TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD { \ #define TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD */ } /* TYPE_SCTP_PRIMITIVE_SETFAILURETHRESHOLD */
#define TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS { \ #define TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS */ } /* TYPE_SCTP_PRIMITIVE_SETPROTOPARAMETERS */
#define TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT { \ #define TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT */ } /* TYPE_SCTP_PRIMITIVE_RECEIVE_UNSENT */
#define TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED { \ #define TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED */ } /* TYPE_SCTP_PRIMITIVE_RECEIVE_UNACKED */
#define TYPE_SCTP_PRIMITIVE_DESTROY { \ #define TYPE_SCTP_PRIMITIVE_DESTROY { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} /* TYPE_SCTP_PRIMITIVE_DESTROY */ } /* TYPE_SCTP_PRIMITIVE_DESTROY */
/* The primary index for this table is the primitive type. /* The primary index for this table is the primitive type.
...@@ -851,46 +873,46 @@ sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE ...@@ -851,46 +873,46 @@ sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE
#define TYPE_SCTP_OTHER_NO_PENDING_TSN { \ #define TYPE_SCTP_OTHER_NO_PENDING_TSN { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ {.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ {.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ {.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ {.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_do_9_2_start_shutdown, \ {.fn = sctp_sf_do_9_2_start_shutdown, \
name: "sctp_do_9_2_start_shutdown"}, \ .name = "sctp_do_9_2_start_shutdown"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ {.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_do_9_2_shutdown_ack, \ {.fn = sctp_sf_do_9_2_shutdown_ack, \
name: "sctp_sf_do_9_2_shutdown_ack"}, \ .name = "sctp_sf_do_9_2_shutdown_ack"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_ignore_other, name: "sctp_sf_ignore_other"}, \ {.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
} }
#define TYPE_SCTP_OTHER_ICMP_UNREACHFRAG { \ #define TYPE_SCTP_OTHER_ICMP_UNREACHFRAG { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} }
sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = { sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = {
...@@ -900,213 +922,234 @@ sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STA ...@@ -900,213 +922,234 @@ sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STA
#define TYPE_SCTP_EVENT_TIMEOUT_NONE { \ #define TYPE_SCTP_EVENT_TIMEOUT_NONE { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
} }
#define TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE { \ #define TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_t1_timer_expire, name: "sctp_sf_t1_timer_expire"}, \ {.fn = sctp_sf_t1_timer_expire, .name = "sctp_sf_t1_timer_expire"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
} }
#define TYPE_SCTP_EVENT_TIMEOUT_T1_INIT { \ #define TYPE_SCTP_EVENT_TIMEOUT_T1_INIT { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_t1_timer_expire, name: "sctp_sf_t1_timer_expire"}, \ {.fn = sctp_sf_t1_timer_expire, .name = "sctp_sf_t1_timer_expire"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
} }
#define TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN { \ #define TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_t2_timer_expire, name: "sctp_sf_t2_timer_expire"}, \ {.fn = sctp_sf_t2_timer_expire, .name = "sctp_sf_t2_timer_expire"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_t2_timer_expire, name: "sctp_sf_t2_timer_expire"}, \ {.fn = sctp_sf_t2_timer_expire, .name = "sctp_sf_t2_timer_expire"}, \
} }
#define TYPE_SCTP_EVENT_TIMEOUT_T3_RTX { \ #define TYPE_SCTP_EVENT_TIMEOUT_T3_RTX { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ {.fn = sctp_sf_do_6_3_3_rtx, .name = "sctp_sf_do_6_3_3_rtx"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ {.fn = sctp_sf_do_6_3_3_rtx, .name = "sctp_sf_do_6_3_3_rtx"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ {.fn = sctp_sf_do_6_3_3_rtx, .name = "sctp_sf_do_6_3_3_rtx"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_do_6_3_3_rtx, name: "sctp_sf_do_6_3_3_rtx"}, \ {.fn = sctp_sf_do_6_3_3_rtx, .name = "sctp_sf_do_6_3_3_rtx"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
} }
#define TYPE_SCTP_EVENT_TIMEOUT_T4_RTO { \ #define TYPE_SCTP_EVENT_TIMEOUT_T4_RTO { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
}
#define TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD { \
/* SCTP_STATE_EMPTY */ \
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_WAIT */ \
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_ESTABLISHED */ \
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \
{.fn = sctp_sf_t5_timer_expire, .name = "sctp_sf_t5_timer_expire"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
} }
#define TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT { \ #define TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_sendbeat_8_3, name: "sctp_sf_sendbeat_8_3"}, \ {.fn = sctp_sf_sendbeat_8_3, .name = "sctp_sf_sendbeat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_sendbeat_8_3, name: "sctp_sf_sendbeat_8_3"}, \ {.fn = sctp_sf_sendbeat_8_3, .name = "sctp_sf_sendbeat_8_3"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} }
#define TYPE_SCTP_EVENT_TIMEOUT_SACK { \ #define TYPE_SCTP_EVENT_TIMEOUT_SACK { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ {.fn = sctp_sf_do_6_2_sack, .name = "sctp_sf_do_6_2_sack"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ {.fn = sctp_sf_do_6_2_sack, .name = "sctp_sf_do_6_2_sack"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_do_6_2_sack, name: "sctp_sf_do_6_2_sack"}, \ {.fn = sctp_sf_do_6_2_sack, .name = "sctp_sf_do_6_2_sack"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
} }
#define TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE { \ #define TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_autoclose_timer_expire, \ {.fn = sctp_sf_autoclose_timer_expire, \
name: "sctp_sf_autoclose_timer_expire"}, \ .name = "sctp_sf_autoclose_timer_expire"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_timer_ignore, name: "sctp_sf_timer_ignore"}, \ {.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
} }
#define TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE { \ #define TYPE_SCTP_EVENT_TIMEOUT_PMTU_RAISE { \
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
{fn: sctp_sf_bug, name: "sctp_sf_bug"}, \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_ESTABLISHED */ \ /* SCTP_STATE_ESTABLISHED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \ /* SCTP_STATE_SHUTDOWN_PENDING */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \ /* SCTP_STATE_SHUTDOWN_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{fn: sctp_sf_not_impl, name: "sctp_sf_not_impl"}, \ {.fn = sctp_sf_not_impl, .name = "sctp_sf_not_impl"}, \
} }
sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = { sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = {
...@@ -1116,6 +1159,7 @@ sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM ...@@ -1116,6 +1159,7 @@ sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM
TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, TYPE_SCTP_EVENT_TIMEOUT_T2_SHUTDOWN,
TYPE_SCTP_EVENT_TIMEOUT_T3_RTX, TYPE_SCTP_EVENT_TIMEOUT_T3_RTX,
TYPE_SCTP_EVENT_TIMEOUT_T4_RTO, TYPE_SCTP_EVENT_TIMEOUT_T4_RTO,
TYPE_SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD,
TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT, TYPE_SCTP_EVENT_TIMEOUT_HEARTBEAT,
TYPE_SCTP_EVENT_TIMEOUT_SACK, TYPE_SCTP_EVENT_TIMEOUT_SACK,
TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE, TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE,
...@@ -1125,12 +1169,11 @@ sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM ...@@ -1125,12 +1169,11 @@ sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM
sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t state) sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t state)
{ {
if (state > SCTP_STATE_MAX) if (state > SCTP_STATE_MAX)
BUG(); return &bug;
if (cid < 0)
return &nop;
if (cid <= SCTP_CID_BASE_MAX) if (cid >= 0 && cid <= SCTP_CID_BASE_MAX) {
return &chunk_event_table[cid][state]; return &chunk_event_table[cid][state];
}
switch (cid) { switch (cid) {
case SCTP_CID_ASCONF: case SCTP_CID_ASCONF:
...@@ -1139,8 +1182,6 @@ sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t stat ...@@ -1139,8 +1182,6 @@ sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t stat
case SCTP_CID_ASCONF_ACK: case SCTP_CID_ASCONF_ACK:
return &chunk_event_table_asconf_ack[state]; return &chunk_event_table_asconf_ack[state];
default: default:
return &nop; return &chunk_event_table_unknown[state];
}; }
return &nop;
} }
/* Copyright (c) 1999-2000 Cisco, Inc. /* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001-2002 Intel Corp.
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001-2002 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
...@@ -82,8 +82,6 @@ static void sctp_wfree(struct sk_buff *skb); ...@@ -82,8 +82,6 @@ static void sctp_wfree(struct sk_buff *skb);
static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p,
int msg_len); int msg_len);
static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p);
static inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname,
int *addr_len, struct sk_buff *skb);
static inline void sctp_sk_addr_set(struct sock *, static inline void sctp_sk_addr_set(struct sock *,
const sockaddr_storage_t *newaddr, const sockaddr_storage_t *newaddr,
sockaddr_storage_t *saveaddr); sockaddr_storage_t *saveaddr);
...@@ -326,8 +324,8 @@ static int __sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, ...@@ -326,8 +324,8 @@ static int __sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs,
SCTP_DEBUG_PRINTK("__sctp_bindx(sk: %p, addrs: %p, addrcnt: %d, " SCTP_DEBUG_PRINTK("__sctp_bindx(sk: %p, addrs: %p, addrcnt: %d, "
"flags: %s)\n", sk, addrs, addrcnt, "flags: %s)\n", sk, addrs, addrcnt,
(BINDX_ADD_ADDR == flags)?"ADD": (BINDX_ADD_ADDR == flags) ? "ADD" :
((BINDX_REM_ADDR == flags)?"REM":"BOGUS")); ((BINDX_REM_ADDR == flags) ? "REM" : "BOGUS"));
switch (flags) { switch (flags) {
case BINDX_ADD_ADDR: case BINDX_ADD_ADDR:
...@@ -500,9 +498,8 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -500,9 +498,8 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
case AF_INET: case AF_INET:
saveaddr = *((sockaddr_storage_t *) saveaddr = *((sockaddr_storage_t *)
&addrs[cnt]); &addrs[cnt]);
saveaddr.v4.sin_port = saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port);
ntohs(saveaddr.v4.sin_port); /* Verify the port. */
/* verify the port */
if (saveaddr.v4.sin_port != bp->port) { if (saveaddr.v4.sin_port != bp->port) {
retval = -EINVAL; retval = -EINVAL;
goto err_bindx_rem; goto err_bindx_rem;
...@@ -606,7 +603,8 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -606,7 +603,8 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
* *
* Returns 0 if ok, <0 errno code on error. * Returns 0 if ok, <0 errno code on error.
*/ */
static int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs, static int sctp_setsockopt_bindx(struct sock* sk,
struct sockaddr_storage *addrs,
int addrssize, int op) int addrssize, int op)
{ {
struct sockaddr_storage *kaddrs; struct sockaddr_storage *kaddrs;
...@@ -614,8 +612,7 @@ static int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs ...@@ -614,8 +612,7 @@ static int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs
size_t addrcnt; size_t addrcnt;
SCTP_DEBUG_PRINTK("sctp_do_setsocktopt_bindx: sk %p addrs %p" SCTP_DEBUG_PRINTK("sctp_do_setsocktopt_bindx: sk %p addrs %p"
" addrssize %d opt %d\n", sk, addrs, " addrssize %d opt %d\n", sk, addrs, addrssize, op);
addrssize, op);
/* Do we have an integer number of structs sockaddr_storage? */ /* Do we have an integer number of structs sockaddr_storage? */
if (unlikely(addrssize <= 0 || if (unlikely(addrssize <= 0 ||
...@@ -851,7 +848,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) ...@@ -851,7 +848,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
goto out_unlock; goto out_unlock;
} }
if (sinfo_flags & MSG_ABORT) { if (sinfo_flags & MSG_ABORT) {
SCTP_DEBUG_PRINTK("Aborting association: %p\n",asoc); SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc);
sctp_primitive_ABORT(asoc, NULL); sctp_primitive_ABORT(asoc, NULL);
err = 0; err = 0;
goto out_unlock; goto out_unlock;
...@@ -866,8 +863,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) ...@@ -866,8 +863,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
* either the default or the user specified stream counts. * either the default or the user specified stream counts.
*/ */
if (sinfo) { if (sinfo) {
if (!sinit || if (!sinit || (sinit && !sinit->sinit_num_ostreams)) {
(sinit && !sinit->sinit_num_ostreams)) {
/* Check against the defaults. */ /* Check against the defaults. */
if (sinfo->sinfo_stream >= if (sinfo->sinfo_stream >=
sp->initmsg.sinit_num_ostreams) { sp->initmsg.sinit_num_ostreams) {
...@@ -1096,12 +1092,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) ...@@ -1096,12 +1092,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
* flags - flags sent or received with the user message, see Section * flags - flags sent or received with the user message, see Section
* 5 for complete description of the flags. * 5 for complete description of the flags.
*/ */
static struct sk_buff * sctp_skb_recv_datagram(struct sock *, int, int, int *); static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
int noblock, int flags, int *addr_len) int noblock, int flags, int *addr_len)
{ {
sctp_ulpevent_t *event = NULL; sctp_ulpevent_t *event = NULL;
sctp_opt_t *sp = sctp_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
int copied; int copied;
int err = 0; int err = 0;
...@@ -1147,19 +1144,16 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, ...@@ -1147,19 +1144,16 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
sock_recv_timestamp(msg, sk, skb); sock_recv_timestamp(msg, sk, skb);
if (sctp_ulpevent_is_notification(event)) { if (sctp_ulpevent_is_notification(event)) {
msg->msg_flags |= MSG_NOTIFICATION; msg->msg_flags |= MSG_NOTIFICATION;
sp->pf->event_msgname(event, msg->msg_name, addr_len);
} else { } else {
/* Copy the address. */ sp->pf->skb_msgname(skb, msg->msg_name, addr_len);
if (addr_len && msg->msg_name)
sctp_sk_memcpy_msgname(sk, msg->msg_name,
addr_len, skb);
} }
/* Check if we allow SCTP_SNDRCVINFO. */ /* Check if we allow SCTP_SNDRCVINFO. */
if (sctp_sk(sk)->subscribe.sctp_data_io_event) if (sp->subscribe.sctp_data_io_event)
sctp_ulpevent_read_sndrcvinfo(event, msg); sctp_ulpevent_read_sndrcvinfo(event, msg);
#if 0 #if 0
/* FIXME: we should be calling IP layer too. */ /* FIXME: we should be calling IP/IPv6 layers. */
if (sk->protinfo.af_inet.cmsg_flags) if (sk->protinfo.af_inet.cmsg_flags)
ip_cmsg_recv(msg, skb); ip_cmsg_recv(msg, skb);
#endif #endif
...@@ -1176,7 +1170,8 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, ...@@ -1176,7 +1170,8 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
return err; return err;
} }
static inline int sctp_setsockopt_disable_fragments(struct sock *sk, char *optval, int optlen) static inline int sctp_setsockopt_disable_fragments(struct sock *sk,
char *optval, int optlen)
{ {
int val; int val;
...@@ -1191,7 +1186,8 @@ static inline int sctp_setsockopt_disable_fragments(struct sock *sk, char *optva ...@@ -1191,7 +1186,8 @@ static inline int sctp_setsockopt_disable_fragments(struct sock *sk, char *optva
return 0; return 0;
} }
static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval, int optlen) static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval,
int optlen)
{ {
if (optlen != sizeof(struct sctp_event_subscribe)) if (optlen != sizeof(struct sctp_event_subscribe))
return -EINVAL; return -EINVAL;
...@@ -1200,7 +1196,8 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval, int ...@@ -1200,7 +1196,8 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval, int
return 0; return 0;
} }
static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, int optlen) static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
int optlen)
{ {
sctp_opt_t *sp = sctp_sk(sk); sctp_opt_t *sp = sctp_sk(sk);
...@@ -1236,7 +1233,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1236,7 +1233,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
int retval = 0; int retval = 0;
char * tmp; char *tmp;
sctp_protocol_t *proto = sctp_get_protocol(); sctp_protocol_t *proto = sctp_get_protocol();
struct list_head *pos; struct list_head *pos;
sctp_func_t *af; sctp_func_t *af;
...@@ -1356,19 +1353,9 @@ static int sctp_init_sock(struct sock *sk) ...@@ -1356,19 +1353,9 @@ static int sctp_init_sock(struct sock *sk)
proto = sctp_get_protocol(); proto = sctp_get_protocol();
/* Create a per socket endpoint structure. Even if we
* change the data structure relationships, this may still
* be useful for storing pre-connect address information.
*/
ep = sctp_endpoint_new(proto, sk, GFP_KERNEL);
if (!ep)
return -ENOMEM;
sp = sctp_sk(sk); sp = sctp_sk(sk);
/* Initialize the SCTP per socket area. */ /* Initialize the SCTP per socket area. */
sp->ep = ep;
sp->type = SCTP_SOCKET_UDP; sp->type = SCTP_SOCKET_UDP;
/* FIXME: The next draft (04) of the SCTP Sockets Extensions /* FIXME: The next draft (04) of the SCTP Sockets Extensions
...@@ -1425,6 +1412,16 @@ static int sctp_init_sock(struct sock *sk) ...@@ -1425,6 +1412,16 @@ static int sctp_init_sock(struct sock *sk)
* for UDP-style sockets only. * for UDP-style sockets only.
*/ */
sp->autoclose = 0; sp->autoclose = 0;
sp->pf = sctp_get_pf_specific(sk->family);
/* Create a per socket endpoint structure. Even if we
* change the data structure relationships, this may still
* be useful for storing pre-connect address information.
*/
ep = sctp_endpoint_new(proto, sk, GFP_KERNEL);
if (NULL == ep)
return -ENOMEM;
sp->ep = ep;
SCTP_DBG_OBJCNT_INC(sock); SCTP_DBG_OBJCNT_INC(sock);
return 0; return 0;
...@@ -1836,8 +1833,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -1836,8 +1833,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
case PF_INET6: case PF_INET6:
SCTP_V6(tmpaddr.v6.sin6_family = AF_INET6; SCTP_V6(tmpaddr.v6.sin6_family = AF_INET6;
tmpaddr.v6.sin6_port = snum; tmpaddr.v6.sin6_port = snum;
tmpaddr.v6.sin6_addr = tmpaddr.v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
inet6_sk(sk)->rcv_saddr;
) )
break; break;
...@@ -1855,7 +1851,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -1855,7 +1851,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
* that this port/socket (sk) combination are already * that this port/socket (sk) combination are already
* in an endpoint. * in an endpoint.
*/ */
for( ; sk2 != NULL; sk2 = sk2->bind_next) { for ( ; sk2 != NULL; sk2 = sk2->bind_next) {
sctp_endpoint_t *ep2; sctp_endpoint_t *ep2;
ep2 = sctp_sk(sk2)->ep; ep2 = sctp_sk(sk2)->ep;
...@@ -1887,7 +1883,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -1887,7 +1883,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
* SO_REUSEADDR on this socket -sk-). * SO_REUSEADDR on this socket -sk-).
*/ */
if (pp->sk == NULL) { if (pp->sk == NULL) {
pp->fastreuse = sk->reuse? 1 : 0; pp->fastreuse = sk->reuse ? 1 : 0;
} else if (pp->fastreuse && sk->reuse == 0) { } else if (pp->fastreuse && sk->reuse == 0) {
pp->fastreuse = 0; pp->fastreuse = 0;
} }
...@@ -2073,7 +2069,7 @@ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsi ...@@ -2073,7 +2069,7 @@ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsi
pp->sk = NULL; pp->sk = NULL;
if ((pp->next = head->chain) != NULL) if ((pp->next = head->chain) != NULL)
pp->next->pprev = &pp->next; pp->next->pprev = &pp->next;
head->chain= pp; head->chain = pp;
pp->pprev = &head->chain; pp->pprev = &head->chain;
} }
SCTP_DEBUG_PRINTK("sctp_bucket_create() ends, pp=%p\n", pp); SCTP_DEBUG_PRINTK("sctp_bucket_create() ends, pp=%p\n", pp);
...@@ -2433,41 +2429,6 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no ...@@ -2433,41 +2429,6 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
return NULL; return NULL;
} }
/* Copy an approriately formatted address for msg_name. */
static inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname,
int *addr_len, struct sk_buff *skb)
{
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6 __attribute__ ((unused));
struct sctphdr *sh;
/* The sockets layer handles copying this out to user space. */
switch (sk->family) {
case PF_INET:
sin = (struct sockaddr_in *)msgname;
if (addr_len)
*addr_len = sizeof(struct sockaddr_in);
sin->sin_family = AF_INET;
sh = (struct sctphdr *) skb->h.raw;
sin->sin_port = sh->source;
sin->sin_addr.s_addr = skb->nh.iph->saddr;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
break;
case PF_INET6:
SCTP_V6(
/* FIXME: Need v6 code here. We should convert
* V4 addresses to PF_INET6 format. See ipv6/udp.c
* for an example. --jgrimm
*/
);
break;
default: /* Should not get here. */
break;
};
}
static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg)
{ {
sockaddr_storage_t *sa; sockaddr_storage_t *sa;
......
...@@ -46,9 +46,10 @@ ...@@ -46,9 +46,10 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
static void sctp_rcvmsg_rfree(struct sk_buff *skb);
static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, static void sctp_ulpevent_set_owner_r(struct sk_buff *skb,
sctp_association_t *asoc); sctp_association_t *asoc);
static void
sctp_ulpevent_set_owner(struct sk_buff *skb, const sctp_association_t *asoc);
/* Create a new sctp_ulpevent. */ /* Create a new sctp_ulpevent. */
sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority) sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority)
...@@ -123,14 +124,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, ...@@ -123,14 +124,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
struct sctp_assoc_change *sac; struct sctp_assoc_change *sac;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, MSG_NOTIFICATION, priority);
priority);
if (!event) if (!event)
goto fail; goto fail;
sac = (struct sctp_assoc_change *) sac = (struct sctp_assoc_change *)
skb_put(event->parent, skb_put(event->parent, sizeof(struct sctp_assoc_change));
sizeof(struct sctp_assoc_change));
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.1 SCTP_ASSOC_CHANGE * 5.3.1.1 SCTP_ASSOC_CHANGE
...@@ -199,6 +198,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, ...@@ -199,6 +198,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc);
sac->sac_assoc_id = sctp_assoc2id(asoc); sac->sac_assoc_id = sctp_assoc2id(asoc);
return event; return event;
...@@ -227,14 +227,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( ...@@ -227,14 +227,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
struct sctp_paddr_change *spc; struct sctp_paddr_change *spc;
event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change), event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change),
MSG_NOTIFICATION, MSG_NOTIFICATION, priority);
priority);
if (!event) if (!event)
goto fail; goto fail;
spc = (struct sctp_paddr_change *) spc = (struct sctp_paddr_change *)
skb_put(event->parent, skb_put(event->parent, sizeof(struct sctp_paddr_change));
sizeof(struct sctp_paddr_change));
/* Sockets API Extensions for SCTP /* Sockets API Extensions for SCTP
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
...@@ -287,12 +285,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( ...@@ -287,12 +285,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.1 SCTP_ASSOC_CHANGE * 5.3.1.1 SCTP_ASSOC_CHANGE
* *
* sac_assoc_id: sizeof (sctp_assoc_t) * spc_assoc_id: sizeof (sctp_assoc_t)
* *
* The association id field, holds the identifier for the association. * The association id field, holds the identifier for the association.
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc);
spc->spc_assoc_id = sctp_assoc2id(asoc); spc->spc_assoc_id = sctp_assoc2id(asoc);
/* Sockets API Extensions for SCTP /* Sockets API Extensions for SCTP
...@@ -360,9 +359,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, ...@@ -360,9 +359,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
/* Embed the event fields inside the cloned skb. */ /* Embed the event fields inside the cloned skb. */
event = (sctp_ulpevent_t *) skb->cb; event = (sctp_ulpevent_t *) skb->cb;
event = sctp_ulpevent_init(event, event = sctp_ulpevent_init(event, skb, MSG_NOTIFICATION);
skb,
MSG_NOTIFICATION);
if (!event) if (!event)
goto fail; goto fail;
...@@ -418,6 +416,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, ...@@ -418,6 +416,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc);
sre->sre_assoc_id = sctp_assoc2id(asoc); sre->sre_assoc_id = sctp_assoc2id(asoc);
return event; return event;
...@@ -515,9 +514,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, ...@@ -515,9 +514,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* The original send information associated with the undelivered * The original send information associated with the undelivered
* message. * message.
*/ */
memcpy(&ssf->ssf_info, memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
&chunk->sinfo,
sizeof(struct sctp_sndrcvinfo));
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.4 SCTP_SEND_FAILED * 5.3.1.4 SCTP_SEND_FAILED
...@@ -528,8 +525,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, ...@@ -528,8 +525,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* same association identifier. For TCP style socket, this field is * same association identifier. For TCP style socket, this field is
* ignored. * ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc);
ssf->ssf_assoc_id = sctp_assoc2id(asoc); ssf->ssf_assoc_id = sctp_assoc2id(asoc);
return event; return event;
fail: fail:
...@@ -541,7 +538,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, ...@@ -541,7 +538,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* Socket Extensions for SCTP - draft-01 * Socket Extensions for SCTP - draft-01
* 5.3.1.5 SCTP_SHUTDOWN_EVENT * 5.3.1.5 SCTP_SHUTDOWN_EVENT
*/ */
sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *asoc, sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
const sctp_association_t *asoc,
__u16 flags, __u16 flags,
int priority) int priority)
{ {
...@@ -549,14 +547,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso ...@@ -549,14 +547,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso
struct sctp_shutdown_event *sse; struct sctp_shutdown_event *sse;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, MSG_NOTIFICATION, priority);
priority);
if (!event) if (!event)
goto fail; goto fail;
sse = (struct sctp_shutdown_event *) sse = (struct sctp_shutdown_event *)
skb_put(event->parent, skb_put(event->parent, sizeof(struct sctp_shutdown_event));
sizeof(struct sctp_shutdown_event));
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.5 SCTP_SHUTDOWN_EVENT * 5.3.1.5 SCTP_SHUTDOWN_EVENT
...@@ -591,6 +587,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso ...@@ -591,6 +587,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc);
sse->sse_assoc_id = sctp_assoc2id(asoc); sse->sse_assoc_id = sctp_assoc2id(asoc);
return event; return event;
...@@ -607,8 +604,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso ...@@ -607,8 +604,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso
* 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
*/ */
sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
sctp_chunk_t *chunk, sctp_chunk_t *chunk, int priority)
int priority)
{ {
sctp_ulpevent_t *event; sctp_ulpevent_t *event;
struct sctp_sndrcvinfo *info; struct sctp_sndrcvinfo *info;
...@@ -818,23 +814,33 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a ...@@ -818,23 +814,33 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
asoc->rwnd_over = skb->len - asoc->rwnd; asoc->rwnd_over = skb->len - asoc->rwnd;
asoc->rwnd = 0; asoc->rwnd = 0;
} }
SCTP_DEBUG_PRINTK("rwnd decreased by %d to (%u, %u)\n", SCTP_DEBUG_PRINTK("rwnd decreased by %d to (%u, %u)\n",
skb->len, asoc->rwnd, asoc->rwnd_over); skb->len, asoc->rwnd, asoc->rwnd_over);
} }
/* A simple destructor to give up the reference to the association. */
static void sctp_ulpevent_rfree(struct sk_buff *skb)
{
sctp_ulpevent_t *event;
event = (sctp_ulpevent_t *)skb->cb;
sctp_association_put(event->asoc);
}
/* Hold the association in case the msg_name needs read out of
* the association.
*/
static void sctp_ulpevent_set_owner(struct sk_buff *skb,
const sctp_association_t *asoc)
{
sctp_ulpevent_t *event;
/* Cast away the const, as we are just wanting to
* bump the reference count.
*/
sctp_association_hold((sctp_association_t *)asoc);
skb->sk = asoc->base.sk;
event = (sctp_ulpevent_t *)skb->cb;
event->asoc = (sctp_association_t *)asoc;
skb->destructor = sctp_ulpevent_rfree;
}
/* /*
* X.25 Packet Layer release 002 * X.25 Packet Layer release 002
* *
* This is ALPHA test software. This code may break your machine, randomly fail to work with new * This is ALPHA test software. This code may break your machine,
* releases, misbehave and/or generally screw up. It might even work. * randomly fail to work with new releases, misbehave and/or generally
* screw up. It might even work.
* *
* This code REQUIRES 2.1.15 or higher * This code REQUIRES 2.1.15 or higher
* *
...@@ -68,9 +69,10 @@ static struct sock *volatile x25_list /* = NULL initially */; ...@@ -68,9 +69,10 @@ static struct sock *volatile x25_list /* = NULL initially */;
static struct proto_ops x25_proto_ops; static struct proto_ops x25_proto_ops;
static x25_address null_x25_address = {" "}; static struct x25_address null_x25_address = {" "};
int x25_addr_ntoa(unsigned char *p, x25_address *called_addr, x25_address *calling_addr) int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr,
struct x25_address *calling_addr)
{ {
int called_len, calling_len; int called_len, calling_len;
char *called, *calling; char *called, *calling;
...@@ -101,13 +103,13 @@ int x25_addr_ntoa(unsigned char *p, x25_address *called_addr, x25_address *calli ...@@ -101,13 +103,13 @@ int x25_addr_ntoa(unsigned char *p, x25_address *called_addr, x25_address *calli
} }
} }
*called = '\0'; *called = *calling = '\0';
*calling = '\0';
return 1 + (called_len + calling_len + 1) / 2; return 1 + (called_len + calling_len + 1) / 2;
} }
int x25_addr_aton(unsigned char *p, x25_address *called_addr, x25_address *calling_addr) int x25_addr_aton(unsigned char *p, struct x25_address *called_addr,
struct x25_address *calling_addr)
{ {
unsigned int called_len, calling_len; unsigned int called_len, calling_len;
char *called, *calling; char *called, *calling;
...@@ -155,22 +157,16 @@ static void x25_remove_socket(struct sock *sk) ...@@ -155,22 +157,16 @@ static void x25_remove_socket(struct sock *sk)
save_flags(flags); save_flags(flags);
cli(); cli();
if ((s = x25_list) == sk) { if ((s = x25_list) == sk)
x25_list = s->next; x25_list = s->next;
restore_flags(flags); else while (s && s->next) {
return;
}
while (s != NULL && s->next != NULL) {
if (s->next == sk) { if (s->next == sk) {
s->next = sk->next; s->next = sk->next;
restore_flags(flags); break;
return;
} }
s = s->next; s = s->next;
} }
restore_flags(flags); restore_flags(flags);
} }
...@@ -181,7 +177,7 @@ static void x25_kill_by_device(struct net_device *dev) ...@@ -181,7 +177,7 @@ static void x25_kill_by_device(struct net_device *dev)
{ {
struct sock *s; struct sock *s;
for (s = x25_list; s != NULL; s = s->next) for (s = x25_list; s; s = s->next)
if (x25_sk(s)->neighbour && x25_sk(s)->neighbour->dev == dev) if (x25_sk(s)->neighbour && x25_sk(s)->neighbour->dev == dev)
x25_disconnect(s, ENETUNREACH, 0, 0); x25_disconnect(s, ENETUNREACH, 0, 0);
} }
...@@ -191,7 +187,7 @@ static void x25_kill_by_device(struct net_device *dev) ...@@ -191,7 +187,7 @@ static void x25_kill_by_device(struct net_device *dev)
*/ */
static int x25_device_event(struct notifier_block *this, unsigned long event, void *ptr) static int x25_device_event(struct notifier_block *this, unsigned long event, void *ptr)
{ {
struct net_device *dev = (struct net_device *)ptr; struct net_device *dev = ptr;
struct x25_neigh *neigh; struct x25_neigh *neigh;
if (dev->type == ARPHRD_X25 if (dev->type == ARPHRD_X25
...@@ -238,7 +234,7 @@ static void x25_insert_socket(struct sock *sk) ...@@ -238,7 +234,7 @@ static void x25_insert_socket(struct sock *sk)
* Find a socket that wants to accept the Call Request we just * Find a socket that wants to accept the Call Request we just
* received. * received.
*/ */
static struct sock *x25_find_listener(x25_address *addr) static struct sock *x25_find_listener(struct x25_address *addr)
{ {
unsigned long flags; unsigned long flags;
struct sock *s; struct sock *s;
...@@ -246,17 +242,14 @@ static struct sock *x25_find_listener(x25_address *addr) ...@@ -246,17 +242,14 @@ static struct sock *x25_find_listener(x25_address *addr)
save_flags(flags); save_flags(flags);
cli(); cli();
for (s = x25_list; s != NULL; s = s->next) { for (s = x25_list; s; s = s->next)
if ((!strcmp(addr->x25_addr, x25_sk(s)->source_addr.x25_addr) || if ((!strcmp(addr->x25_addr, x25_sk(s)->source_addr.x25_addr) ||
strcmp(addr->x25_addr, null_x25_address.x25_addr) == 0) && !strcmp(addr->x25_addr, null_x25_address.x25_addr)) &&
s->state == TCP_LISTEN) { s->state == TCP_LISTEN)
restore_flags(flags); break;
return s;
}
}
restore_flags(flags); restore_flags(flags);
return NULL; return s;
} }
/* /*
...@@ -270,15 +263,12 @@ struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh) ...@@ -270,15 +263,12 @@ struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh)
save_flags(flags); save_flags(flags);
cli(); cli();
for (s = x25_list; s != NULL; s = s->next) { for (s = x25_list; s; s = s->next)
if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == neigh) { if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == neigh)
restore_flags(flags); break;
return s;
}
}
restore_flags(flags); restore_flags(flags);
return NULL; return s;
} }
/* /*
...@@ -288,9 +278,10 @@ unsigned int x25_new_lci(struct x25_neigh *neigh) ...@@ -288,9 +278,10 @@ unsigned int x25_new_lci(struct x25_neigh *neigh)
{ {
unsigned int lci = 1; unsigned int lci = 1;
while (x25_find_socket(lci, neigh) != NULL) { while (x25_find_socket(lci, neigh))
lci++; if (++lci == 4096) {
if (lci == 4096) return 0; lci = 0;
break;
} }
return lci; return lci;
...@@ -339,7 +330,7 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer ...@@ -339,7 +330,7 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
kfree_skb(skb); kfree_skb(skb);
} }
if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) { if (atomic_read(&sk->wmem_alloc) || atomic_read(&sk->rmem_alloc)) {
/* Defer: outstanding buffers */ /* Defer: outstanding buffers */
init_timer(&sk->timer); init_timer(&sk->timer);
sk->timer.expires = jiffies + 10 * HZ; sk->timer.expires = jiffies + 10 * HZ;
...@@ -362,73 +353,69 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer ...@@ -362,73 +353,69 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
static int x25_setsockopt(struct socket *sock, int level, int optname, static int x25_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sock *sk = sock->sk;
int opt; int opt;
struct sock *sk = sock->sk;
int rc = -ENOPROTOOPT;
if (level != SOL_X25) if (level != SOL_X25 || optname != X25_QBITINCL)
return -ENOPROTOOPT; goto out;
rc = -EINVAL;
if (optlen < sizeof(int)) if (optlen < sizeof(int))
return-EINVAL; goto out;
rc = -EFAULT;
if (get_user(opt, (int *)optval)) if (get_user(opt, (int *)optval))
return -EFAULT; goto out;
switch (optname) {
case X25_QBITINCL:
x25_sk(sk)->qbitincl = opt ? 1 : 0;
return 0;
default: x25_sk(sk)->qbitincl = !!opt;
return -ENOPROTOOPT; rc = 0;
} out:
return rc;
} }
static int x25_getsockopt(struct socket *sock, int level, int optname, static int x25_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen) char *optval, int *optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int val = 0; int val, len, rc = -ENOPROTOOPT;
int len;
if (level != SOL_X25) if (level != SOL_X25 || optname != X25_QBITINCL)
return -ENOPROTOOPT; goto out;
rc = -EFAULT;
if (get_user(len, optlen)) if (get_user(len, optlen))
return -EFAULT; goto out;
switch (optname) {
case X25_QBITINCL:
val = x25_sk(sk)->qbitincl;
break;
default:
return -ENOPROTOOPT;
}
len = min_t(unsigned int, len, sizeof(int)); len = min_t(unsigned int, len, sizeof(int));
rc = -EINVAL;
if (len < 0) if (len < 0)
return -EINVAL; goto out;
rc = -EFAULT;
if (put_user(len, optlen)) if (put_user(len, optlen))
return -EFAULT; goto out;
return copy_to_user(optval, &val, len) ? -EFAULT : 0; val = x25_sk(sk)->qbitincl;
rc = copy_to_user(optval, &val, len) ? -EFAULT : 0;
out:
return rc;
} }
static int x25_listen(struct socket *sock, int backlog) static int x25_listen(struct socket *sock, int backlog)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int rc = -EOPNOTSUPP;
if (sk->state != TCP_LISTEN) { if (sk->state != TCP_LISTEN) {
memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN); memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN);
sk->max_ack_backlog = backlog; sk->max_ack_backlog = backlog;
sk->state = TCP_LISTEN; sk->state = TCP_LISTEN;
return 0; rc = 0;
} }
return -EOPNOTSUPP; return rc;
} }
static struct sock *x25_alloc_socket(void) static struct sock *x25_alloc_socket(void)
...@@ -445,7 +432,7 @@ static struct sock *x25_alloc_socket(void) ...@@ -445,7 +432,7 @@ static struct sock *x25_alloc_socket(void)
if (!x25) if (!x25)
goto frees; goto frees;
memset(x25, 0x00, sizeof(*x25)); memset(x25, 0, sizeof(*x25));
x25->sk = sk; x25->sk = sk;
...@@ -455,10 +442,13 @@ static struct sock *x25_alloc_socket(void) ...@@ -455,10 +442,13 @@ static struct sock *x25_alloc_socket(void)
skb_queue_head_init(&x25->fragment_queue); skb_queue_head_init(&x25->fragment_queue);
skb_queue_head_init(&x25->interrupt_in_queue); skb_queue_head_init(&x25->interrupt_in_queue);
skb_queue_head_init(&x25->interrupt_out_queue); skb_queue_head_init(&x25->interrupt_out_queue);
out: return sk; out:
frees: sk_free(sk); return sk;
frees:
sk_free(sk);
sk = NULL; sk = NULL;
decmod: MOD_DEC_USE_COUNT; decmod:
MOD_DEC_USE_COUNT;
goto out; goto out;
} }
...@@ -466,12 +456,14 @@ static int x25_create(struct socket *sock, int protocol) ...@@ -466,12 +456,14 @@ static int x25_create(struct socket *sock, int protocol)
{ {
struct sock *sk; struct sock *sk;
x25_cb *x25; x25_cb *x25;
int rc = -ESOCKTNOSUPPORT;
if (sock->type != SOCK_SEQPACKET || protocol != 0) if (sock->type != SOCK_SEQPACKET || protocol)
return -ESOCKTNOSUPPORT; goto out;
rc = -ENOMEM;
if ((sk = x25_alloc_socket()) == NULL) if ((sk = x25_alloc_socket()) == NULL)
return -ENOMEM; goto out;
x25 = x25_sk(sk); x25 = x25_sk(sk);
...@@ -495,20 +487,21 @@ static int x25_create(struct socket *sock, int protocol) ...@@ -495,20 +487,21 @@ static int x25_create(struct socket *sock, int protocol)
x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; x25->facilities.throughput = X25_DEFAULT_THROUGHPUT;
x25->facilities.reverse = X25_DEFAULT_REVERSE; x25->facilities.reverse = X25_DEFAULT_REVERSE;
rc = 0;
return 0; out:
return rc;
} }
static struct sock *x25_make_new(struct sock *osk) static struct sock *x25_make_new(struct sock *osk)
{ {
struct sock *sk; struct sock *sk = NULL;
x25_cb *x25, *ox25; x25_cb *x25, *ox25;
if (osk->type != SOCK_SEQPACKET) if (osk->type != SOCK_SEQPACKET)
return NULL; goto out;
if ((sk = x25_alloc_socket()) == NULL) if ((sk = x25_alloc_socket()) == NULL)
return NULL; goto out;
x25 = x25_sk(sk); x25 = x25_sk(sk);
...@@ -533,7 +526,7 @@ static struct sock *x25_make_new(struct sock *osk) ...@@ -533,7 +526,7 @@ static struct sock *x25_make_new(struct sock *osk)
x25->qbitincl = ox25->qbitincl; x25->qbitincl = ox25->qbitincl;
init_timer(&x25->timer); init_timer(&x25->timer);
out:
return sk; return sk;
} }
...@@ -542,7 +535,8 @@ static int x25_release(struct socket *sock) ...@@ -542,7 +535,8 @@ static int x25_release(struct socket *sock)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25; x25_cb *x25;
if (sk == NULL) return 0; if (!sk)
goto out;
x25 = x25_sk(sk); x25 = x25_sk(sk);
...@@ -567,14 +561,11 @@ static int x25_release(struct socket *sock) ...@@ -567,14 +561,11 @@ static int x25_release(struct socket *sock)
sk->dead = 1; sk->dead = 1;
sk->destroy = 1; sk->destroy = 1;
break; break;
default:
break;
} }
sock->sk = NULL; sock->sk = NULL;
sk->socket = NULL; /* Not used, but we should do this */ sk->socket = NULL; /* Not used, but we should do this */
out:
return 0; return 0;
} }
...@@ -583,21 +574,14 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -583,21 +574,14 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
if (sk->zapped == 0) if (!sk->zapped ||
return -EINVAL; addr_len != sizeof(struct sockaddr_x25) ||
addr->sx25_family != AF_X25)
if (addr_len != sizeof(struct sockaddr_x25))
return -EINVAL;
if (addr->sx25_family != AF_X25)
return -EINVAL; return -EINVAL;
x25_sk(sk)->source_addr = addr->sx25_addr; x25_sk(sk)->source_addr = addr->sx25_addr;
x25_insert_socket(sk); x25_insert_socket(sk);
sk->zapped = 0; sk->zapped = 0;
SOCK_DEBUG(sk, "x25_bind: socket is bound\n"); SOCK_DEBUG(sk, "x25_bind: socket is bound\n");
return 0; return 0;
...@@ -609,42 +593,49 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -609,42 +593,49 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
x25_cb *x25 = x25_sk(sk); x25_cb *x25 = x25_sk(sk);
struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
struct net_device *dev; struct net_device *dev;
int rc = 0;
if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
return 0; /* Connect completed during a ERESTARTSYS event */ goto out; /* Connect completed during a ERESTARTSYS event */
} }
rc = -ECONNREFUSED;
if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) { if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) {
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
return -ECONNREFUSED; goto out;
} }
rc = -EISCONN; /* No reconnect on a seqpacket socket */
if (sk->state == TCP_ESTABLISHED) if (sk->state == TCP_ESTABLISHED)
return -EISCONN; /* No reconnect on a seqpacket socket */ goto out;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
if (addr_len != sizeof(struct sockaddr_x25)) rc = -EINVAL;
return -EINVAL; if (addr_len != sizeof(struct sockaddr_x25) ||
addr->sx25_family != AF_X25)
if (addr->sx25_family != AF_X25) goto out;
return -EINVAL;
if ((dev = x25_get_route(&addr->sx25_addr)) == NULL) rc = -ENETUNREACH;
return -ENETUNREACH; dev = x25_get_route(&addr->sx25_addr);
if (!dev)
goto out;
if ((x25->neighbour = x25_get_neigh(dev)) == NULL) x25->neighbour = x25_get_neigh(dev);
return -ENETUNREACH; if (!x25->neighbour)
goto out;
x25_limit_facilities(&x25->facilities, x25->neighbour); x25_limit_facilities(&x25->facilities, x25->neighbour);
if ((x25->lci = x25_new_lci(x25->neighbour)) == 0) x25->lci = x25_new_lci(x25->neighbour);
return -ENETUNREACH; if (!x25->lci)
goto out;
rc = -EINVAL;
if (sk->zapped) /* Must bind first - autobinding does not work */ if (sk->zapped) /* Must bind first - autobinding does not work */
return -EINVAL; goto out;
if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr)) if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr))
memset(&x25->source_addr, '\0', X25_ADDR_LEN); memset(&x25->source_addr, '\0', X25_ADDR_LEN);
...@@ -663,49 +654,50 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len ...@@ -663,49 +654,50 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len
x25_start_t21timer(sk); x25_start_t21timer(sk);
/* Now the loop */ /* Now the loop */
rc = -EINPROGRESS;
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
return -EINPROGRESS; goto out;
cli(); /* To avoid races on the sleep */ cli(); /* To avoid races on the sleep */
/* /*
* A Clear Request or timeout or failed routing will go to closed. * A Clear Request or timeout or failed routing will go to closed.
*/ */
rc = -ERESTARTSYS;
while (sk->state == TCP_SYN_SENT) { while (sk->state == TCP_SYN_SENT) {
/* FIXME: going to sleep with interrupts disabled */
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
if (signal_pending(current)) { if (signal_pending(current))
sti(); goto out_unlock;
return -ERESTARTSYS;
}
} }
if (sk->state != TCP_ESTABLISHED) { if (sk->state != TCP_ESTABLISHED) {
sti();
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */ rc = sock_error(sk); /* Always set at this point */
goto out_unlock;
} }
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
rc = 0;
out_unlock:
sti(); sti();
out:
return 0; return rc;
} }
static int x25_accept(struct socket *sock, struct socket *newsock, int flags) static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
{ {
struct sock *sk; struct sock *sk = sock->sk;
struct sock *newsk; struct sock *newsk;
struct sk_buff *skb; struct sk_buff *skb;
int rc = -EINVAL;
if ((sk = sock->sk) == NULL) if (!sk || sk->state != TCP_LISTEN)
return -EINVAL; goto out;
rc = -EOPNOTSUPP;
if (sk->type != SOCK_SEQPACKET) if (sk->type != SOCK_SEQPACKET)
return -EOPNOTSUPP; goto out;
if (sk->state != TCP_LISTEN)
return -EINVAL;
/* /*
* The write queue this time is holding sockets ready to use * The write queue this time is holding sockets ready to use
...@@ -714,17 +706,16 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -714,17 +706,16 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
do { do {
cli(); cli();
if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) { if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
if (flags & O_NONBLOCK) { rc = -EWOULDBLOCK;
sti(); if (flags & O_NONBLOCK)
return -EWOULDBLOCK; goto out_unlock;
} /* FIXME: going to sleep with interrupts disabled */
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
if (signal_pending(current)) { rc = -ERESTARTSYS;
sti(); if (signal_pending(current))
return -ERESTARTSYS; goto out_unlock;
}
} }
} while (skb == NULL); } while (!skb);
newsk = skb->sk; newsk = skb->sk;
newsk->pair = NULL; newsk->pair = NULL;
...@@ -738,8 +729,12 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -738,8 +729,12 @@ static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
sk->ack_backlog--; sk->ack_backlog--;
newsock->sk = newsk; newsock->sk = newsk;
newsock->state = SS_CONNECTED; newsock->state = SS_CONNECTED;
rc = 0;
return 0; out:
return rc;
out_unlock:
sti();
goto out;
} }
static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
...@@ -748,16 +743,15 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_l ...@@ -748,16 +743,15 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_l
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); x25_cb *x25 = x25_sk(sk);
if (peer != 0) { if (peer) {
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; return -ENOTCONN;
sx25->sx25_addr = x25->dest_addr; sx25->sx25_addr = x25->dest_addr;
} else { } else
sx25->sx25_addr = x25->source_addr; sx25->sx25_addr = x25->source_addr;
}
sx25->sx25_family = AF_X25; sx25->sx25_family = AF_X25;
*uaddr_len = sizeof(struct sockaddr_x25); *uaddr_len = sizeof(*sx25);
return 0; return 0;
} }
...@@ -767,9 +761,9 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -767,9 +761,9 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
struct sock *sk; struct sock *sk;
struct sock *make; struct sock *make;
x25_cb *makex25; x25_cb *makex25;
x25_address source_addr, dest_addr; struct x25_address source_addr, dest_addr;
struct x25_facilities facilities; struct x25_facilities facilities;
int len; int len, rc;
/* /*
* Remove the LCI and frame type. * Remove the LCI and frame type.
...@@ -790,18 +784,14 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -790,18 +784,14 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
/* /*
* We can't accept the Call Request. * We can't accept the Call Request.
*/ */
if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog) { if (!sk || sk->ack_backlog == sk->max_ack_backlog)
x25_transmit_clear_request(neigh, lci, 0x01); goto out_clear_request;
return 0;
}
/* /*
* Try to reach a compromise on the requested facilities. * Try to reach a compromise on the requested facilities.
*/ */
if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1) { if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1)
x25_transmit_clear_request(neigh, lci, 0x01); goto out_clear_request;
return 0;
}
/* /*
* current neighbour/link might impose additional limits * current neighbour/link might impose additional limits
...@@ -813,10 +803,9 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -813,10 +803,9 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
/* /*
* Try to create a new socket. * Try to create a new socket.
*/ */
if ((make = x25_make_new(sk)) == NULL) { make = x25_make_new(sk);
x25_transmit_clear_request(neigh, lci, 0x01); if (!make)
return 0; goto out_clear_request;
}
/* /*
* Remove the facilities, leaving any Call User Data. * Remove the facilities, leaving any Call User Data.
...@@ -857,8 +846,13 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i ...@@ -857,8 +846,13 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned i
if (!sk->dead) if (!sk->dead)
sk->data_ready(sk, skb->len); sk->data_ready(sk, skb->len);
rc = 1;
return 1; out:
return rc;
out_clear_request:
rc = 0;
x25_transmit_clear_request(neigh, lci, 0x01);
goto out;
} }
static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
...@@ -866,46 +860,53 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -866,46 +860,53 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); x25_cb *x25 = x25_sk(sk);
struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name; struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name;
int err;
struct sockaddr_x25 sx25; struct sockaddr_x25 sx25;
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *asmptr; unsigned char *asmptr;
int size, qbit = 0; int noblock = msg->msg_flags & MSG_DONTWAIT;
int size, qbit = 0, rc = -EINVAL;
if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_OOB | MSG_EOR)) if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_OOB | MSG_EOR))
return -EINVAL; goto out;
/* we currently don't support segmented records at the user interface */ /* we currently don't support segmented records at the user interface */
if (!(msg->msg_flags & (MSG_EOR|MSG_OOB))) if (!(msg->msg_flags & (MSG_EOR|MSG_OOB)))
return -EINVAL; goto out;
rc = -EADDRNOTAVAIL;
if (sk->zapped) if (sk->zapped)
return -EADDRNOTAVAIL; goto out;
rc = -EPIPE;
if (sk->shutdown & SEND_SHUTDOWN) { if (sk->shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 0); send_sig(SIGPIPE, current, 0);
return -EPIPE; goto out;
} }
if (x25->neighbour == NULL) rc = -ENETUNREACH;
return -ENETUNREACH; if (!x25->neighbour)
goto out;
if (usx25 != NULL) { if (usx25) {
rc = -EINVAL;
if (msg->msg_namelen < sizeof(sx25)) if (msg->msg_namelen < sizeof(sx25))
return -EINVAL; goto out;
sx25 = *usx25; memcpy(&sx25, usx25, sizeof(sx25));
rc = -EISCONN;
if (strcmp(x25->dest_addr.x25_addr, sx25.sx25_addr.x25_addr)) if (strcmp(x25->dest_addr.x25_addr, sx25.sx25_addr.x25_addr))
return -EISCONN; goto out;
rc = -EINVAL;
if (sx25.sx25_family != AF_X25) if (sx25.sx25_family != AF_X25)
return -EINVAL; goto out;
} else { } else {
/* /*
* FIXME 1003.1g - if the socket is like this because * FIXME 1003.1g - if the socket is like this because
* it has become closed (not started closed) we ought * it has become closed (not started closed) we ought
* to SIGPIPE, EPIPE; * to SIGPIPE, EPIPE;
*/ */
rc = -ENOTCONN;
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; goto out;
sx25.sx25_family = AF_X25; sx25.sx25_family = AF_X25;
sx25.sx25_addr = x25->dest_addr; sx25.sx25_addr = x25->dest_addr;
...@@ -921,8 +922,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -921,8 +922,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN; size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) skb = sock_alloc_send_skb(sk, size, noblock, &rc);
return err; if (!skb)
goto out;
X25_SKB_CB(skb)->flags = msg->msg_flags; X25_SKB_CB(skb)->flags = msg->msg_flags;
skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN); skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN);
...@@ -934,7 +936,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -934,7 +936,9 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
asmptr = skb->h.raw = skb_put(skb, len); asmptr = skb->h.raw = skb_put(skb, len);
memcpy_fromiovec(asmptr, msg->msg_iov, len); rc = memcpy_fromiovec(asmptr, msg->msg_iov, len);
if (rc)
goto out_kfree_skb;
/* /*
* If the Q BIT Include socket option is in force, the first * If the Q BIT Include socket option is in force, the first
...@@ -985,22 +989,19 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -985,22 +989,19 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
SOCK_DEBUG(sk, "x25_sendmsg: Built header.\n"); SOCK_DEBUG(sk, "x25_sendmsg: Built header.\n");
SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n"); SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n");
if (sk->state != TCP_ESTABLISHED) { rc = -ENOTCONN;
kfree_skb(skb); if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; goto out_kfree_skb;
}
if (msg->msg_flags & MSG_OOB) { if (msg->msg_flags & MSG_OOB)
skb_queue_tail(&x25->interrupt_out_queue, skb); skb_queue_tail(&x25->interrupt_out_queue, skb);
} else { else {
len = x25_output(sk, skb); len = x25_output(sk, skb);
if(len<0){ if (len < 0)
kfree_skb(skb); kfree_skb(skb);
} else { else if (x25->qbitincl)
if (x25->qbitincl)
len++; len++;
} }
}
/* /*
* lock_sock() is currently only used to serialize this x25_kick() * lock_sock() is currently only used to serialize this x25_kick()
...@@ -1019,12 +1020,17 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1019,12 +1020,17 @@ static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
lock_sock(sk); lock_sock(sk);
x25_kick(sk); x25_kick(sk);
release_sock(sk); release_sock(sk);
rc = len;
return len; out:
return rc;
out_kfree_skb:
kfree_skb(skb);
goto out;
} }
static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
int flags, struct scm_cookie *scm)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); x25_cb *x25 = x25_sk(sk);
...@@ -1032,18 +1038,19 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl ...@@ -1032,18 +1038,19 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl
int copied, qbit; int copied, qbit;
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *asmptr; unsigned char *asmptr;
int er; int rc = -ENOTCONN;
/* /*
* This works for seqpacket too. The receiver has ordered the queue for * This works for seqpacket too. The receiver has ordered the queue for
* us! We do one quick check first though * us! We do one quick check first though
*/ */
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN; goto out;
if (flags & MSG_OOB) { if (flags & MSG_OOB) {
rc = -EINVAL;
if (sk->urginline || !skb_peek(&x25->interrupt_in_queue)) if (sk->urginline || !skb_peek(&x25->interrupt_in_queue))
return -EINVAL; goto out;
skb = skb_dequeue(&x25->interrupt_in_queue); skb = skb_dequeue(&x25->interrupt_in_queue);
...@@ -1060,8 +1067,9 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl ...@@ -1060,8 +1067,9 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl
msg->msg_flags |= MSG_OOB; msg->msg_flags |= MSG_OOB;
} else { } else {
/* Now we can treat all alike */ /* Now we can treat all alike */
if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &rc);
return er; if (!skb)
goto out;
qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
...@@ -1086,21 +1094,25 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl ...@@ -1086,21 +1094,25 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int fl
/* Currently, each datagram always contains a complete record */ /* Currently, each datagram always contains a complete record */
msg->msg_flags |= MSG_EOR; msg->msg_flags |= MSG_EOR;
skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (rc)
goto out_free_dgram;
if (sx25 != NULL) { if (sx25) {
sx25->sx25_family = AF_X25; sx25->sx25_family = AF_X25;
sx25->sx25_addr = x25->dest_addr; sx25->sx25_addr = x25->dest_addr;
} }
msg->msg_namelen = sizeof(struct sockaddr_x25); msg->msg_namelen = sizeof(struct sockaddr_x25);
skb_free_datagram(sk, skb);
lock_sock(sk); lock_sock(sk);
x25_check_rbuf(sk); x25_check_rbuf(sk);
release_sock(sk); release_sock(sk);
rc = copied;
return copied; out_free_dgram:
skb_free_datagram(sk, skb);
out:
return rc;
} }
...@@ -1108,6 +1120,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -1108,6 +1120,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
x25_cb *x25 = x25_sk(sk); x25_cb *x25 = x25_sk(sk);
int rc;
switch (cmd) { switch (cmd) {
case TIOCOUTQ: { case TIOCOUTQ: {
...@@ -1115,26 +1128,33 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -1115,26 +1128,33 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
if (amount < 0) if (amount < 0)
amount = 0; amount = 0;
return put_user(amount, (unsigned int *)arg); rc = put_user(amount, (unsigned int *)arg);
break;
} }
case TIOCINQ: { case TIOCINQ: {
struct sk_buff *skb; struct sk_buff *skb;
int amount = 0; int amount = 0;
/* These two are safe on a single CPU system as only user tasks fiddle here */ /*
* These two are safe on a single CPU system as
* only user tasks fiddle here
*/
if ((skb = skb_peek(&sk->receive_queue)) != NULL) if ((skb = skb_peek(&sk->receive_queue)) != NULL)
amount = skb->len; amount = skb->len;
return put_user(amount, (unsigned int *)arg); rc = put_user(amount, (unsigned int *)arg);
break;
} }
case SIOCGSTAMP: case SIOCGSTAMP:
if (sk != NULL) { if (sk) {
if (sk->stamp.tv_sec == 0) rc = -ENOENT;
return -ENOENT; if (!sk->stamp.tv_sec)
return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; break;
rc = copy_to_user((void *)arg, &sk->stamp,
sizeof(struct timeval)) ? -EFAULT : 0;
} }
return -EINVAL; rc = -EINVAL;
break;
case SIOCGIFADDR: case SIOCGIFADDR:
case SIOCSIFADDR: case SIOCSIFADDR:
case SIOCGIFDSTADDR: case SIOCGIFDSTADDR:
...@@ -1145,74 +1165,90 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -1145,74 +1165,90 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCSIFNETMASK: case SIOCSIFNETMASK:
case SIOCGIFMETRIC: case SIOCGIFMETRIC:
case SIOCSIFMETRIC: case SIOCSIFMETRIC:
return -EINVAL; rc = -EINVAL;
break;
case SIOCADDRT: case SIOCADDRT:
case SIOCDELRT: case SIOCDELRT:
if (!capable(CAP_NET_ADMIN)) return -EPERM; rc = -EPERM;
return x25_route_ioctl(cmd, (void *)arg); if (!capable(CAP_NET_ADMIN))
break;
rc = x25_route_ioctl(cmd, (void *)arg);
break;
case SIOCX25GSUBSCRIP: case SIOCX25GSUBSCRIP:
return x25_subscr_ioctl(cmd, (void *)arg); rc = x25_subscr_ioctl(cmd, (void *)arg);
break;
case SIOCX25SSUBSCRIP: case SIOCX25SSUBSCRIP:
if (!capable(CAP_NET_ADMIN)) return -EPERM; rc = -EPERM;
return x25_subscr_ioctl(cmd, (void *)arg); if (!capable(CAP_NET_ADMIN))
break;
rc = x25_subscr_ioctl(cmd, (void *)arg);
break;
case SIOCX25GFACILITIES: { case SIOCX25GFACILITIES: {
struct x25_facilities facilities; struct x25_facilities fac = x25->facilities;
facilities = x25->facilities; rc = copy_to_user((void *)arg, &fac, sizeof(fac)) ? -EFAULT : 0;
return copy_to_user((void *)arg, &facilities, sizeof(facilities)) ? -EFAULT : 0; break;
} }
case SIOCX25SFACILITIES: { case SIOCX25SFACILITIES: {
struct x25_facilities facilities; struct x25_facilities facilities;
rc = -EFAULT;
if (copy_from_user(&facilities, (void *)arg, sizeof(facilities))) if (copy_from_user(&facilities, (void *)arg, sizeof(facilities)))
return -EFAULT; break;
rc = -EINVAL;
if (sk->state != TCP_LISTEN && sk->state != TCP_CLOSE) if (sk->state != TCP_LISTEN && sk->state != TCP_CLOSE)
return -EINVAL; break;
if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096) if (facilities.pacsize_in < X25_PS16 ||
return -EINVAL; facilities.pacsize_in > X25_PS4096)
if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096) break;
return -EINVAL; if (facilities.pacsize_out < X25_PS16 ||
if (facilities.winsize_in < 1 || facilities.winsize_in > 127) facilities.pacsize_out > X25_PS4096)
return -EINVAL; break;
if (facilities.throughput < 0x03 || facilities.throughput > 0xDD) if (facilities.winsize_in < 1 ||
return -EINVAL; facilities.winsize_in > 127)
if (facilities.reverse != 0 && facilities.reverse != 1) break;
return -EINVAL; if (facilities.throughput < 0x03 ||
facilities.throughput > 0xDD)
break;
if (facilities.reverse && facilities.reverse != 1)
break;
x25->facilities = facilities; x25->facilities = facilities;
return 0; rc = 0;
break;
} }
case SIOCX25GCALLUSERDATA: { case SIOCX25GCALLUSERDATA: {
struct x25_calluserdata calluserdata; struct x25_calluserdata cud = x25->calluserdata;
calluserdata = x25->calluserdata; rc = copy_to_user((void *)arg, &cud, sizeof(cud)) ? -EFAULT : 0;
return copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata)) ? -EFAULT : 0; break;
} }
case SIOCX25SCALLUSERDATA: { case SIOCX25SCALLUSERDATA: {
struct x25_calluserdata calluserdata; struct x25_calluserdata calluserdata;
rc = -EFAULT;
if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata))) if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata)))
return -EFAULT; break;
rc = -EINVAL;
if (calluserdata.cudlength > X25_MAX_CUD_LEN) if (calluserdata.cudlength > X25_MAX_CUD_LEN)
return -EINVAL; break;
x25->calluserdata = calluserdata; x25->calluserdata = calluserdata;
return 0; rc = 0;
break;
} }
case SIOCX25GCAUSEDIAG: { case SIOCX25GCAUSEDIAG: {
struct x25_causediag causediag; struct x25_causediag causediag;
causediag = x25->causediag; causediag = x25->causediag;
return copy_to_user((void *)arg, &causediag, sizeof(causediag)) ? -EFAULT : 0; rc = copy_to_user((void *)arg, &causediag, sizeof(causediag)) ? -EFAULT : 0;
break;
} }
default: default:
return dev_ioctl(cmd, (void *)arg); rc = dev_ioctl(cmd, (void *)arg);
break;
} }
/*NOTREACHED*/ return rc;
return 0;
} }
static int x25_get_info(char *buffer, char **start, off_t offset, int length) static int x25_get_info(char *buffer, char **start, off_t offset, int length)
...@@ -1220,15 +1256,16 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1220,15 +1256,16 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length)
struct sock *s; struct sock *s;
struct net_device *dev; struct net_device *dev;
const char *devname; const char *devname;
int len = 0; int len;
off_t pos = 0; off_t pos = 0;
off_t begin = 0; off_t begin = 0;
cli(); cli();
len += sprintf(buffer, "dest_addr src_addr dev lci st vs vr va t t2 t21 t22 t23 Snd-Q Rcv-Q inode\n"); len = sprintf(buffer, "dest_addr src_addr dev lci st vs vr va "
"t t2 t21 t22 t23 Snd-Q Rcv-Q inode\n");
for (s = x25_list; s != NULL; s = s->next) { for (s = x25_list; s; s = s->next) {
x25_cb *x25 = x25_sk(s); x25_cb *x25 = x25_sk(s);
if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL) if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL)
...@@ -1236,7 +1273,9 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1236,7 +1273,9 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length)
else else
devname = x25->neighbour->dev->name; devname = x25->neighbour->dev->name;
len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X %d %d %d %d %3lu %3lu %3lu %3lu %3lu %5d %5d %ld\n", len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X %d %d "
"%d %d %3lu %3lu %3lu %3lu %3lu "
"%5d %5d %ld\n",
!x25->dest_addr.x25_addr[0] ? "*" : !x25->dest_addr.x25_addr[0] ? "*" :
x25->dest_addr.x25_addr, x25->dest_addr.x25_addr,
!x25->source_addr.x25_addr[0] ? "*" : !x25->source_addr.x25_addr[0] ? "*" :
...@@ -1254,7 +1293,7 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1254,7 +1293,7 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length)
x25->t23 / HZ, x25->t23 / HZ,
atomic_read(&s->wmem_alloc), atomic_read(&s->wmem_alloc),
atomic_read(&s->rmem_alloc), atomic_read(&s->rmem_alloc),
s->socket != NULL ? SOCK_INODE(s->socket)->i_ino : 0L); s->socket ? SOCK_INODE(s->socket)->i_ino : 0L);
pos = begin + len; pos = begin + len;
...@@ -1272,9 +1311,10 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1272,9 +1311,10 @@ static int x25_get_info(char *buffer, char **start, off_t offset, int length)
*start = buffer + (offset - begin); *start = buffer + (offset - begin);
len -= (offset - begin); len -= (offset - begin);
if (len > length) len = length; if (len > length)
len = length;
return(len); return len;
} }
struct net_proto_family x25_family_ops = { struct net_proto_family x25_family_ops = {
...@@ -1313,17 +1353,16 @@ static struct packet_type x25_packet_type = { ...@@ -1313,17 +1353,16 @@ static struct packet_type x25_packet_type = {
}; };
struct notifier_block x25_dev_notifier = { struct notifier_block x25_dev_notifier = {
.notifier_call =x25_device_event, .notifier_call = x25_device_event,
}; };
void x25_kill_by_neigh(struct x25_neigh *neigh) void x25_kill_by_neigh(struct x25_neigh *neigh)
{ {
struct sock *s; struct sock *s;
for( s=x25_list; s != NULL; s=s->next){ for (s = x25_list; s; s = s->next)
if (x25_sk(s)->neighbour == neigh) if (x25_sk(s)->neighbour == neigh)
x25_disconnect(s, ENETUNREACH, 0, 0); x25_disconnect(s, ENETUNREACH, 0, 0);
}
} }
static int __init x25_init(void) static int __init x25_init(void)
...@@ -1351,7 +1390,7 @@ static int __init x25_init(void) ...@@ -1351,7 +1390,7 @@ static int __init x25_init(void)
* Register any pre existing devices. * Register any pre existing devices.
*/ */
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for (dev = dev_base; dev != NULL; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25 if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25
#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
|| dev->type == ARPHRD_ETHER || dev->type == ARPHRD_ETHER
......
...@@ -98,7 +98,7 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) ...@@ -98,7 +98,7 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
*/ */
static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{ {
x25_address source_addr, dest_addr; struct x25_address source_addr, dest_addr;
switch (frametype) { switch (frametype) {
case X25_CALL_ACCEPTED: { case X25_CALL_ACCEPTED: {
......
...@@ -48,7 +48,8 @@ static struct x25_route *x25_route_list /* = NULL initially */; ...@@ -48,7 +48,8 @@ static struct x25_route *x25_route_list /* = NULL initially */;
/* /*
* Add a new route. * Add a new route.
*/ */
static int x25_add_route(x25_address *address, unsigned int sigdigits, struct net_device *dev) static int x25_add_route(struct x25_address *address, unsigned int sigdigits,
struct net_device *dev)
{ {
struct x25_route *x25_route; struct x25_route *x25_route;
unsigned long flags; unsigned long flags;
...@@ -103,7 +104,8 @@ static void x25_remove_route(struct x25_route *x25_route) ...@@ -103,7 +104,8 @@ static void x25_remove_route(struct x25_route *x25_route)
restore_flags(flags); restore_flags(flags);
} }
static int x25_del_route(x25_address *address, unsigned int sigdigits, struct net_device *dev) static int x25_del_route(struct x25_address *address, unsigned int sigdigits,
struct net_device *dev)
{ {
struct x25_route *x25_route; struct x25_route *x25_route;
...@@ -158,7 +160,7 @@ struct net_device *x25_dev_get(char *devname) ...@@ -158,7 +160,7 @@ struct net_device *x25_dev_get(char *devname)
/* /*
* Find a device given an X.25 address. * Find a device given an X.25 address.
*/ */
struct net_device *x25_get_route(x25_address *addr) struct net_device *x25_get_route(struct x25_address *addr)
{ {
struct x25_route *route, *use = NULL; struct x25_route *route, *use = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment