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

📄 sm_statefuns.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	struct sctp_chunk *reply;	size_t paylen = 0;	if (!sctp_vtag_verify(chunk, asoc))		return sctp_sf_pdiscard(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);	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) &&	    (asoc->c.peer_vtag == new_asoc->c.peer_vtag))		return 'D';	/* Collision case C. */	if ((asoc->c.my_vtag != new_asoc->c.my_vtag) &&	    (asoc->c.peer_vtag == new_asoc->c.peer_vtag) &&	    (0 == new_asoc->c.my_ttag) &&	    (0 == new_asoc->c.peer_ttag))		return 'C';	/* No match to any of the special cases; discard this packet. */	return 'E';}/* Common helper routine for both duplicate and simulataneous INIT * chunk handling. */static sctp_disposition_t sctp_sf_do_unexpected_init(	const struct sctp_endpoint *ep,	const struct sctp_association *asoc,	const sctp_subtype_t type,	void *arg, sctp_cmd_seq_t *commands){	sctp_disposition_t retval;	struct sctp_chunk *chunk = arg;	struct sctp_chunk *repl;	struct sctp_association *new_asoc;	struct sctp_chunk *err_chunk;	struct sctp_packet *packet;	sctp_unrecognized_param_t *unk_param;	int len;	/* 6.10 Bundling	 * An endpoint MUST NOT bundle INIT, INIT ACK or	 * SHUTDOWN COMPLETE with any other chunks.	 */	if (!chunk->singleton)		return SCTP_DISPOSITION_VIOLATION;	/* 3.1 A packet containing an INIT chunk MUST have a zero Verification	 * Tag. 	 */	if (chunk->sctp_hdr->vtag != 0)		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);	/* Grab the INIT header.  */	chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;	/* Tag the variable length parameters.  */	chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t));	/* Verify the INIT chunk before processing it. */	err_chunk = NULL;	if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,			      (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,			      &err_chunk)) {		/* This chunk contains fatal error. It is to be discarded.		 * Send an ABORT, with causes if there is any.		 */		if (err_chunk) {			packet = sctp_abort_pkt_new(ep, asoc, arg,					(__u8 *)(err_chunk->chunk_hdr) +					sizeof(sctp_chunkhdr_t),					ntohs(err_chunk->chunk_hdr->length) -					sizeof(sctp_chunkhdr_t));			if (packet) {				sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,						SCTP_PACKET(packet));				SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);				retval = SCTP_DISPOSITION_CONSUME;			} else {				retval = SCTP_DISPOSITION_NOMEM;			}			goto cleanup;		} else {			return sctp_sf_tabort_8_4_8(ep, asoc, type, arg,						    commands);		}	}	/*	 * 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.	 * FIXME:  We are copying parameters from the endpoint not the	 * association.	 */	new_asoc = sctp_make_temp_asoc(ep, chunk, GFP_ATOMIC);	if (!new_asoc)		goto nomem;	/* In the outbound INIT ACK the endpoint MUST copy its current	 * Verification Tag and Peers Verification tag into a reserved	 * place (local tie-tag and per tie-tag) within the state cookie.	 */	if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,			       sctp_source(chunk),			       (sctp_init_chunk_t *)chunk->chunk_hdr,			       GFP_ATOMIC)) {		retval = SCTP_DISPOSITION_NOMEM;		goto nomem_init;	}	/* Make sure no new addresses are being added during the	 * restart.   Do not do this check for COOKIE-WAIT state,	 * since there are no peer addresses to check against.	 * Upon return an ABORT will have been sent if needed.	 */	if (!sctp_state(asoc, COOKIE_WAIT)) {		if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk,						 commands)) {			retval = SCTP_DISPOSITION_CONSUME;			goto cleanup_asoc;		}	}	sctp_tietags_populate(new_asoc, asoc);	/* B) "Z" shall respond immediately with an INIT ACK chunk.  */	/* If there are errors need to be reported for unknown parameters,	 * make sure to reserve enough room in the INIT ACK for them.	 */	len = 0;	if (err_chunk) {		len = ntohs(err_chunk->chunk_hdr->length) -			sizeof(sctp_chunkhdr_t);	}	if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0)		goto nomem;	repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);	if (!repl)		goto nomem;

⌨️ 快捷键说明

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