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

📄 input.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct sctp_association *asoc = NULL;	struct sctp_transport *transport;	struct inet_sock *inet;	sk_buff_data_t saveip, savesctp;	int err;	if (skb->len < ihlen + 8) {		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);		return;	}	/* Fix up skb to look at the embedded net header. */	saveip = skb->network_header;	savesctp = skb->transport_header;	skb_reset_network_header(skb);	skb_set_transport_header(skb, ihlen);	sk = sctp_err_lookup(AF_INET, skb, sctp_hdr(skb), &asoc, &transport);	/* Put back, the original values. */	skb->network_header = saveip;	skb->transport_header = savesctp;	if (!sk) {		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);		return;	}	/* Warning:  The sock lock is held.  Remember to call	 * sctp_err_finish!	 */	switch (type) {	case ICMP_PARAMETERPROB:		err = EPROTO;		break;	case ICMP_DEST_UNREACH:		if (code > NR_ICMP_UNREACH)			goto out_unlock;		/* PMTU discovery (RFC1191) */		if (ICMP_FRAG_NEEDED == code) {			sctp_icmp_frag_needed(sk, asoc, transport, info);			goto out_unlock;		}		else {			if (ICMP_PROT_UNREACH == code) {				sctp_icmp_proto_unreachable(sk, asoc,							    transport);				goto out_unlock;			}		}		err = icmp_err_convert[code].errno;		break;	case ICMP_TIME_EXCEEDED:		/* Ignore any time exceeded errors due to fragment reassembly		 * timeouts.		 */		if (ICMP_EXC_FRAGTIME == code)			goto out_unlock;		err = EHOSTUNREACH;		break;	default:		goto out_unlock;	}	inet = inet_sk(sk);	if (!sock_owned_by_user(sk) && inet->recverr) {		sk->sk_err = err;		sk->sk_error_report(sk);	} else {  /* Only an error on timeout */		sk->sk_err_soft = err;	}out_unlock:	sctp_err_finish(sk, asoc);}/* * RFC 2960, 8.4 - Handle "Out of the blue" Packets. * * This function scans all the chunks in the OOTB packet to determine if * the packet should be discarded right away.  If a response might be needed * for this packet, or, if further processing is possible, the packet will * be queued to a proper inqueue for the next phase of handling. * * Output: * Return 0 - If further processing is needed. * Return 1 - If the packet can be discarded right away. */static int sctp_rcv_ootb(struct sk_buff *skb){	sctp_chunkhdr_t *ch;	__u8 *ch_end;	sctp_errhdr_t *err;	ch = (sctp_chunkhdr_t *) skb->data;	/* Scan through all the chunks in the packet.  */	do {		/* Break out if chunk length is less then minimal. */		if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))			break;		ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));		if (ch_end > skb_tail_pointer(skb))			break;		/* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the		 * receiver MUST silently discard the OOTB packet and take no		 * further action.		 */		if (SCTP_CID_ABORT == ch->type)			goto discard;		/* RFC 8.4, 6) If the packet contains a SHUTDOWN COMPLETE		 * chunk, the receiver should silently discard the packet		 * and take no further action.		 */		if (SCTP_CID_SHUTDOWN_COMPLETE == ch->type)			goto discard;		/* RFC 4460, 2.11.2		 * This will discard packets with INIT chunk bundled as		 * subsequent chunks in the packet.  When INIT is first,		 * the normal INIT processing will discard the chunk.		 */		if (SCTP_CID_INIT == ch->type && (void *)ch != skb->data)			goto discard;		/* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR		 * or a COOKIE ACK the SCTP Packet should be silently		 * discarded.		 */		if (SCTP_CID_COOKIE_ACK == ch->type)			goto discard;		if (SCTP_CID_ERROR == ch->type) {			sctp_walk_errors(err, ch) {				if (SCTP_ERROR_STALE_COOKIE == err->cause)					goto discard;			}		}		ch = (sctp_chunkhdr_t *) ch_end;	} while (ch_end < skb_tail_pointer(skb));	return 0;discard:	return 1;}/* Insert endpoint into the hash table.  */static void __sctp_hash_endpoint(struct sctp_endpoint *ep){	struct sctp_ep_common *epb;	struct sctp_hashbucket *head;	epb = &ep->base;	epb->hashent = sctp_ep_hashfn(epb->bind_addr.port);	head = &sctp_ep_hashtable[epb->hashent];	sctp_write_lock(&head->lock);	hlist_add_head(&epb->node, &head->chain);	sctp_write_unlock(&head->lock);}/* Add an endpoint to the hash. Local BH-safe. */void sctp_hash_endpoint(struct sctp_endpoint *ep){	sctp_local_bh_disable();	__sctp_hash_endpoint(ep);	sctp_local_bh_enable();}/* Remove endpoint from the hash table.  */static void __sctp_unhash_endpoint(struct sctp_endpoint *ep){	struct sctp_hashbucket *head;	struct sctp_ep_common *epb;	epb = &ep->base;	if (hlist_unhashed(&epb->node))		return;	epb->hashent = sctp_ep_hashfn(epb->bind_addr.port);	head = &sctp_ep_hashtable[epb->hashent];	sctp_write_lock(&head->lock);	__hlist_del(&epb->node);	sctp_write_unlock(&head->lock);}/* Remove endpoint from the hash.  Local BH-safe. */void sctp_unhash_endpoint(struct sctp_endpoint *ep){	sctp_local_bh_disable();	__sctp_unhash_endpoint(ep);	sctp_local_bh_enable();}/* Look up an endpoint. */static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr){	struct sctp_hashbucket *head;	struct sctp_ep_common *epb;	struct sctp_endpoint *ep;	struct hlist_node *node;	int hash;	hash = sctp_ep_hashfn(ntohs(laddr->v4.sin_port));	head = &sctp_ep_hashtable[hash];	read_lock(&head->lock);	sctp_for_each_hentry(epb, node, &head->chain) {		ep = sctp_ep(epb);		if (sctp_endpoint_is_match(ep, laddr))			goto hit;	}	ep = sctp_sk((sctp_get_ctl_sock()))->ep;	epb = &ep->base;hit:	sctp_endpoint_hold(ep);	read_unlock(&head->lock);	return ep;}/* Insert association into the hash table.  */static void __sctp_hash_established(struct sctp_association *asoc){	struct sctp_ep_common *epb;	struct sctp_hashbucket *head;	epb = &asoc->base;	/* Calculate which chain this entry will belong to. */	epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port);	head = &sctp_assoc_hashtable[epb->hashent];	sctp_write_lock(&head->lock);	hlist_add_head(&epb->node, &head->chain);	sctp_write_unlock(&head->lock);}/* Add an association to the hash. Local BH-safe. */void sctp_hash_established(struct sctp_association *asoc){	if (asoc->temp)		return;	sctp_local_bh_disable();	__sctp_hash_established(asoc);	sctp_local_bh_enable();}/* Remove association from the hash table.  */static void __sctp_unhash_established(struct sctp_association *asoc){	struct sctp_hashbucket *head;	struct sctp_ep_common *epb;	epb = &asoc->base;	epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port,					 asoc->peer.port);	head = &sctp_assoc_hashtable[epb->hashent];	sctp_write_lock(&head->lock);	__hlist_del(&epb->node);	sctp_write_unlock(&head->lock);}/* Remove association from the hash table.  Local BH-safe. */void sctp_unhash_established(struct sctp_association *asoc){	if (asoc->temp)		return;	sctp_local_bh_disable();	__sctp_unhash_established(asoc);	sctp_local_bh_enable();}/* Look up an association. */static struct sctp_association *__sctp_lookup_association(					const union sctp_addr *local,					const union sctp_addr *peer,					struct sctp_transport **pt){	struct sctp_hashbucket *head;	struct sctp_ep_common *epb;	struct sctp_association *asoc;	struct sctp_transport *transport;	struct hlist_node *node;	int hash;	/* Optimize here for direct hit, only listening connections can	 * have wildcards anyways.	 */	hash = sctp_assoc_hashfn(ntohs(local->v4.sin_port), ntohs(peer->v4.sin_port));	head = &sctp_assoc_hashtable[hash];	read_lock(&head->lock);	sctp_for_each_hentry(epb, node, &head->chain) {		asoc = sctp_assoc(epb);		transport = sctp_assoc_is_match(asoc, local, peer);		if (transport)			goto hit;	}	read_unlock(&head->lock);	return NULL;hit:	*pt = transport;	sctp_association_hold(asoc);	read_unlock(&head->lock);	return asoc;}/* Look up an association. BH-safe. */SCTP_STATICstruct sctp_association *sctp_lookup_association(const union sctp_addr *laddr,						 const union sctp_addr *paddr,					    struct sctp_transport **transportp){	struct sctp_association *asoc;	sctp_local_bh_disable();	asoc = __sctp_lookup_association(laddr, paddr, transportp);	sctp_local_bh_enable();	return asoc;}/* Is there an association matching the given local and peer addresses? */int sctp_has_association(const union sctp_addr *laddr,			 const union sctp_addr *paddr){	struct sctp_association *asoc;	struct sctp_transport *transport;	if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) {		sctp_association_put(asoc);		return 1;	}	return 0;}/* * SCTP Implementors Guide, 2.18 Handling of address * parameters within the INIT or INIT-ACK. * * D) When searching for a matching TCB upon reception of an INIT *    or INIT-ACK chunk the receiver SHOULD use not only the *    source address of the packet (containing the INIT or *    INIT-ACK) but the receiver SHOULD also use all valid *    address parameters contained within the chunk. * * 2.18.3 Solution description * * This new text clearly specifies to an implementor the need * to look within the INIT or INIT-ACK. Any implementation that * does not do this, may not be able to establish associations * in certain circumstances. * */static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,	const union sctp_addr *laddr, struct sctp_transport **transportp){	struct sctp_association *asoc;	union sctp_addr addr;	union sctp_addr *paddr = &addr;	struct sctphdr *sh = sctp_hdr(skb);	sctp_chunkhdr_t *ch;	union sctp_params params;	sctp_init_chunk_t *init;	struct sctp_transport *transport;	struct sctp_af *af;	ch = (sctp_chunkhdr_t *) skb->data;	/* The code below will attempt to walk the chunk and extract	 * parameter information.  Before we do that, we need to verify	 * that the chunk length doesn't cause overflow.  Otherwise, we'll	 * walk off the end.	 */	if (WORD_ROUND(ntohs(ch->length)) > skb->len)		return NULL;	/*	 * This code will NOT touch anything inside the chunk--it is	 * strictly READ-ONLY.	 *	 * RFC 2960 3  SCTP packet Format	 *	 * Multiple chunks can be bundled into one SCTP packet up to	 * the MTU size, except for the INIT, INIT ACK, and SHUTDOWN	 * COMPLETE chunks.  These chunks MUST NOT be bundled with any	 * other chunk in a packet.  See Section 6.10 for more details	 * on chunk bundling.	 */	/* Find the start of the TLVs and the end of the chunk.  This is	 * the region we search for address parameters.	 */	init = (sctp_init_chunk_t *)skb->data;	/* Walk the parameters looking for embedded addresses. */	sctp_walk_params(params, init, init_hdr.params) {		/* Note: Ignoring hostname addresses. */		af = sctp_get_af_specific(param_type2af(params.p->type));		if (!af)			continue;		af->from_addr_param(paddr, params.addr, sh->source, 0);		asoc = __sctp_lookup_association(laddr, paddr, &transport);		if (asoc)			return asoc;	}	return NULL;}/* SCTP-AUTH, Section 6.3:*    If the receiver does not find a STCB for a packet containing an AUTH*    chunk as the first chunk and not a COOKIE-ECHO chunk as the second*    chunk, it MUST use the chunks after the AUTH chunk to look up an existing*    association.** This means that any chunks that can help us identify the association need* to be looked at to find this assocation.** TODO: The only chunk currently defined that can do that is ASCONF, but we* don't support that functionality yet.*/static struct sctp_association *__sctp_rcv_auth_lookup(struct sk_buff *skb,				      const union sctp_addr *paddr,				      const union sctp_addr *laddr,				      struct sctp_transport **transportp){	/* XXX - walk through the chunks looking for something that can	 * help us find the association.  INIT, and INIT-ACK are not permitted.	 * That leaves ASCONF, but we don't support that yet.	 */	return NULL;}/* * There are circumstances when we need to look inside the SCTP packet * for information to help us find the association.   Examples * include looking inside of INIT/INIT-ACK chunks or after the AUTH * chunks. */static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb,				      const union sctp_addr *paddr,				      const union sctp_addr *laddr,				      struct sctp_transport **transportp){	sctp_chunkhdr_t *ch;	ch = (sctp_chunkhdr_t *) skb->data;	/* If this is INIT/INIT-ACK look inside the chunk too. */	switch (ch->type) {	case SCTP_CID_INIT:	case SCTP_CID_INIT_ACK:		return __sctp_rcv_init_lookup(skb, laddr, transportp);		break;	case SCTP_CID_AUTH:		return __sctp_rcv_auth_lookup(skb, paddr, laddr, transportp);		break;	}	return NULL;}/* Lookup an association for an inbound skb. */static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,				      const union sctp_addr *paddr,				      const union sctp_addr *laddr,				      struct sctp_transport **transportp){	struct sctp_association *asoc;	asoc = __sctp_lookup_association(laddr, paddr, transportp);	/* Further lookup for INIT/INIT-ACK packets.	 * SCTP Implementors Guide, 2.18 Handling of address	 * parameters within the INIT or INIT-ACK.	 */	if (!asoc)		asoc = __sctp_rcv_lookup_harder(skb, paddr, laddr, transportp);	return asoc;}

⌨️ 快捷键说明

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