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

📄 input.c

📁 一种在UDP协议中实现了拥赛控制和重传机制的协议
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct sctp_endpoint *ep;	struct sctp_association *asoc;	struct sctp_transport *transport;	struct inet_sock *inet;	char *saveip, *savesctp;	int err;	if (skb->len < ((iph->ihl << 2) + 8)) {		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);		return;	}	/* Fix up skb to look at the embedded net header. */	saveip = skb->nh.raw;	savesctp  = skb->h.raw;	skb->nh.iph = iph;	skb->h.raw = (char *)sh;	sk = sctp_err_lookup(AF_INET, skb, sh, &ep, &asoc, &transport);	/* Put back, the original pointers. */	skb->nh.raw = saveip;	skb->h.raw = 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, ep, 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, ep, 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. */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;	ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));	/* Scan through all the chunks in the packet.  */	while (ch_end > (__u8 *)ch && ch_end < skb->tail) {		/* 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 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;	        ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));	}	return 0;discard:	return 1;}/* Insert endpoint into the hash table.  */static void __sctp_hash_endpoint(struct sctp_endpoint *ep){	struct sctp_ep_common **epp;	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);	epp = &head->chain;	epb->next = *epp;	if (epb->next)		(*epp)->pprev = &epb->next;	*epp = epb;	epb->pprev = epp;	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;	epb->hashent = sctp_ep_hashfn(epb->bind_addr.port);	head = &sctp_ep_hashtable[epb->hashent];	sctp_write_lock(&head->lock);	if (epb->pprev) {		if (epb->next)			epb->next->pprev = epb->pprev;		*epb->pprev = epb->next;		epb->pprev = NULL;	}	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;	int hash;	hash = sctp_ep_hashfn(laddr->v4.sin_port);	head = &sctp_ep_hashtable[hash];	read_lock(&head->lock);	for (epb = head->chain; epb; epb = epb->next) {		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);	sock_hold(epb->sk);	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 **epp;	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);	epp = &head->chain;	epb->next = *epp;	if (epb->next)		(*epp)->pprev = &epb->next;	*epp = epb;	epb->pprev = epp;	sctp_write_unlock(&head->lock);}/* Add an association to the hash. Local BH-safe. */void sctp_hash_established(struct sctp_association *asoc){	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);	if (epb->pprev) {		if (epb->next)			epb->next->pprev = epb->pprev;		*epb->pprev = epb->next;		epb->pprev = NULL;	}	sctp_write_unlock(&head->lock);}/* Remove association from the hash table.  Local BH-safe. */void sctp_unhash_established(struct sctp_association *asoc){	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;	int hash;	/* Optimize here for direct hit, only listening connections can	 * have wildcards anyways.	 */	hash = sctp_assoc_hashfn(local->v4.sin_port, peer->v4.sin_port);	head = &sctp_assoc_hashtable[hash];	read_lock(&head->lock);	for (epb = head->chain; epb; epb = epb->next) {		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);	sock_hold(epb->sk);	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))) {		sock_put(asoc->base.sk);		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 = (struct sctphdr *) skb->h.raw;	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;	/* If this is INIT/INIT-ACK look inside the chunk too. */	switch (ch->type) {	case SCTP_CID_INIT:	case SCTP_CID_INIT_ACK:		break;	default:		return NULL;	}	/* 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, ntohs(sh->source), 0);		asoc = __sctp_lookup_association(laddr, paddr, &transport);		if (asoc)			return asoc;	}	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_init_lookup(skb, laddr, transportp);	return asoc;}

⌨️ 快捷键说明

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