📄 dcp.c
字号:
struct sock *sk; struct dcp_opt *tp; sk = (struct sock *)s; tp = &(sk->tp_pinfo.tp_dcp);#if DCP_DEBUG > 1 printk ("TIMEWAIT Complete\n");#endif sk->state = DCP_CLOSED; unregister_dccp_sk (sk); return NULL;}/* Gets the sequence number from a given packet * * Parameters: skb - the sk_buff containing the packet */static inline u32 whatis_seqno (struct sk_buff *skb){ u32 c; /* the seq_no occupies three bytes so we need to do a little calculating to get the number */ /* ackn is the highest serial # we've seen */ c = ((unsigned char) skb->data[5]) * 0x10000; c += ((unsigned char) skb->data[6]) * 0x100; c += ((unsigned char) skb->data[7]); return c;}/* Sets the ack number to match the sequence number of the received packet. The difference between the old ack number and the sequence * number must be less than 1001. * * Parameters: t - the ack number to be updated * skb - the received packet containing the sequence number to update to */static inline void dccp_update_ackn (unsigned int *t, struct sk_buff *skb){ unsigned int c, diff; // getting the sequence number from the packet c = whatis_seqno (skb); /* we only want to update *t if c > *t (allowing for wraps), but we've got to do it sanely.. if c is more than 1000 greater than t we'll ignore - todo why +/- 1000 */ if (c >= *t) diff = c - *t; else /* wrap */ diff = c + (0x1000000 - *t); if ((diff<=1000) || (*t == 0xefffffff)|| (0x1000000 - diff <= 1000) ) *t =c; return;}/* Sets the number of received but unacked packets to zero. Only should be used when opening or closing a connection. * * Parameters: tp - the structure containing all the miscellaneous information regarding a half-connection */static void inline clear_unacked (struct dcp_opt *tp){ spin_lock (&tp->rsem); tp->unacked = 0; spin_unlock(&tp->rsem); return;}/* Returns the number of bytes of header information prior to the option fields * * Parameters: type - the type of packet we want to know the header length of */static inline int optionoffset (unsigned char type){ int p =0; //-TOM should type be &0xf0 ?? /* Possibly, depends how much you trust the packet to have the reserved bits correctly set to zero. I'll do it anyway - SHANE */ type = type & 0xF0; switch (type) { case TYPE_DATA: p = 12; break; case TYPE_REQUEST: case TYPE_RESPONSE: case TYPE_DATAACK: case TYPE_ACK: case TYPE_CLOSEREQ: case TYPE_CLOSE: p = 16; break; case TYPE_RESET: p = 20; break; case TYPE_MOVE: p = 28; break; } return p;}/* Checks to see if the given sequence number has been acknowledged - i.e. it is in the congestion window vector * * Parameters: sk - the socket upon which the connection is taking place * sn - the sequence number being searched for in the congestion window */static inline u32 value_in_cwndvector (struct sock *sk, u32 sn){ /* todo - this is a wildly inefficient way of doing this */ struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp); u32 gap; unsigned char *t; if (tp->cv_ts == tp->cv_hs) /* empty */ return 0; /* missing */ if (sn >= tp->cv_ts) gap = (sn - tp->cv_ts); else /* sn has wrapped but ts hasn't */ gap = (sn + (0x1000000 - tp->cv_ts)); if (gap > tp->cv_sz) return 0; t = tp->cv_tp + (gap*4); if (t >= (tp->cwndvector + (tp->cv_sz*4))) t -= (tp->cv_sz *4); /* wrapped */ return *( (u32 *) t);}/* Checks the Ack Vector buffer stored locally to see if any acknowledgements have been lost * * Parameters: sk - the socket that the connection uses * */static int noackloss (struct sock *sk){ struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp); /* csn = current sequence number */ u32 csn; u16 v,rv; rv = 1; v = 0; // ackc_wsn is highest sequence number that has been checked for loss previously if (tp->ackc_wsn == 0x1000000) tp->ackc_wsn = tp->av_ts; // go backwards through ack vector until we get 3 received acks for (csn=tp->av_hs; ((tp->ackc_wsn != csn) && (v < DCP_NUMDUPACKS)); csn = wrapdec_24(csn)) if (value_in_ackvector(sk,csn) != 3) v++; if (v==DCP_NUMDUPACKS) { // Do we have any unreceived acks following our three received acks? // If so, we have some ack loss while (tp->ackc_wsn != csn) { if (value_in_ackvector (sk,csn) == 3) /* missing */ { rv = 0; break; } csn = wrapdec_24(csn); } } // I'm not 100% sure with this. I think ackc_wsn should be set to csn when we exit the for loop. There'll // be a little overlap, but the current method runs the risk of not detecting ack loss on packets that were // sent just prior to this function call - SHANE tp->ackc_wsn = tp->av_hs; return rv;}/* Changes flags to represent the fact that there may be room in the congestion window again * * Parameters: sk - the socket which may now have space in its cwnd * */static void dcp_writeable (struct sock *sk){ struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp); struct socket *sock = sk->socket; /* for poll sleepers */ // if we've got room in the congestion window now, set things up so that we can send packets again if (tp->outstanding < tp->cwnd) { clear_bit(SOCK_NOSPACE, &sock->flags); if (sk->sleep && waitqueue_active(sk->sleep)) wake_up_interruptible(sk->sleep); if (sock->fasync_list && !(sk->shutdown&SEND_SHUTDOWN)) sock_wake_async(sock, 2, POLL_OUT); } return;}/* Processes the ack vector for CCID 2. Updates congestion window and ack ratios as necessary, based on * the frequency and loss of acknowledgements. * * Parameters: sk - the socket which the connection is active on * skb - the sk_buff containing the DCCP packet with the ack vector * type - the type of DCCP packet in skb */static void intake_acks (struct sock *sk, struct sk_buff *skb, unsigned char type) /* we return number of packets acked */{ /* rsem lock held */ u32 rackn,c4=0,csn; struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp); unsigned char *p, *eop,i,j,v, congevent,lookforts,*data; /* todo, this really belongs in a bottom half */ int rv =0; // TFRC need not bother... if (tp->ccid !=2) return; if ((type == TYPE_REQUEST) || (type == TYPE_DATA)) return ; /* have no ackn */ rackn = dccp_whatis_ackn (skb); // rv += credit_pkt (sk,rackn); if (((sk->state == DCP_OPEN) && tp->checkingrtt)) { lookforts = 1; c4 = tp->checkingsn; } else lookforts = 0; //Check if this is the ack for a rtt finding packet if (lookforts && (c4 == rackn)) { /* todo, accept timestamp here, either on specific sn or any old timestamp */ new_rtt_sample (tp, jiffies - tp->checkingrtt); tp->checkingrtt = 0; lookforts = 0; } p = skb->data + optionoffset (skb->data[4]); data = skb->data + (skb->data[8] * 4); // Cycling through option list, looking for any ACK VECTOR options to process while ( p < data) // Option codes less than 32 are always one byte so we can instantly skip if (*p < 32) p++; else { /* Don't go off the end of the skbuff! */ if (!( ((p+1) - skb->data) < skb->len)) return ; // this is where the next option starts eop = p + p[1];#if DCP_DEBUG > 2 printk ("%d EOP LEN (w=%d) type=%d optlen=%d (eop is %d from b), p is %d from b\n", tp->whoami, skb->len, type,p[1],eop-skb->data, p-skb->data); #endif if ((eop - skb->data) > skb->len) return ; /* we're clear to end of option */ // We only do this for the ACK vector option if ((*p == DCP_OPT_ACKV0) || (*p == DCP_OPT_ACKV1)) for (p+=2; p < eop;p++) { v = *p >> 7 ; /* really 6, but we don't know what to do with ecn bit yet - todo */ v = !v; // if the state is RECEIVED if (v) { // why is the below line commented out - it looks kinda important - SHANE // rv += credit_pkt (sk,rackn); if (lookforts && (c4 == rackn)) { /* todo, accept timestamp here, either on specific sn or any old timestamp */ new_rtt_sample (tp, jiffies - tp->checkingrtt); tp->checkingrtt = 0; lookforts = 0; } } rackn = wrapdec_24(rackn); // getting the run length and crediting all those packets j = *p & 0x3F; for (i=0;i<j;i++) { // Since this has appeared three times now it could probably be made into a separate function - SHANE if (v) { // Same again - should really uncomment this stuff at some stage // rv += credit_pkt (sk,rackn); if (lookforts && (c4 == rackn)) { /* todo, accept timestamp here, either on specific sn or any old timestamp */ new_rtt_sample (tp, jiffies - tp->checkingrtt); tp->checkingrtt = 0; lookforts = 0; } } rackn = wrapdec_24(rackn); } } else p = eop; } if (rv) /* acked new data - grow cwnd */ { if (tp->cwnd < tp->ssthresh) /* slowstart */ { /* Increase congestion window by one for every ACK received */ tp->cwnd++; rcvr_ratio_inbounds(tp); dcp_writeable(sk); /* for polling sleepers */ } else /* avoidance */ { /* Every time the congestion window is filled, increase the size of it by one */ /* avoidp represents the number of acked outgoing packets in the congestion window */ tp->avoidp += tp->rcvr_ratio; if (tp->avoidp >= tp->cwnd) /* a windows worth of acks */ { tp->cwnd++; rcvr_ratio_inbounds(tp); dcp_writeable(sk); /* for polling sleepers */ tp->avoidp = 0; } }#if DCP_DEBUG > 2 printk ("%d positive cwnd adjustment, now %d (R%d)\n",tp->whoami,tp->cwnd,tp->avoidp);#endif } /* check to see if we've created a fast retransmit case by being the third newer packet to be acked in front of an older one.. we'll scan from newest going back, loooking for NUMDUPACKS (3) hits, after that we'll fill in any outstandings (and dec ctr) where we find them */ if (tp->outstanding && rv) { congevent = 0; v = 0; for (csn=tp->cv_hs; ((tp->cv_ts != csn) && (v < DCP_NUMDUPACKS)); csn = wrapdec_24(csn)) if (value_in_cwndvector(sk,csn)) v++; if (v==DCP_NUMDUPACKS) { // finding all the sequence numbers that have not been acked and crediting them while ((tp->cv_ts != csn) && tp->outstanding) { if (!value_in_cwndvector (sk,csn)) /* missing */ { congevent = 1; // we know it is lost, so we can credit it safely enough rv += credit_pkt (sk,csn); } csn = wrapdec_24(csn); } } if (congevent) {#if DCP_DEBUG > 1 printk ("LOSS DETECTED - cwnd now %d\n",tp->cwnd);#endif tp->checkingrtt = tp->checkingsn = 0; /* karn says we don't want to count any outstanding window measures */ tp->cwnd = tp->cwnd /2; /* halve congestion window in response to loss */ tp->avoidp = 0; if (!tp->cwnd) tp->cwnd = 1; tp->ssthresh = tp->cwnd; rcvr_ratio_inbounds(tp); } } // ackc = count of congestion windows that have not seen any loss of acks // ackp = number of packets that have been credited in the current window if (rv) { tp->ackp += rv; if (tp->ackp >= tp->cwnd) { /* full window of data */ tp->ackp = 0; if (noackloss(sk)) { tp->ackc++; if ((tp->rcvr_ratio > 1) && /* reduce ackratio - see lots of acks as path is clear */ (tp->ackc >= tp->cwnd / (tp->rcvr_ratio * tp->rcvr_ratio - tp->rcvr_ratio))) { tp->rcvr_ratio--; rcvr_ratio_inbounds(tp); tp->ackc = 0; } } else { /* we're losing acks, so we want to up ackratio to send less of them and ease congestion*/ tp->rcvr_ratio *= 2; tp->ackc = 0; rcvr_ratio_inbounds(tp); } } } return;}/* Updates the receiver's ack ratio value to ensure it conforms to the CCID 2 specifications (cc. March 2003!) * * Parameters: tp - the dcp_opt structure containing the congestion window and ack ratio information for this connection * */static inline void rcvr_ratio_inbounds (struct dcp_opt *tp){ /* Copied from the CCID 2 specs: * There are three constraints on the Ack Ratio. First, it is always * an integer. Second, it is never greater than half the congestion * window (with fractions rounded up). Third, it is at least two for a * congestion window of four or more packets. * */ if (tp->rcvr_ratio > (tp->cwnd/2)) { tp->rcvr_ratio = tp->cwnd/2; if (tp->cwnd % 2) tp->rcvr_ratio++; } if ((tp->cwnd >= 4) && (tp->rcvr_ratio < 2)) tp->rcvr_ratio = 2; return;}/* Generates a DCCP Answer option i.e. a confirm option, in response to a DCCP Change, or Ask, option and adds it to the list of options * to be included in the next outgoing packet *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -