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

📄 sm_make_chunk.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* This implementation defaults to making the first transport	 * added as the primary transport.  The source address seems to	 * be a a better choice than any of the embedded addresses.	 */	if (peer_addr)		if(!sctp_assoc_add_peer(asoc, peer_addr, gfp))			goto nomem;	/* Process the initialization parameters.  */	sctp_walk_params(param, peer_init, init_hdr.params) {		if (!sctp_process_param(asoc, param, peer_addr, gfp))                        goto clean_up;	}	/* The fixed INIT headers are always in network byte	 * order.	 */	asoc->peer.i.init_tag =		ntohl(peer_init->init_hdr.init_tag);	asoc->peer.i.a_rwnd =		ntohl(peer_init->init_hdr.a_rwnd);	asoc->peer.i.num_outbound_streams =		ntohs(peer_init->init_hdr.num_outbound_streams);	asoc->peer.i.num_inbound_streams =		ntohs(peer_init->init_hdr.num_inbound_streams);	asoc->peer.i.initial_tsn =		ntohl(peer_init->init_hdr.initial_tsn);	/* Apply the upper bounds for output streams based on peer's	 * number of inbound streams.	 */	if (asoc->c.sinit_num_ostreams  >	    ntohs(peer_init->init_hdr.num_inbound_streams)) {		asoc->c.sinit_num_ostreams =			ntohs(peer_init->init_hdr.num_inbound_streams);	}	if (asoc->c.sinit_max_instreams >	    ntohs(peer_init->init_hdr.num_outbound_streams)) {		asoc->c.sinit_max_instreams =			ntohs(peer_init->init_hdr.num_outbound_streams);	}	/* Copy Initiation tag from INIT to VT_peer in cookie.   */	asoc->c.peer_vtag = asoc->peer.i.init_tag;	/* Peer Rwnd   : Current calculated value of the peer's rwnd.  */	asoc->peer.rwnd = asoc->peer.i.a_rwnd;	/* Copy cookie in case we need to resend COOKIE-ECHO. */	cookie = asoc->peer.cookie;	if (cookie) {		asoc->peer.cookie = kmalloc(asoc->peer.cookie_len, gfp);		if (!asoc->peer.cookie)			goto clean_up;		memcpy(asoc->peer.cookie, cookie, asoc->peer.cookie_len);	}	/* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily	 * high (for example, implementations MAY use the size of the receiver	 * advertised window).	 */	list_for_each(pos, &asoc->peer.transport_addr_list) {		transport = list_entry(pos, struct sctp_transport, transports);		transport->ssthresh = asoc->peer.i.a_rwnd;	}	/* Set up the TSN tracking pieces.  */	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE,			 asoc->peer.i.initial_tsn);	/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number	 *	 * The stream sequence number in all the streams shall start	 * from 0 when the association is established.  Also, when the	 * stream sequence number reaches the value 65535 the next	 * stream sequence number shall be set to 0.	 */	/* Allocate storage for the negotiated streams if it is not a temporary 	 * association.	 */	if (!asoc->temp) {		int assoc_id;		int error;		asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams,					       asoc->c.sinit_num_ostreams, gfp);		if (!asoc->ssnmap)			goto clean_up;	retry:		if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))			goto clean_up;		spin_lock_bh(&sctp_assocs_id_lock);		error = idr_get_new_above(&sctp_assocs_id, (void *)asoc, 1,					  &assoc_id);		spin_unlock_bh(&sctp_assocs_id_lock);		if (error == -EAGAIN)			goto retry;		else if (error)			goto clean_up;		asoc->assoc_id = (sctp_assoc_t) assoc_id;	}	/* ADDIP Section 4.1 ASCONF Chunk Procedures	 *	 * When an endpoint has an ASCONF signaled change to be sent to the	 * remote endpoint it should do the following:	 * ...	 * A2) A serial number should be assigned to the Chunk. The serial	 * number should be a monotonically increasing number. All serial	 * numbers are defined to be initialized at the start of the	 * association to the same value as the Initial TSN.	 */	asoc->peer.addip_serial = asoc->peer.i.initial_tsn - 1;	return 1;clean_up:	/* Release the transport structures. */	list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {		transport = list_entry(pos, struct sctp_transport, transports);		list_del_init(pos);		sctp_transport_free(transport);	}nomem:	return 0;}/* Update asoc with the option described in param. * * RFC2960 3.3.2.1 Optional/Variable Length Parameters in INIT * * asoc is the association to update. * param is the variable length parameter to use for update. * cid tells us if this is an INIT, INIT ACK or COOKIE ECHO. * If the current packet is an INIT we want to minimize the amount of * work we do.  In particular, we should not build transport * structures for the addresses. */int sctp_process_param(struct sctp_association *asoc, union sctp_params param,		       const union sctp_addr *peer_addr, int gfp){	union sctp_addr addr;	int i;	__u16 sat;	int retval = 1;	sctp_scope_t scope;	time_t stale;	struct sctp_af *af;	/* We maintain all INIT parameters in network byte order all the	 * time.  This allows us to not worry about whether the parameters	 * came from a fresh INIT, and INIT ACK, or were stored in a cookie.	 */	switch (param.p->type) {	case SCTP_PARAM_IPV6_ADDRESS:		if (PF_INET6 != asoc->base.sk->sk_family)			break;		/* Fall through. */	case SCTP_PARAM_IPV4_ADDRESS:		af = sctp_get_af_specific(param_type2af(param.p->type));		af->from_addr_param(&addr, param.addr, asoc->peer.port, 0);		scope = sctp_scope(peer_addr);		if (sctp_in_scope(&addr, scope))			if (!sctp_assoc_add_peer(asoc, &addr, gfp))				return 0;		break;	case SCTP_PARAM_COOKIE_PRESERVATIVE:		if (!sctp_cookie_preserve_enable)			break;		stale = ntohl(param.life->lifespan_increment);		/* Suggested Cookie Life span increment's unit is msec,		 * (1/1000sec).		 */		asoc->cookie_life.tv_sec += stale / 1000;		asoc->cookie_life.tv_usec += (stale % 1000) * 1000;		break;	case SCTP_PARAM_HOST_NAME_ADDRESS:		SCTP_DEBUG_PRINTK("unimplemented SCTP_HOST_NAME_ADDRESS\n");		break;	case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES:		/* Turn off the default values first so we'll know which		 * ones are really set by the peer.		 */		asoc->peer.ipv4_address = 0;		asoc->peer.ipv6_address = 0;		/* Cycle through address types; avoid divide by 0. */		sat = ntohs(param.p->length) - sizeof(sctp_paramhdr_t);		if (sat)			sat /= sizeof(__u16);		for (i = 0; i < sat; ++i) {			switch (param.sat->types[i]) {			case SCTP_PARAM_IPV4_ADDRESS:				asoc->peer.ipv4_address = 1;				break;			case SCTP_PARAM_IPV6_ADDRESS:				asoc->peer.ipv6_address = 1;				break;			case SCTP_PARAM_HOST_NAME_ADDRESS:				asoc->peer.hostname_address = 1;				break;			default: /* Just ignore anything else.  */				break;			};		}		break;	case SCTP_PARAM_STATE_COOKIE:		asoc->peer.cookie_len =			ntohs(param.p->length) - sizeof(sctp_paramhdr_t);		asoc->peer.cookie = param.cookie->body;		break;	case SCTP_PARAM_HEARTBEAT_INFO:		/* Would be odd to receive, but it causes no problems. */		break;	case SCTP_PARAM_UNRECOGNIZED_PARAMETERS:		/* Rejected during verify stage. */		break;	case SCTP_PARAM_ECN_CAPABLE:		asoc->peer.ecn_capable = 1;		break;	case SCTP_PARAM_FWD_TSN_SUPPORT:		if (sctp_prsctp_enable) {			asoc->peer.prsctp_capable = 1;			break;		}		/* Fall Through */ 	default:		/* Any unrecognized parameters should have been caught		 * and handled by sctp_verify_param() which should be		 * called prior to this routine.  Simply log the error		 * here.		 */		SCTP_DEBUG_PRINTK("Ignoring param: %d for association %p.\n",				  ntohs(param.p->type), asoc);		break;	};	return retval;}/* Select a new verification tag.  */__u32 sctp_generate_tag(const struct sctp_endpoint *ep){	/* I believe that this random number generator complies with RFC1750.	 * A tag of 0 is reserved for special cases (e.g. INIT).	 */	__u32 x;	do {		get_random_bytes(&x, sizeof(__u32));	} while (x == 0);	return x;}/* Select an initial TSN to send during startup.  */__u32 sctp_generate_tsn(const struct sctp_endpoint *ep){	__u32 retval;	get_random_bytes(&retval, sizeof(__u32));	return retval;}/* * ADDIP 3.1.1 Address Configuration Change Chunk (ASCONF) *      0                   1                   2                   3 *      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     | Type = 0xC1   |  Chunk Flags  |      Chunk Length             | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |                       Serial Number                           | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |                    Address Parameter                          | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |                     ASCONF Parameter #1                       | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     \                                                               \ *     /                             ....                              / *     \                                                               \ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |                     ASCONF Parameter #N                       | *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Address Parameter and other parameter will not be wrapped in this function  */struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,				    union sctp_addr *addr, int vparam_len){	sctp_addiphdr_t asconf;	struct sctp_chunk *retval;	int length = sizeof(asconf) + vparam_len;	union sctp_addr_param addrparam;	int addrlen;	struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);	addrlen = af->to_addr_param(addr, &addrparam);	if (!addrlen)		return NULL;	length += addrlen;	/* Create the chunk.  */	retval = sctp_make_chunk(asoc, SCTP_CID_ASCONF, 0, length);	if (!retval)		return NULL;	asconf.serial = htonl(asoc->addip_serial++);	retval->subh.addip_hdr =		sctp_addto_chunk(retval, sizeof(asconf), &asconf);	retval->param_hdr.v =		sctp_addto_chunk(retval, addrlen, &addrparam);	return retval;}/* ADDIP * 3.2.1 Add IP Address * 	0                   1                   2                   3 * 	0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |        Type = 0xC001          |    Length = Variable          | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |               ASCONF-Request Correlation ID                   | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |                       Address Parameter                       | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * 3.2.2 Delete IP Address * 	0                   1                   2                   3 * 	0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |        Type = 0xC002          |    Length = Variable          | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |               ASCONF-Request Correlation ID                   | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |                       Address Parameter                       | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,					      union sctp_addr	      *laddr,					      struct sockaddr	      *addrs,					      int		      addrcnt,					      __u16		      flags){	sctp_addip_param_t	param;	struct sctp_chunk	*retval;	union sctp_addr_param	addr_param;	union sctp_addr		*addr;	void			*addr_buf;	struct sctp_af		*af;	int			paramlen = sizeof(param);	int			addr_param_len = 0;	int 			totallen = 0;	int 			i;	/* Get total length of all the address parameters. */	addr_buf = addrs;	for (i = 0; i < addrcnt; i++) {		addr = (union sctp_addr *)addr_buf;		af = sctp_get_af_specific(addr->v4.sin_family);		addr_param_len = af->to_addr_param(addr, &addr_param);		totallen += paramlen;		totallen += addr_param_len;		addr_buf += af->sockaddr_len;	}	/* Create an asconf chunk with the required length. */	retval = sctp_make_asconf(asoc, laddr, totallen);	if (!retval)		return NULL;	/* Add the address parameters to the asconf chunk. */	addr_buf = addrs;	for (i = 0; i < addrcnt; i++) {		addr = (union sctp_addr *)addr_buf;		af = sctp_get_af_specific(addr->v4.sin_family);		addr_param_len = af->to_addr_param(addr, &addr_param);		param.param_hdr.type = flags;		param.param_hdr.length = htons(paramlen + addr_param_len);		param.crr_id = i;		sctp_addto_chunk(retval, paramlen, &param);		sctp_addto_chunk(retval, addr_param_len, &addr_param);		addr_buf += af->sockaddr_len;	}	return retval;}/* ADDIP * 3.2.4 Set Primary IP Address *	0                   1                   2                   3 *	0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |        Type =0xC004           |    Length = Variable          | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |               ASCONF-Request Correlation ID                   | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *     |                       Address Parameter                       | *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Create an ASCONF chunk with Set Primary IP address parameter.  */struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,					     union sctp_addr *addr){	sctp_addip_param_t	param;	struct sctp_chunk 	*retval;	int 			len = sizeof(param);	union sctp_addr_param	addrparam;	int			addrlen;	struct sctp_af		*af = sctp_get_af_specific(addr->v4.sin_family);	addrlen = af->to_addr

⌨️ 快捷键说明

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