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

📄 sm_statefuns.c

📁 一种在UDP协议中实现了拥赛控制和重传机制的协议
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	if (asoc->peer.adaption_ind) {		ev = sctp_ulpevent_make_adaption_indication(asoc, GFP_ATOMIC);		if (!ev)			goto nomem;		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,				SCTP_ULPEVENT(ev));	}	return SCTP_DISPOSITION_CONSUME;nomem:	return SCTP_DISPOSITION_NOMEM;}/* Generate and sendout a heartbeat packet.  */static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,					    const struct sctp_association *asoc,					    const sctp_subtype_t type,					    void *arg,					    sctp_cmd_seq_t *commands){	struct sctp_transport *transport = (struct sctp_transport *) arg;	struct sctp_chunk *reply;	sctp_sender_hb_info_t hbinfo;	size_t paylen = 0;	hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO;	hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t));	hbinfo.daddr = transport->ipaddr;	hbinfo.sent_at = jiffies;	/* Send a heartbeat to our peer.  */	paylen = sizeof(sctp_sender_hb_info_t);	reply = sctp_make_heartbeat(asoc, transport, &hbinfo, paylen);	if (!reply)		return SCTP_DISPOSITION_NOMEM;	/* Set rto_pending indicating that an RTT measurement	 * is started with this heartbeat chunk.	 */	sctp_add_cmd_sf(commands, SCTP_CMD_RTO_PENDING,			SCTP_TRANSPORT(transport));	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));	return SCTP_DISPOSITION_CONSUME;}/* Generate a HEARTBEAT packet on the given transport.  */sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,					const struct sctp_association *asoc,					const sctp_subtype_t type,					void *arg,					sctp_cmd_seq_t *commands){	struct sctp_transport *transport = (struct sctp_transport *) arg;	if (asoc->overall_error_count > asoc->max_retrans) {		/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,				SCTP_U32(SCTP_ERROR_NO_ERROR));		SCTP_INC_STATS(SCTP_MIB_ABORTEDS);		SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);		return SCTP_DISPOSITION_DELETE_TCB;	}	/* Section 3.3.5.	 * The Sender-specific Heartbeat Info field should normally include	 * information about the sender's current time when this HEARTBEAT	 * chunk is sent and the destination transport address to which this	 * HEARTBEAT is sent (see Section 8.3).	 */	if (transport->hb_allowed) {		if (SCTP_DISPOSITION_NOMEM ==				sctp_sf_heartbeat(ep, asoc, type, arg,						  commands))			return SCTP_DISPOSITION_NOMEM;		/* Set transport error counter and association error counter		 * when sending heartbeat.		 */		sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET,				SCTP_TRANSPORT(transport));	}	sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMER_UPDATE,			SCTP_TRANSPORT(transport));        return SCTP_DISPOSITION_CONSUME;}/* * Process an heartbeat request. * * Section: 8.3 Path Heartbeat * The receiver of the HEARTBEAT should immediately respond with a * HEARTBEAT ACK that contains the Heartbeat Information field copied * from the received HEARTBEAT chunk. * * Verification Tag:  8.5 Verification Tag [Normal verification] * 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 and shall not process it any further except for * those cases listed in Section 8.5.1 below. * * 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_beat_8_3(const struct sctp_endpoint *ep,				    const struct sctp_association *asoc,				    const sctp_subtype_t type,				    void *arg,				    sctp_cmd_seq_t *commands){	struct sctp_chunk *chunk = arg;	struct sctp_chunk *reply;	size_t paylen = 0;	if (!sctp_vtag_verify(chunk, asoc))		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);	/* Make sure that the HEARTBEAT chunk has a valid length. */	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))		return sctp_sf_violation_chunklen(ep, asoc, type, arg,						  commands);	/* 8.3 The receiver of the HEARTBEAT should immediately	 * respond with a HEARTBEAT ACK that contains the Heartbeat	 * Information field copied from the received HEARTBEAT chunk.	 */	chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data;	paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t);	skb_pull(chunk->skb, paylen);	reply = sctp_make_heartbeat_ack(asoc, chunk,					chunk->subh.hb_hdr, paylen);	if (!reply)		goto nomem;	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));	return SCTP_DISPOSITION_CONSUME;nomem:	return SCTP_DISPOSITION_NOMEM;}/* * Process the returning HEARTBEAT ACK. * * Section: 8.3 Path Heartbeat * 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, and mark the destination * transport address as active if it is not so marked. The endpoint may * optionally report to the upper layer when an inactive destination * address is marked as active due to the reception of the latest * HEARTBEAT ACK. The receiver of the HEARTBEAT ACK must also * clear the association overall error count as well (as defined * in section 8.1). * * 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. * * Verification Tag:  8.5 Verification Tag [Normal verification] * * 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_backbeat_8_3(const struct sctp_endpoint *ep,					const struct sctp_association *asoc,					const sctp_subtype_t type,					void *arg,					sctp_cmd_seq_t *commands){	struct sctp_chunk *chunk = arg;	union sctp_addr from_addr;	struct sctp_transport *link;	sctp_sender_hb_info_t *hbinfo;	unsigned long max_interval;	if (!sctp_vtag_verify(chunk, asoc))		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);	/* Make sure that the HEARTBEAT-ACK chunk has a valid length.  */	if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))		return sctp_sf_violation_chunklen(ep, asoc, type, arg,						  commands);	hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;	from_addr = hbinfo->daddr;	link = sctp_assoc_lookup_paddr(asoc, &from_addr);	/* This should never happen, but lets log it if so.  */	if (!link) {		printk(KERN_WARNING		       "%s: Could not find address %d.%d.%d.%d\n",		       __FUNCTION__, NIPQUAD(from_addr.v4.sin_addr));		return SCTP_DISPOSITION_DISCARD;	}	max_interval = link->hb_interval + link->rto;	/* Check if the timestamp looks valid.  */	if (time_after(hbinfo->sent_at, jiffies) ||	    time_after(jiffies, hbinfo->sent_at + max_interval)) {		SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp"				  "received for transport: %p\n",				   __FUNCTION__, link);		return SCTP_DISPOSITION_DISCARD;	}	/* 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 and mark the destination transport address as active if	 * it is not so marked.	 */	sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_ON, SCTP_TRANSPORT(link));	return SCTP_DISPOSITION_CONSUME;}/* Helper function to send out an abort for the restart * condition. */static int sctp_sf_send_restart_abort(union sctp_addr *ssa,				      struct sctp_chunk *init,				      sctp_cmd_seq_t *commands){	int len;	struct sctp_packet *pkt;	union sctp_addr_param *addrparm;	struct sctp_errhdr *errhdr;	struct sctp_endpoint *ep;	char buffer[sizeof(struct sctp_errhdr)+sizeof(union sctp_addr_param)];	struct sctp_af *af = sctp_get_af_specific(ssa->v4.sin_family);	/* Build the error on the stack.   We are way to malloc crazy	 * throughout the code today.	 */	errhdr = (struct sctp_errhdr *)buffer;	addrparm = (union sctp_addr_param *)errhdr->variable;	/* Copy into a parm format. */	len = af->to_addr_param(ssa, addrparm);	len += sizeof(sctp_errhdr_t);	errhdr->cause = SCTP_ERROR_RESTART;	errhdr->length = htons(len);	/* Assign to the control socket. */	ep = sctp_sk((sctp_get_ctl_sock()))->ep;	/* Association is NULL since this may be a restart attack and we	 * want to send back the attacker's vtag.	 */	pkt = sctp_abort_pkt_new(ep, NULL, init, errhdr, len);	if (!pkt)		goto out;	sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(pkt));	SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);	/* Discard the rest of the inbound packet. */	sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());out:	/* Even if there is no memory, treat as a failure so	 * the packet will get dropped.	 */	return 0;}/* A restart is occurring, check to make sure no new addresses * are being added as we may be under a takeover attack. */static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc,				       const struct sctp_association *asoc,				       struct sctp_chunk *init,				       sctp_cmd_seq_t *commands){	struct sctp_transport *new_addr, *addr;	struct list_head *pos, *pos2;	int found;	/* Implementor's Guide - Sectin 5.2.2	 * ...	 * Before responding the endpoint MUST check to see if the	 * unexpected INIT adds new addresses to the association. If new	 * addresses are added to the association, the endpoint MUST respond	 * with an ABORT..	 */	/* Search through all current addresses and make sure	 * we aren't adding any new ones.	 */	new_addr = NULL;	found = 0;	list_for_each(pos, &new_asoc->peer.transport_addr_list) {		new_addr = list_entry(pos, struct sctp_transport, transports);		found = 0;		list_for_each(pos2, &asoc->peer.transport_addr_list) {			addr = list_entry(pos2, struct sctp_transport,					  transports);			if (sctp_cmp_addr_exact(&new_addr->ipaddr,						&addr->ipaddr)) {				found = 1;				break;			}		}		if (!found)			break;	}	/* If a new address was added, ABORT the sender. */	if (!found && new_addr) {		sctp_sf_send_restart_abort(&new_addr->ipaddr, init, commands);	}	/* Return success if all addresses were found. */	return found;}/* Populate the verification/tie tags based on overlapping INIT * scenario. * * Note: Do not use in CLOSED or SHUTDOWN-ACK-SENT state. */static void sctp_tietags_populate(struct sctp_association *new_asoc,				  const struct sctp_association *asoc){	switch (asoc->state) {	/* 5.2.1 INIT received in COOKIE-WAIT or COOKIE-ECHOED State */	case SCTP_STATE_COOKIE_WAIT:		new_asoc->c.my_vtag     = asoc->c.my_vtag;		new_asoc->c.my_ttag     = asoc->c.my_vtag;		new_asoc->c.peer_ttag   = 0;		break;	case SCTP_STATE_COOKIE_ECHOED:		new_asoc->c.my_vtag     = asoc->c.my_vtag;		new_asoc->c.my_ttag     = asoc->c.my_vtag;		new_asoc->c.peer_ttag   = asoc->c.peer_vtag;		break;	/* 5.2.2 Unexpected INIT in States Other than CLOSED, COOKIE-ECHOED,	 * COOKIE-WAIT and SHUTDOWN-ACK-SENT	 */	default:		new_asoc->c.my_ttag   = asoc->c.my_vtag;		new_asoc->c.peer_ttag = asoc->c.peer_vtag;		break;	};	/* Other parameters for the endpoint SHOULD be copied from the	 * existing parameters of the association (e.g. number of	 * outbound streams) into the INIT ACK and cookie.	 */	new_asoc->rwnd                  = asoc->rwnd;	new_asoc->c.sinit_num_ostreams  = asoc->c.sinit_num_ostreams;	new_asoc->c.sinit_max_instreams = asoc->c.sinit_max_instreams;	new_asoc->c.initial_tsn         = asoc->c.initial_tsn;}/* * Compare vtag/tietag values to determine unexpected COOKIE-ECHO * handling action. * * RFC 2960 5.2.4 Handle a COOKIE ECHO when a TCB exists. * * Returns value representing action to be taken.   These action values * correspond to Action/Description values in RFC 2960, Table 2. */static char sctp_tietags_compare(struct sctp_association *new_asoc,				 const struct sctp_association *asoc){	/* In this case, the peer may have restarted.  */	if ((asoc->c.my_vtag != new_asoc->c.my_vtag) &&	    (asoc->c.peer_vtag != new_asoc->c.peer_vtag) &&	    (asoc->c.my_vtag == new_asoc->c.my_ttag) &&	    (asoc->c.peer_vtag == new_asoc->c.peer_ttag))		return 'A';	/* Collision case B. */	if ((asoc->c.my_vtag == new_asoc->c.my_vtag) &&	    ((asoc->c.peer_vtag != new_asoc->c.peer_vtag) ||	     (0 == asoc->c.peer_vtag))) {		return 'B';	}	/* Collision case D. */	if ((asoc->c.my_vtag == new_asoc->c.my_vtag) &&

⌨️ 快捷键说明

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