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

📄 associola.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	 * primary destination, the sender MUST do the following:	 *	 * 1) If CHANGEOVER_ACTIVE is set, then there was a switch	 * to this destination address earlier. The sender MUST set	 * CYCLING_CHANGEOVER to indicate that this switch is a	 * double switch to the same destination address.	 */	if (transport->cacc.changeover_active)		transport->cacc.cycling_changeover = 1;	/* 2) The sender MUST set CHANGEOVER_ACTIVE to indicate that	 * a changeover has occurred.	 */	transport->cacc.changeover_active = 1;	/* 3) The sender MUST store the next TSN to be sent in	 * next_tsn_at_change.	 */	transport->cacc.next_tsn_at_change = asoc->next_tsn;}/* Add a transport address to an association.  */struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,					   const union sctp_addr *addr,					   int gfp){	struct sctp_transport *peer;	struct sctp_opt *sp;	unsigned short port;	sp = sctp_sk(asoc->base.sk);	/* AF_INET and AF_INET6 share common port field. */	port = addr->v4.sin_port;	/* Set the port if it has not been set yet.  */	if (0 == asoc->peer.port)		asoc->peer.port = port;	/* Check to see if this is a duplicate. */	peer = sctp_assoc_lookup_paddr(asoc, addr);	if (peer)		return peer;	peer = sctp_transport_new(addr, gfp);	if (!peer)		return NULL;	sctp_transport_set_owner(peer, asoc);	/* Initialize the pmtu of the transport. */	sctp_transport_pmtu(peer);	/* If this is the first transport addr on this association,	 * initialize the association PMTU to the peer's PMTU.	 * If not and the current association PMTU is higher than the new	 * peer's PMTU, reset the association PMTU to the new peer's PMTU.	 */	if (asoc->pmtu)		asoc->pmtu = min_t(int, peer->pmtu, asoc->pmtu);	else		asoc->pmtu = peer->pmtu;	SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to "			  "%d\n", asoc, asoc->pmtu);	asoc->frag_point = sctp_frag_point(sp, asoc->pmtu);	/* The asoc->peer.port might not be meaningful yet, but	 * initialize the packet structure anyway.	 */	sctp_packet_init(&peer->packet, peer, asoc->base.bind_addr.port,			 asoc->peer.port);	/* 7.2.1 Slow-Start	 *	 * o The initial cwnd before data transmission or after a	 *   sufficiently long idle period MUST be <= 2*MTU.	 *	 * o The initial value of ssthresh MAY be arbitrarily high	 *   (for example, implementations MAY use the size of the	 *   receiver advertised window).	 */	peer->cwnd = asoc->pmtu * 2;	/* At this point, we may not have the receiver's advertised window,	 * so initialize ssthresh to the default value and it will be set	 * later when we process the INIT.	 */	peer->ssthresh = SCTP_DEFAULT_MAXWINDOW;	peer->partial_bytes_acked = 0;	peer->flight_size = 0;	peer->error_threshold = peer->max_retrans;	/* By default, enable heartbeat for peer address. */	peer->hb_allowed = 1;	/* Initialize the peer's heartbeat interval based on the	 * sock configured value.	 */	peer->hb_interval = msecs_to_jiffies(sp->paddrparam.spp_hbinterval);	/* Set the path max_retrans.  */	peer->max_retrans = asoc->max_retrans;	/* Set the transport's RTO.initial value */	peer->rto = asoc->rto_initial;	/* Attach the remote transport to our asoc.  */	list_add_tail(&peer->transports, &asoc->peer.transport_addr_list);	/* If we do not yet have a primary path, set one.  */	if (!asoc->peer.primary_path) {		sctp_assoc_set_primary(asoc, peer);		asoc->peer.retran_path = peer;	}	if (asoc->peer.active_path == asoc->peer.retran_path)		asoc->peer.retran_path = peer;	return peer;}/* Delete a transport address from an association.  */void sctp_assoc_del_peer(struct sctp_association *asoc,			 const union sctp_addr *addr){	struct list_head	*pos;	struct list_head	*temp;	struct sctp_transport	*peer = NULL;	struct sctp_transport	*transport;	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {		transport = list_entry(pos, struct sctp_transport, transports);		if (sctp_cmp_addr_exact(addr, &transport->ipaddr)) {			peer = transport;			list_del(pos);			break;		}	}	/* The address we want delete is not in the association. */	if (!peer)		return;	/* Get the first transport of asoc. */ 	pos = asoc->peer.transport_addr_list.next;	transport = list_entry(pos, struct sctp_transport, transports);	/* Update any entries that match the peer to be deleted. */  	if (asoc->peer.primary_path == peer)		sctp_assoc_set_primary(asoc, transport);	if (asoc->peer.active_path == peer)		asoc->peer.active_path = transport;	if (asoc->peer.retran_path == peer)		asoc->peer.retran_path = transport;	if (asoc->peer.last_data_from == peer)		asoc->peer.last_data_from = transport;	sctp_transport_free(peer);}/* Lookup a transport by address. */struct sctp_transport *sctp_assoc_lookup_paddr(					const struct sctp_association *asoc,					const union sctp_addr *address){	struct sctp_transport *t;	struct list_head *pos;	/* Cycle through all transports searching for a peer address. */	list_for_each(pos, &asoc->peer.transport_addr_list) {		t = list_entry(pos, struct sctp_transport, transports);		if (sctp_cmp_addr_exact(address, &t->ipaddr))			return t;	}	return NULL;}/* Engage in transport control operations. * Mark the transport up or down and send a notification to the user. * Select and update the new active and retran paths. */void sctp_assoc_control_transport(struct sctp_association *asoc,				  struct sctp_transport *transport,				  sctp_transport_cmd_t command,				  sctp_sn_error_t error){	struct sctp_transport *t = NULL;	struct sctp_transport *first;	struct sctp_transport *second;	struct sctp_ulpevent *event;	struct list_head *pos;	int spc_state = 0;	/* Record the transition on the transport.  */	switch (command) {	case SCTP_TRANSPORT_UP:		transport->active = SCTP_ACTIVE;		spc_state = SCTP_ADDR_AVAILABLE;		break;	case SCTP_TRANSPORT_DOWN:		transport->active = SCTP_INACTIVE;		spc_state = SCTP_ADDR_UNREACHABLE;		break;	default:		return;	};	/* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the	 * user.	 */	event = sctp_ulpevent_make_peer_addr_change(asoc,				(struct sockaddr_storage *) &transport->ipaddr,				0, spc_state, error, GFP_ATOMIC);	if (event)		sctp_ulpq_tail_event(&asoc->ulpq, event);	/* Select new active and retran paths. */	/* Look for the two most recently used active transports.	 *	 * This code produces the wrong ordering whenever jiffies	 * rolls over, but we still get usable transports, so we don't	 * worry about it.	 */	first = NULL; second = NULL;	list_for_each(pos, &asoc->peer.transport_addr_list) {		t = list_entry(pos, struct sctp_transport, transports);		if (!t->active)			continue;		if (!first || t->last_time_heard > first->last_time_heard) {			second = first;			first = t;		}		if (!second || t->last_time_heard > second->last_time_heard)			second = t;	}	/* RFC 2960 6.4 Multi-Homed SCTP Endpoints	 *	 * By default, an endpoint should always transmit to the	 * primary path, unless the SCTP user explicitly specifies the	 * destination transport address (and possibly source	 * transport address) to use.	 *	 * [If the primary is active but not most recent, bump the most	 * recently used transport.]	 */	if (asoc->peer.primary_path->active &&	    first != asoc->peer.primary_path) {		second = first;		first = asoc->peer.primary_path;	}	/* If we failed to find a usable transport, just camp on the	 * primary, even if it is inactive.	 */	if (!first) {		first = asoc->peer.primary_path;		second = asoc->peer.primary_path;	}	/* Set the active and retran transports.  */	asoc->peer.active_path = first;	asoc->peer.retran_path = second;}/* Hold a reference to an association. */void sctp_association_hold(struct sctp_association *asoc){	atomic_inc(&asoc->base.refcnt);}/* Release a reference to an association and cleanup * if there are no more references. */void sctp_association_put(struct sctp_association *asoc){	if (atomic_dec_and_test(&asoc->base.refcnt))		sctp_association_destroy(asoc);}/* Allocate the next TSN, Transmission Sequence Number, for the given * association. */__u32 sctp_association_get_next_tsn(struct sctp_association *asoc){	/* From Section 1.6 Serial Number Arithmetic:	 * Transmission Sequence Numbers wrap around when they reach	 * 2**32 - 1.  That is, the next TSN a DATA chunk MUST use	 * after transmitting TSN = 2*32 - 1 is TSN = 0.	 */	__u32 retval = asoc->next_tsn;	asoc->next_tsn++;	asoc->unack_data++;	return retval;}/* Allocate 'num' TSNs by incrementing the association's TSN by num. */__u32 sctp_association_get_tsn_block(struct sctp_association *asoc, int num){	__u32 retval = asoc->next_tsn;	asoc->next_tsn += num;	asoc->unack_data += num;	return retval;}/* Compare two addresses to see if they match.  Wildcard addresses * only match themselves. */int sctp_cmp_addr_exact(const union sctp_addr *ss1,			const union sctp_addr *ss2){	struct sctp_af *af;	af = sctp_get_af_specific(ss1->sa.sa_family);	if (unlikely(!af))		return 0;	return af->cmp_addr(ss1, ss2);}/* Return an ecne chunk to get prepended to a packet. * Note:  We are sly and return a shared, prealloced chunk.  FIXME: * No we don't, but we could/should. */struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc){	struct sctp_chunk *chunk;	/* Send ECNE if needed.	 * Not being able to allocate a chunk here is not deadly.	 */	if (asoc->need_ecne)		chunk = sctp_make_ecne(asoc, asoc->last_ecne_tsn);	else		chunk = NULL;	return chunk;}/* Use this function for the packet prepend callback when no ECNE * packet is desired (e.g. some packets don't like to be bundled). */struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc){	return NULL;}/* * Find which transport this TSN was sent on. */struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc,					     __u32 tsn){	struct sctp_transport *active;	struct sctp_transport *match;	struct list_head *entry, *pos;	struct sctp_transport *transport;	struct sctp_chunk *chunk;	__u32 key = htonl(tsn);	match = NULL;	/*	 * FIXME: In general, find a more efficient data structure for	 * searching.	 */	/*	 * The general strategy is to search each transport's transmitted	 * list.   Return which transport this TSN lives on.	 *	 * Let's be hopeful and check the active_path first.	 * Another optimization would be to know if there is only one	 * outbound path and not have to look for the TSN at all.	 *	 */	active = asoc->peer.active_path;	list_for_each(entry, &active->transmitted) {		chunk = list_entry(entry, struct sctp_chunk, transmitted_list);		if (key == chunk->subh.data_hdr->tsn) {			match = active;			goto out;		}	}	/* If not found, go search all the other transports. */	list_for_each(pos, &asoc->peer.transport_addr_list) {		transport = list_entry(pos, struct sctp_transport, transports);		if (transport == active)			break;

⌨️ 快捷键说明

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