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

📄 associola.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
		list_for_each(entry, &transport->transmitted) {			chunk = list_entry(entry, struct sctp_chunk,					   transmitted_list);			if (key == chunk->subh.data_hdr->tsn) {				match = transport;				goto out;			}		}	}out:	return match;}/* Is this the association we are looking for? */struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,					   const union sctp_addr *laddr,					   const union sctp_addr *paddr){	struct sctp_transport *transport;	sctp_read_lock(&asoc->base.addr_lock);	if ((asoc->base.bind_addr.port == laddr->v4.sin_port) &&	    (asoc->peer.port == paddr->v4.sin_port)) {		transport = sctp_assoc_lookup_paddr(asoc, paddr);		if (!transport)			goto out;		if (sctp_bind_addr_match(&asoc->base.bind_addr, laddr,					 sctp_sk(asoc->base.sk)))			goto out;	}	transport = NULL;out:	sctp_read_unlock(&asoc->base.addr_lock);	return transport;}/* Do delayed input processing.  This is scheduled by sctp_rcv(). */static void sctp_assoc_bh_rcv(struct sctp_association *asoc){	struct sctp_endpoint *ep;	struct sctp_chunk *chunk;	struct sock *sk;	struct sctp_inq *inqueue;	int state, subtype;	int error = 0;	/* The association should be held so we should be safe. */	ep = asoc->ep;	sk = asoc->base.sk;	inqueue = &asoc->base.inqueue;	sctp_association_hold(asoc);	while (NULL != (chunk = sctp_inq_pop(inqueue))) {		state = asoc->state;		subtype = chunk->chunk_hdr->type;		/* Remember where the last DATA chunk came from so we		 * know where to send the SACK.		 */		if (sctp_chunk_is_data(chunk))			asoc->peer.last_data_from = chunk->transport;		else			SCTP_INC_STATS(SCTP_MIB_INCTRLCHUNKS);		if (chunk->transport)			chunk->transport->last_time_heard = jiffies;		/* Run through the state machine. */		error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype),				   state, ep, asoc, chunk, GFP_ATOMIC);		/* Check to see if the association is freed in response to		 * the incoming chunk.  If so, get out of the while loop.		 */		if (asoc->base.dead)			break;		/* If there is an error on chunk, discard this packet. */		if (error && chunk)			chunk->pdiscard = 1;	}	sctp_association_put(asoc);}/* This routine moves an association from its old sk to a new sk.  */void sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk){	struct sctp_opt *newsp = sctp_sk(newsk);	struct sock *oldsk = assoc->base.sk;	/* Delete the association from the old endpoint's list of	 * associations.	 */	list_del_init(&assoc->asocs);	/* Decrement the backlog value for a TCP-style socket. */	if (sctp_style(oldsk, TCP))		oldsk->sk_ack_backlog--;	/* Release references to the old endpoint and the sock.  */	sctp_endpoint_put(assoc->ep);	sock_put(assoc->base.sk);	/* Get a reference to the new endpoint.  */	assoc->ep = newsp->ep;	sctp_endpoint_hold(assoc->ep);	/* Get a reference to the new sock.  */	assoc->base.sk = newsk;	sock_hold(assoc->base.sk);	/* Add the association to the new endpoint's list of associations.  */	sctp_endpoint_add_asoc(newsp->ep, assoc);}/* Update an association (possibly from unexpected COOKIE-ECHO processing).  */void sctp_assoc_update(struct sctp_association *asoc,		       struct sctp_association *new){	struct sctp_transport *trans;	struct list_head *pos, *temp;	/* Copy in new parameters of peer. */	asoc->c = new->c;	asoc->peer.rwnd = new->peer.rwnd;	asoc->peer.sack_needed = new->peer.sack_needed;	asoc->peer.i = new->peer.i;	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE,			 asoc->peer.i.initial_tsn);	/* Remove any peer addresses not present in the new association. */	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {		trans = list_entry(pos, struct sctp_transport, transports);		if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr))			sctp_assoc_del_peer(asoc, &trans->ipaddr);	}	/* If the case is A (association restart), use	 * initial_tsn as next_tsn. If the case is B, use	 * current next_tsn in case data sent to peer	 * has been discarded and needs retransmission.	 */	if (asoc->state >= SCTP_STATE_ESTABLISHED) {		asoc->next_tsn = new->next_tsn;		asoc->ctsn_ack_point = new->ctsn_ack_point;		asoc->adv_peer_ack_point = new->adv_peer_ack_point;		/* Reinitialize SSN for both local streams		 * and peer's streams.		 */		sctp_ssnmap_clear(asoc->ssnmap);	} else {		/* Add any peer addresses from the new association. */		list_for_each(pos, &new->peer.transport_addr_list) {			trans = list_entry(pos, struct sctp_transport,					   transports);			if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr))				sctp_assoc_add_peer(asoc, &trans->ipaddr,						    GFP_ATOMIC);		}		asoc->ctsn_ack_point = asoc->next_tsn - 1;		asoc->adv_peer_ack_point = asoc->ctsn_ack_point;		if (!asoc->ssnmap) {			/* Move the ssnmap. */			asoc->ssnmap = new->ssnmap;			new->ssnmap = NULL;		}	}}/* Update the retran path for sending a retransmitted packet. * Round-robin through the active transports, else round-robin * through the inactive transports as this is the next best thing * we can try. */void sctp_assoc_update_retran_path(struct sctp_association *asoc){	struct sctp_transport *t, *next;	struct list_head *head = &asoc->peer.transport_addr_list;	struct list_head *pos;	/* Find the next transport in a round-robin fashion. */	t = asoc->peer.retran_path;	pos = &t->transports;	next = NULL;	while (1) {		/* Skip the head. */		if (pos->next == head)			pos = head->next;		else			pos = pos->next;		t = list_entry(pos, struct sctp_transport, transports);		/* Try to find an active transport. */		if (t->active) {			break;		} else {			/* Keep track of the next transport in case			 * we don't find any active transport.			 */			if (!next)				next = t;		}		/* We have exhausted the list, but didn't find any		 * other active transports.  If so, use the next		 * transport.		 */		if (t == asoc->peer.retran_path) {			t = next;			break;		}	}	asoc->peer.retran_path = t;}/* Choose the transport for sending a SHUTDOWN packet.  */struct sctp_transport *sctp_assoc_choose_shutdown_transport(	struct sctp_association *asoc){	/* If this is the first time SHUTDOWN is sent, use the active path,	 * else use the retran path. If the last SHUTDOWN was sent over the	 * retran path, update the retran path and use it.	 */	if (!asoc->shutdown_last_sent_to)		return asoc->peer.active_path;	else {		if (asoc->shutdown_last_sent_to == asoc->peer.retran_path)			sctp_assoc_update_retran_path(asoc);		return asoc->peer.retran_path;	}}/* Update the association's pmtu and frag_point by going through all the * transports. This routine is called when a transport's PMTU has changed. */void sctp_assoc_sync_pmtu(struct sctp_association *asoc){	struct sctp_transport *t;	struct list_head *pos;	__u32 pmtu = 0;	if (!asoc)		return;	/* Get the lowest pmtu of all the transports. */	list_for_each(pos, &asoc->peer.transport_addr_list) {		t = list_entry(pos, struct sctp_transport, transports);		if (!pmtu || (t->pmtu < pmtu))			pmtu = t->pmtu;	}	if (pmtu) {		struct sctp_opt *sp = sctp_sk(asoc->base.sk);		asoc->pmtu = pmtu;		asoc->frag_point = sctp_frag_point(sp, pmtu);	}	SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",			  __FUNCTION__, asoc, asoc->pmtu, asoc->frag_point);}/* Should we send a SACK to update our peer? */static inline int sctp_peer_needs_update(struct sctp_association *asoc){	switch (asoc->state) {	case SCTP_STATE_ESTABLISHED:	case SCTP_STATE_SHUTDOWN_PENDING:	case SCTP_STATE_SHUTDOWN_RECEIVED:	case SCTP_STATE_SHUTDOWN_SENT:		if ((asoc->rwnd > asoc->a_rwnd) &&		    ((asoc->rwnd - asoc->a_rwnd) >=		     min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu)))			return 1;		break;	default:		break;	}	return 0;}/* Increase asoc's rwnd by len and send any window update SACK if needed. */void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len){	struct sctp_chunk *sack;	struct timer_list *timer;	if (asoc->rwnd_over) {		if (asoc->rwnd_over >= len) {			asoc->rwnd_over -= len;		} else {			asoc->rwnd += (len - asoc->rwnd_over);			asoc->rwnd_over = 0;		}	} else {		asoc->rwnd += len;	}	SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) "			  "- %u\n", __FUNCTION__, asoc, len, asoc->rwnd,			  asoc->rwnd_over, asoc->a_rwnd);	/* Send a window update SACK if the rwnd has increased by at least the	 * minimum of the association's PMTU and half of the receive buffer.	 * The algorithm used is similar to the one described in	 * Section 4.2.3.3 of RFC 1122.	 */	if (sctp_peer_needs_update(asoc)) {		asoc->a_rwnd = asoc->rwnd;		SCTP_DEBUG_PRINTK("%s: Sending window update SACK- asoc: %p "				  "rwnd: %u a_rwnd: %u\n", __FUNCTION__,				  asoc, asoc->rwnd, asoc->a_rwnd);		sack = sctp_make_sack(asoc);		if (!sack)			return;		asoc->peer.sack_needed = 0;		sctp_outq_tail(&asoc->outqueue, sack);		/* Stop the SACK timer.  */		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];		if (timer_pending(timer) && del_timer(timer))			sctp_association_put(asoc);	}}/* Decrease asoc's rwnd by len. */void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len){	SCTP_ASSERT(asoc->rwnd, "rwnd zero", return);	SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return);	if (asoc->rwnd >= len) {		asoc->rwnd -= len;	} else {		asoc->rwnd_over = len - asoc->rwnd;		asoc->rwnd = 0;	}	SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n",			  __FUNCTION__, asoc, len, asoc->rwnd,			  asoc->rwnd_over);}/* Build the bind address list for the association based on info from the * local endpoint and the remote peer. */int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc, int gfp){	sctp_scope_t scope;	int flags;	/* Use scoping rules to determine the subset of addresses from	 * the endpoint.	 */	scope = sctp_scope(&asoc->peer.active_path->ipaddr);	flags = (PF_INET6 == asoc->base.sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0;	if (asoc->peer.ipv4_address)		flags |= SCTP_ADDR4_PEERSUPP;	if (asoc->peer.ipv6_address)		flags |= SCTP_ADDR6_PEERSUPP;	return sctp_bind_addr_copy(&asoc->base.bind_addr,				   &asoc->ep->base.bind_addr,				   scope, gfp, flags);}/* Build the association's bind address list from the cookie.  */int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc,					 struct sctp_cookie *cookie, int gfp){	int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length);	int var_size3 = cookie->raw_addr_list_len;	__u8 *raw = (__u8 *)cookie->peer_init + var_size2;	return sctp_raw_to_bind_addrs(&asoc->base.bind_addr, raw, var_size3,				      asoc->ep->base.bind_addr.port, gfp);}/* Lookup laddr in the bind address list of an association. */ int sctp_assoc_lookup_laddr(struct sctp_association *asoc, 			    const union sctp_addr *laddr){	int found;	sctp_read_lock(&asoc->base.addr_lock);	if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) &&	    sctp_bind_addr_match(&asoc->base.bind_addr, laddr,			         sctp_sk(asoc->base.sk))) {		found = 1;		goto out;	}	found = 0;out:	sctp_read_unlock(&asoc->base.addr_lock);	return found;}

⌨️ 快捷键说明

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