⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sm_sideeffect.c

📁 在linux环境下的流控制传输协议(sctp)的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
				 struct sctp_association *asoc,				 struct sctp_chunk *chunk,				 sctp_init_chunk_t *peer_init,				 gfp_t gfp){	int error;	/* We only process the init as a sideeffect in a single	 * case.   This is when we process the INIT-ACK.   If we	 * fail during INIT processing (due to malloc problems),	 * just return the error and stop processing the stack.	 */	if (!sctp_process_init(asoc, chunk->chunk_hdr->type,			       sctp_source(chunk), peer_init, gfp))		error = -ENOMEM;	else		error = 0;	return error;}/* Helper function to break out starting up of heartbeat timers.  */static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,				     struct sctp_association *asoc){	struct sctp_transport *t;	struct list_head *pos;	/* Start a heartbeat timer for each transport on the association.	 * hold a reference on the transport to make sure none of	 * the needed data structures go away.	 */	list_for_each(pos, &asoc->peer.transport_addr_list) {		t = list_entry(pos, struct sctp_transport, transports);		if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t)))			sctp_transport_hold(t);	}}static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,				    struct sctp_association *asoc){	struct sctp_transport *t;	struct list_head *pos;	/* Stop all heartbeat timers. */	list_for_each(pos, &asoc->peer.transport_addr_list) {		t = list_entry(pos, struct sctp_transport, transports);		if (del_timer(&t->hb_timer))			sctp_transport_put(t);	}}/* Helper function to stop any pending T3-RTX timers */static void sctp_cmd_t3_rtx_timers_stop(sctp_cmd_seq_t *cmds,					struct sctp_association *asoc){	struct sctp_transport *t;	struct list_head *pos;	list_for_each(pos, &asoc->peer.transport_addr_list) {		t = list_entry(pos, struct sctp_transport, transports);		if (timer_pending(&t->T3_rtx_timer) &&		    del_timer(&t->T3_rtx_timer)) {			sctp_transport_put(t);		}	}}/* Helper function to update the heartbeat timer. */static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,				     struct sctp_association *asoc,				     struct sctp_transport *t){	/* Update the heartbeat timer.  */	if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t)))		sctp_transport_hold(t);}/* Helper function to handle the reception of an HEARTBEAT ACK.  */static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,				  struct sctp_association *asoc,				  struct sctp_transport *t,				  struct sctp_chunk *chunk){	sctp_sender_hb_info_t *hbinfo;	/* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the	 * HEARTBEAT should clear the error counter of the destination	 * transport address to which the HEARTBEAT was sent.	 * The association's overall error count is also cleared.	 */	t->error_count = 0;	t->asoc->overall_error_count = 0;	/* Mark the destination transport address as active if it is not so	 * marked.	 */	if ((t->state == SCTP_INACTIVE) || (t->state == SCTP_UNCONFIRMED))		sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,					     SCTP_HEARTBEAT_SUCCESS);	/* The receiver of the HEARTBEAT ACK should also perform an	 * RTT measurement for that destination transport address	 * using the time value carried in the HEARTBEAT ACK chunk.	 * If the transport's rto_pending variable has been cleared,	 * it was most likely due to a retransmit.  However, we want	 * to re-enable it to properly update the rto.	 */	if (t->rto_pending == 0)		t->rto_pending = 1;	hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;	sctp_transport_update_rto(t, (jiffies - hbinfo->sent_at));	/* Update the heartbeat timer.  */	if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t)))		sctp_transport_hold(t);}/* Helper function to do a transport reset at the expiry of the hearbeat * timer. */static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,				     struct sctp_association *asoc,				     struct sctp_transport *t){	sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE);	/* Mark one strike against a transport.  */	sctp_do_8_2_transport_strike(asoc, t);}/* Helper function to process the process SACK command.  */static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,				 struct sctp_association *asoc,				 struct sctp_sackhdr *sackh){	int err;	if (sctp_outq_sack(&asoc->outqueue, sackh)) {		/* There are no more TSNs awaiting SACK.  */		err = sctp_do_sm(SCTP_EVENT_T_OTHER,				 SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN),				 asoc->state, asoc->ep, asoc, NULL,				 GFP_ATOMIC);	} else {		/* Windows may have opened, so we need		 * to check if we have DATA to transmit		 */		err = sctp_outq_flush(&asoc->outqueue, 0);	}	return err;}/* Helper function to set the timeout value for T2-SHUTDOWN timer and to set * the transport for a shutdown chunk. */static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,			      struct sctp_association *asoc,			      struct sctp_chunk *chunk){	struct sctp_transport *t;	t = sctp_assoc_choose_shutdown_transport(asoc);	asoc->shutdown_last_sent_to = t;	asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;	chunk->transport = t;}/* Helper function to change the state of an association. */static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds,			       struct sctp_association *asoc,			       sctp_state_t state){	struct sock *sk = asoc->base.sk;	asoc->state = state;	SCTP_DEBUG_PRINTK("sctp_cmd_new_state: asoc %p[%s]\n",			  asoc, sctp_state_tbl[state]);	if (sctp_style(sk, TCP)) {		/* Change the sk->sk_state of a TCP-style socket that has		 * sucessfully completed a connect() call.		 */		if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED))			sk->sk_state = SCTP_SS_ESTABLISHED;		/* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */		if (sctp_state(asoc, SHUTDOWN_RECEIVED) &&		    sctp_sstate(sk, ESTABLISHED))			sk->sk_shutdown |= RCV_SHUTDOWN;	}	if (sctp_state(asoc, COOKIE_WAIT)) {		/* Reset init timeouts since they may have been		 * increased due to timer expirations.		 */		asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =						asoc->rto_initial;		asoc->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] =						asoc->rto_initial;	}	if (sctp_state(asoc, ESTABLISHED) ||	    sctp_state(asoc, CLOSED) ||	    sctp_state(asoc, SHUTDOWN_RECEIVED)) {		/* Wake up any processes waiting in the asoc's wait queue in		 * sctp_wait_for_connect() or sctp_wait_for_sndbuf().		 */		if (waitqueue_active(&asoc->wait))			wake_up_interruptible(&asoc->wait);		/* Wake up any processes waiting in the sk's sleep queue of		 * a TCP-style or UDP-style peeled-off socket in		 * sctp_wait_for_accept() or sctp_wait_for_packet().		 * For a UDP-style socket, the waiters are woken up by the		 * notifications.		 */		if (!sctp_style(sk, UDP))			sk->sk_state_change(sk);	}}/* Helper function to delete an association. */static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds,				struct sctp_association *asoc){	struct sock *sk = asoc->base.sk;	/* If it is a non-temporary association belonging to a TCP-style	 * listening socket that is not closed, do not free it so that accept()	 * can pick it up later.	 */	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) &&	    (!asoc->temp) && (sk->sk_shutdown != SHUTDOWN_MASK))		return;	sctp_unhash_established(asoc);	sctp_association_free(asoc);}/* * ADDIP Section 4.1 ASCONF Chunk Procedures * A4) Start a T-4 RTO timer, using the RTO value of the selected * destination address (we use active path instead of primary path just * because primary path may be inactive. */static void sctp_cmd_setup_t4(sctp_cmd_seq_t *cmds,				struct sctp_association *asoc,				struct sctp_chunk *chunk){	struct sctp_transport *t;	t = asoc->peer.active_path;	asoc->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = t->rto;	chunk->transport = t;}/* Process an incoming Operation Error Chunk. */static void sctp_cmd_process_operr(sctp_cmd_seq_t *cmds,				   struct sctp_association *asoc,				   struct sctp_chunk *chunk){	struct sctp_operr_chunk *operr_chunk;	struct sctp_errhdr *err_hdr;	operr_chunk = (struct sctp_operr_chunk *)chunk->chunk_hdr;	err_hdr = &operr_chunk->err_hdr;	switch (err_hdr->cause) {	case SCTP_ERROR_UNKNOWN_CHUNK:	{		struct sctp_chunkhdr *unk_chunk_hdr;		unk_chunk_hdr = (struct sctp_chunkhdr *)err_hdr->variable;		switch (unk_chunk_hdr->type) {		/* ADDIP 4.1 A9) If the peer responds to an ASCONF with an		 * ERROR chunk reporting that it did not recognized the ASCONF		 * chunk type, the sender of the ASCONF MUST NOT send any		 * further ASCONF chunks and MUST stop its T-4 timer.		 */		case SCTP_CID_ASCONF:			asoc->peer.asconf_capable = 0;			sctp_add_cmd_sf(cmds, SCTP_CMD_TIMER_STOP,					SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));			break;		default:			break;		}		break;	}	default:		break;	}}/* Process variable FWDTSN chunk information. */static void sctp_cmd_process_fwdtsn(struct sctp_ulpq *ulpq,				    struct sctp_chunk *chunk){	struct sctp_fwdtsn_skip *skip;	/* Walk through all the skipped SSNs */	sctp_walk_fwdtsn(skip, chunk) {		sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn));	}	return;}/* Helper function to remove the association non-primary peer * transports. */static void sctp_cmd_del_non_primary(struct sctp_association *asoc){	struct sctp_transport *t;	struct list_head *pos;	struct list_head *temp;	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {		t = list_entry(pos, struct sctp_transport, transports);		if (!sctp_cmp_addr_exact(&t->ipaddr,					 &asoc->peer.primary_addr)) {			sctp_assoc_del_peer(asoc, &t->ipaddr);		}	}	return;}/* Helper function to set sk_err on a 1-1 style socket. */static void sctp_cmd_set_sk_err(struct sctp_association *asoc, int error){	struct sock *sk = asoc->base.sk;	if (!sctp_style(sk, UDP))		sk->sk_err = error;}/* Helper function to generate an association change event */static void sctp_cmd_assoc_change(sctp_cmd_seq_t *commands,				 struct sctp_association *asoc,				 u8 state){	struct sctp_ulpevent *ev;	ev = sctp_ulpevent_make_assoc_change(asoc, 0, state, 0,					    asoc->c.sinit_num_ostreams,					    asoc->c.sinit_max_instreams,					    NULL, GFP_ATOMIC);	if (ev)		sctp_ulpq_tail_event(&asoc->ulpq, ev);}/* Helper function to generate an adaptation indication event */static void sctp_cmd_adaptation_ind(sctp_cmd_seq_t *commands,				    struct sctp_association *asoc){	struct sctp_ulpevent *ev;	ev = sctp_ulpevent_make_adaptation_indication(asoc, GFP_ATOMIC);	if (ev)		sctp_ulpq_tail_event(&asoc->ulpq, ev);}/* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real * functionality there. */#define DEBUG_PRE \	SCTP_DEBUG_PRINTK("sctp_do_sm prefn: " \			  "ep %p, %s, %s, asoc %p[%s], %s\n", \			  ep, sctp_evttype_tbl[event_type], \			  (*debug_fn)(subtype), asoc, \			  sctp_state_tbl[state], state_fn->name)#define DEBUG_POST \	SCTP_DEBUG_PRINTK("sctp_do_sm postfn: " \			  "asoc %p, status: %s\n", \			  asoc, sctp_status_tbl[status])#define DEBUG_POST_SFX \	SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \			  error, asoc, \			  sctp_state_tbl[(asoc && sctp_id2assoc(ep->base.sk, \			  sctp_assoc2id(asoc)))?asoc->state:SCTP_STATE_CLOSED])/* * This is the master state machine processing function. * * If you want to understand all of lksctp, this is a * good place to start. */int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,	       sctp_state_t state,	       struct sctp_endpoint *ep,	       struct sctp_association *asoc,	       void *event_arg,	       gfp_t gfp){	sctp_cmd_seq_t commands;	const sctp_sm_table_entry_t *state_fn;	sctp_disposition_t status;	int error = 0;	typedef const char *(printfn_t)(sctp_subtype_t);	static printfn_t *table[] = {		NULL, sctp_cname, sctp_tname, sctp_oname, sctp_pname,	};	printfn_t *debug_fn  __attribute__ ((unused)) = table[event_type];	/* Look up the state function, run it, and then process the	 * side effects.  These three steps are the heart of lksctp.	 */	state_fn = sctp_sm_lookup_event(event_type, state, subtype);	sctp_init_cmd_seq(&commands);	DEBUG_PRE;	status = (*state_fn->fn)(ep, asoc, subtype, event_arg, &commands);	DEBUG_POST;	error = sctp_side_effects(event_type, subtype, state,				  ep, asoc, event_arg, status,				  &commands, gfp);	DEBUG_POST_SFX;	return error;}#undef DEBUG_PRE#undef DEBUG_POST/***************************************************************** * This the master state function side effect processing function. *****************************************************************/static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,			     sctp_state_t state,			     struct sctp_endpoint *ep,			     struct sctp_association *asoc,			     void *event_arg,			     sctp_disposition_t status,			     sctp_cmd_seq_t *commands,			     gfp_t gfp){	int error;	/* FIXME - Most of the dispositions left today would be categorized	 * as "exceptional" dispositions.  For those dispositions, it	 * may not be proper to run through any of the commands at all.	 * For example, the command interpreter might be run only with	 * disposition SCTP_DISPOSITION_CONSUME.	 */	if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state,					       ep, asoc,					       event_arg, status,					       commands, gfp)))		goto bail;	switch (status) {	case SCTP_DISPOSITION_DISCARD:		SCTP_DEBUG_PRINTK("Ignored sctp protocol event - state %d, "				  "event_type %d, event_id %d\n",				  state, event_type, subtype.chunk);		break;	case SCTP_DISPOSITION_NOMEM:		/* We ran out of memory, so we need to discard this		 * packet.		 */		/* BUG--we should now recover some memory, probably by		 * reneging...		 */		error = -ENOMEM;		break;	case SCTP_DISPOSITION_DELETE_TCB:		/* This should now be a command. */		break;	case SCTP_DISPOSITION_CONSUME:	case SCTP_DISPOSITION_ABORT:		/*		 * We should no longer have much work to do here as the		 * real work has been done as explicit commands above.		 */		break;	case SCTP_DISPOSITION_VIOLATION:		if (net_ratelimit())			printk(KERN_ERR "sctp protocol violation state %d "			       "chunkid %d\n", state, subtype.chunk);		break;	case SCTP_DISPOSITION_NOT_IMPL:		printk(KERN_WARNING "sctp unimplemented feature in state %d, "		       "event_type %d, event_id %d\n",		       state, event_type, subtype.chunk);		break;	case SCTP_DISPOSITION_BUG:		printk(KERN_ERR "sctp bug in state %d, "		       "event_type %d, event_id %d\n",		       state, event_type, subtype.chunk);		BUG();		break;	default:		printk(KERN_ERR "sctp impossible disposition %d "		       "in state %d, event_type %d, event_id %d\n",		       status, state, event_type, subtype.chunk);		BUG();		break;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -