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

📄 output.c

📁 一种在UDP协议中实现了拥赛控制和重传机制的协议
💻 C
📖 第 1 页 / 共 2 页
字号:
	 */	skb_set_owner_w(nskb, sk);	/* Build the SCTP header.  */	sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));	sh->source = htons(packet->source_port);	sh->dest   = htons(packet->destination_port);	/* From 6.8 Adler-32 Checksum Calculation:	 * After the packet is constructed (containing the SCTP common	 * header and one or more control or DATA chunks), the	 * transmitter shall:	 *	 * 1) Fill in the proper Verification Tag in the SCTP common	 *    header and initialize the checksum field to 0's.	 */	sh->vtag     = htonl(packet->vtag);	sh->checksum = 0;	/* 2) Calculate the Adler-32 checksum of the whole packet,	 *    including the SCTP common header and all the	 *    chunks.	 *	 * Note: Adler-32 is no longer applicable, as has been replaced	 * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.	 */	crc32 = sctp_start_cksum((__u8 *)sh, sizeof(struct sctphdr));	/**	 * 6.10 Bundling	 *	 *    An endpoint bundles chunks by simply including multiple	 *    chunks in one outbound SCTP packet.  ...	 */	/**	 * 3.2  Chunk Field Descriptions	 *	 * The total length of a chunk (including Type, Length and	 * Value fields) MUST be a multiple of 4 bytes.  If the length	 * of the chunk is not a multiple of 4 bytes, the sender MUST	 * pad the chunk with all zero bytes and this padding is not	 * included in the chunk length field.  The sender should	 * never pad with more than 3 bytes.	 *	 * [This whole comment explains WORD_ROUND() below.]	 */	SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n");	while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) {		if (sctp_chunk_is_data(chunk)) {			if (!chunk->has_tsn) {				sctp_chunk_assign_ssn(chunk);				sctp_chunk_assign_tsn(chunk);			/* 6.3.1 C4) When data is in flight and when allowed			 * by rule C5, a new RTT measurement MUST be made each			 * round trip.  Furthermore, new RTT measurements			 * SHOULD be made no more than once per round-trip			 * for a given destination transport address.			 */				if (!tp->rto_pending) {					chunk->rtt_in_progress = 1;					tp->rto_pending = 1;				}			} else				chunk->resent = 1;			chunk->sent_at = jiffies;			has_data = 1;		}		padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len;		if (padding)			memset(skb_put(chunk->skb, padding), 0, padding);		crc32 = sctp_update_copy_cksum(skb_put(nskb, chunk->skb->len),					       chunk->skb->data,					       chunk->skb->len, crc32);		SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n",				  "*** Chunk", chunk,				  sctp_cname(SCTP_ST_CHUNK(					  chunk->chunk_hdr->type)),				  chunk->has_tsn ? "TSN" : "No TSN",				  chunk->has_tsn ?				  ntohl(chunk->subh.data_hdr->tsn) : 0,				  "length", ntohs(chunk->chunk_hdr->length),				  "chunk->skb->len", chunk->skb->len,				  "rtt_in_progress", chunk->rtt_in_progress);		/*		 * If this is a control chunk, this is our last		 * reference. Free data chunks after they've been		 * acknowledged or have failed.		 */		if (!sctp_chunk_is_data(chunk))    			sctp_chunk_free(chunk);	}	/* Perform final transformation on checksum. */	crc32 = sctp_end_cksum(crc32);	/* 3) Put the resultant value into the checksum field in the	 *    common header, and leave the rest of the bits unchanged.	 */	sh->checksum = htonl(crc32);	/* IP layer ECN support	 * From RFC 2481	 *  "The ECN-Capable Transport (ECT) bit would be set by the	 *   data sender to indicate that the end-points of the	 *   transport protocol are ECN-capable."	 *	 * Now setting the ECT bit all the time, as it should not cause	 * any problems protocol-wise even if our peer ignores it.	 *	 * Note: The works for IPv6 layer checks this bit too later	 * in transmission.  See IP6_ECN_flow_xmit().	 */	INET_ECN_xmit(nskb->sk);	/* Set up the IP options.  */	/* BUG: not implemented	 * For v4 this all lives somewhere in sk->sk_opt...	 */	/* Dump that on IP!  */	if (asoc && asoc->peer.last_sent_to != tp) {		/* Considering the multiple CPU scenario, this is a		 * "correcter" place for last_sent_to.  --xguo		 */		asoc->peer.last_sent_to = tp;	}	if (has_data) {		struct timer_list *timer;		unsigned long timeout;		tp->last_time_used = jiffies;		/* Restart the AUTOCLOSE timer when sending data. */		if (sctp_state(asoc, ESTABLISHED) && asoc->autoclose) {			timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE];			timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE];			if (!mod_timer(timer, jiffies + timeout))				sctp_association_hold(asoc);		}	}	dst = tp->dst;	/* The 'obsolete' field of dst is set to 2 when a dst is freed. */	if (!dst || (dst->obsolete > 1)) {		dst_release(dst);		sctp_transport_route(tp, NULL, sctp_sk(sk));		sctp_assoc_sync_pmtu(asoc);	}	nskb->dst = dst_clone(tp->dst);	if (!nskb->dst)		goto no_route;	SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb len %d\n",			  nskb->len);	(*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok);out:	packet->size = packet->overhead;	return err;no_route:	kfree_skb(nskb);	IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);	/* FIXME: Returning the 'err' will effect all the associations	 * associated with a socket, although only one of the paths of the	 * association is unreachable.	 * The real failure of a transport or association can be passed on	 * to the user via notifications. So setting this error may not be	 * required.	 */	 /* err = -EHOSTUNREACH; */err:	/* Control chunks are unreliable so just drop them.  DATA chunks	 * will get resent or dropped later.	 */	while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) {		if (!sctp_chunk_is_data(chunk))    			sctp_chunk_free(chunk);	}	goto out;nomem:	err = -ENOMEM;	goto err;}/******************************************************************** * 2nd Level Abstractions ********************************************************************//* This private function handles the specifics of appending DATA chunks.  */static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,					   struct sctp_chunk *chunk){	sctp_xmit_t retval = SCTP_XMIT_OK;	size_t datasize, rwnd, inflight;	struct sctp_transport *transport = packet->transport;	__u32 max_burst_bytes;	struct sctp_association *asoc = transport->asoc;	struct sctp_sock *sp = sctp_sk(asoc->base.sk);	struct sctp_outq *q = &asoc->outqueue;	/* RFC 2960 6.1  Transmission of DATA Chunks	 *	 * A) At any given time, the data sender MUST NOT transmit new data to	 * any destination transport address if its peer's rwnd indicates	 * that the peer has no buffer space (i.e. rwnd is 0, see Section	 * 6.2.1).  However, regardless of the value of rwnd (including if it	 * is 0), the data sender can always have one DATA chunk in flight to	 * the receiver if allowed by cwnd (see rule B below).  This rule	 * allows the sender to probe for a change in rwnd that the sender	 * missed due to the SACK having been lost in transit from the data	 * receiver to the data sender.	 */	rwnd = asoc->peer.rwnd;	inflight = asoc->outqueue.outstanding_bytes;	datasize = sctp_data_size(chunk);	if (datasize > rwnd) {		if (inflight > 0) {			/* We have (at least) one data chunk in flight,			 * so we can't fall back to rule 6.1 B).			 */			retval = SCTP_XMIT_RWND_FULL;			goto finish;		}	}	/* sctpimpguide-05 2.14.2	 * D) When the time comes for the sender to	 * transmit new DATA chunks, the protocol parameter Max.Burst MUST	 * first be applied to limit how many new DATA chunks may be sent.	 * The limit is applied by adjusting cwnd as follows:	 * 	if ((flightsize + Max.Burst * MTU) < cwnd)	 *		cwnd = flightsize + Max.Burst * MTU	 */	max_burst_bytes = asoc->max_burst * asoc->pmtu;	if ((transport->flight_size + max_burst_bytes) < transport->cwnd) {		transport->cwnd = transport->flight_size + max_burst_bytes;		SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: "				  "transport: %p, cwnd: %d, "				  "ssthresh: %d, flight_size: %d, "				  "pba: %d\n",				  __FUNCTION__, transport,				  transport->cwnd,				  transport->ssthresh,				  transport->flight_size,				  transport->partial_bytes_acked);	}	/* RFC 2960 6.1  Transmission of DATA Chunks	 *	 * B) At any given time, the sender MUST NOT transmit new data	 * to a given transport address if it has cwnd or more bytes	 * of data outstanding to that transport address.	 */	/* RFC 7.2.4 & the Implementers Guide 2.8.	 *	 * 3) ...	 *    When a Fast Retransmit is being performed the sender SHOULD	 *    ignore the value of cwnd and SHOULD NOT delay retransmission.	 */	if (!chunk->fast_retransmit)		if (transport->flight_size >= transport->cwnd) {			retval = SCTP_XMIT_RWND_FULL;			goto finish;		}	/* Nagle's algorithm to solve small-packet problem:	 * Inhibit the sending of new chunks when new outgoing data arrives	 * if any previously transmitted data on the connection remains	 * unacknowledged.	 */	if (!sp->nodelay && sctp_packet_empty(packet) &&	    q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) {		unsigned len = datasize + q->out_qlen;		/* Check whether this chunk and all the rest of pending		 * data will fit or delay in hopes of bundling a full		 * sized packet.		 */		if (len < asoc->pmtu - packet->overhead) {			retval = SCTP_XMIT_NAGLE_DELAY;			goto finish;		}	}	/* Keep track of how many bytes are in flight over this transport. */	transport->flight_size += datasize;	/* Keep track of how many bytes are in flight to the receiver. */	asoc->outqueue.outstanding_bytes += datasize;	/* Update our view of the receiver's rwnd. */	if (datasize < rwnd)		rwnd -= datasize;	else		rwnd = 0;	asoc->peer.rwnd = rwnd;	/* Has been accepted for transmission. */	if (!asoc->peer.prsctp_capable)		chunk->msg->can_abandon = 0;finish:	return retval;}

⌨️ 快捷键说明

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