📄 dcp.c
字号:
* Parameters: skb - the sk_buff containing the received packet */static int dccp_rcv (struct sk_buff *skb){ struct sock *sk; u32 locala, remotea, svc; u16 lport, rport; unsigned char ptype; /* extract the info we need to get the list lookup */ if ((ptype = parse_dccp_pkt (skb,&locala,&remotea,&svc,&lport,&rport)) == TYPE_INVALID) { printk ("dccp: Packet is not a valid DCCP packet\n"); goto drop; } /* lookup the sk for it.. */ sk = lookup_dccp_sk(0,remotea,svc,lport,rport,ptype); if (!sk) { printk ("dccp: rcvd dccp packet for non existant session %08X:%d to %08X:%d (svc=%X)\n", remotea,ntohs(rport),locala,ntohs(lport),svc); goto rst; } /* if found we want to signal newdata via wake_up() after placing skb in a circular q.. */ if (dccp_enq_rcv (sk,skb)) {#if DCP_DEBUG > 0 printk ("dccp: rcvd dccp packet but there doesn't seem to be any room for it\n");#endif goto drop; } /* don't touch skb after this point - it's either been xferred to another handler, or freed completely if it was just an ack */ //TODO: [TOM] MAYBE here is better for CCID3? //no here is in the upper half and its baaad here@! return 0; /* OK! */rst: if ( (skb->data[4] != TYPE_RESET)) { itask.data = skb; /* some risk of lost resets here - thats ok by me */ if (schedule_task(&itask)) return 0; }drop: /* we'll drop the packet if we can't find the sk, or if there is no room in the q */ /* if we don't queue this thing up we want to drop it */#if DCP_DEBUG > 0 printk ("dccp: dropping packet\n");#endif kfree_skb(skb); return 0;}static struct inet_protocol dccp_protocol = {handler: dccp_rcv,err_handler: NULL,protocol: DCCP_PROTO, /* 33 as per eddie kohler 4/25/2002 */name: "DCCP"};/* Sets a different outstanding packet to be the round trip time estimator, * in the event of the previous round trip time measurement timing out without a response * * Parameters: vd - the socket on which the connection is taking place * */static void *dccp_charged_timeout (unsigned long vd){ /* ok - we've had an RTO timer go off */ struct sock *sk; struct dcp_opt *tp; u32 ld,lsn; sk = (struct sock *)vd; tp = &(sk->tp_pinfo.tp_dcp); spin_lock (&tp->rsem); // if the timer is actually set and the outstanding timer packet is in the congestion window if ((tp->rto_num != 0x1000000) && (ld = value_in_cwndvector (sk,tp->rto_num))) { // nope, we haven't actually timed out - ideally, we wouldn't reach this point if ((jiffies - ld) < tp->rto) { /* just reschedule it */ tp->retransmit_timer.expires = ld + tp->rto; mod_timer (&tp->retransmit_timer,tp->retransmit_timer.expires); } else { #if DCP_DEBUG > 1 printk ("PACKET TIMEOUT %d\n",tp->rto_num);#endif // The outstanding timer packet has not been acked before the timeout tp->checkingrtt = tp->checkingsn = 0; /* karn says we don't want to count any outstanding window measures */ lsn = tp->rto_num; tp->rto_num = 0x1000000; // we've given up on this packet so remove it from the congestion window credit_pkt(sk,lsn); // Our timing info has to come from another outstanding packet asap while ((tp->cv_ts != tp->cv_hs) && tp->outstanding) { tp->retransmit_timer.function = (void *) dccp_charged_timeout; tp->retransmit_timer.data = (unsigned long) sk; // we use cv_tp because it should be the next packet ACKed tp->retransmit_timer.expires = *((u32 *)tp->cv_tp) + tp->rto; // making sure our timer isn't due to expire sometime in the past if (tp->retransmit_timer.expires <= jiffies) {#if DCP_DEBUG > 2 printk ("CONCURRENT PACKET TO %d\n",tp->cv_ts);#endif credit_pkt(sk,tp->cv_ts); } else { /*printk ("would set new rto timer to %d (delta %d)\n", tp->retransmit_timer.expires, tp->retransmit_timer.expires - jiffies); */ tp->rto_num = tp->cv_ts; add_timer (&tp->retransmit_timer); break; } } // all data packets have been lost so adjust cwnd, ssthresh et al. if (jiffies > tp->timeout_barrier) /* can't adj more than once a window*/ { tp->timeout_barrier = jiffies + tp->rtt; tp->ssthresh = tp->cwnd/2; tp->cwnd = 1; if (!tp->ssthresh) tp->ssthresh = 1; rcvr_ratio_inbounds(tp); } } } else tp->rto_num = 0x1000000; spin_unlock (&tp->rsem); wake_up (&tp->newdata); return NULL;}/* Updates timer related variables to signify that the packet needs to be re-sent - used with regards to connection * handshakes and closing. Not applicable to data or acks * * Parameters: s - the socket on which the connection is taking place * */static void *dcp_resend (unsigned long s){ struct sock *sk; struct dcp_opt *tp; sk = (struct sock *)s; tp = &(sk->tp_pinfo.tp_dcp); // I presume something checks the value of timer_expired later on to see if a resend is required - SHANE tp->timer_expired = 1; tp->retries++;#if DCP_DEBUG > 2 printk ("dccp: Timer Expired at %d:%X\n",tp->whoami,(unsigned)jiffies);#endif wake_up (&tp->newdata); return NULL;}/* Updates rtt information based on the new sample received * * Parameters: tp - the dcp_opt structure containing the current rtt information * M - the rtt estimate * */static inline void new_rtt_sample (struct dcp_opt *tp, u16 M){ /* lock held */ u16 err; // deviation calculations if (M >= tp->rtt) { err = M - tp->rtt; tp->rtt = tp->rtt + (err >> 3); } else { err = tp->rtt - M; tp->rtt = tp->rtt - (err >> 3); } tp->rtt_d = tp->rtt_d + ((err - tp->rtt_d) >> 2); // updating the timeout value tp->rto = tp->rtt + (tp->rtt_d << 2); // Updating minimum rtt if necessary if (tp->rtt < DCP_MIN_RTT) tp->rtt = DCP_MIN_RTT;#if DCP_DEBUG > 1 printk ("new rtt sample: %d, rtt is now %d\n",M,tp->rtt);#endif return;}/* Initializes the ack and congestion window vectors for a socket * * Parameters: sk - the socket for which the vectors need to be initialized * */static int finalize_init(struct sock *sk){ /* setup vector trackers */ struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp); tp->av_sz = tp->cv_sz = INIT_VECTOR_SIZE; /* initially track this number of packets - keep as multiple of 8 */ tp->av_hs =tp->av_ts = tp->cv_hs = tp->cv_ts = 0; //tp->ackvector = kmalloc(tp->av_sz/4, GFP_KERNEL); /* 2 bits entry */ tp->ackvector = vmalloc(tp->av_sz/4); /* 2 bits entry */ //tp->cwndvector = kmalloc(tp->cv_sz*4,GFP_KERNEL); /* 32 bits per entry */ tp->cwndvector = vmalloc(tp->cv_sz*4L); /* 32 bits per entry */ memset (tp->ackvector,0xff,tp->av_sz/4); memset (tp->cwndvector,0,tp->cv_sz*4); tp->av_tp = tp->ackvector; tp->cv_hp = tp->cv_tp = tp->cwndvector; tp->av_clist = NULL; return 0;}/* Updates the congestion window to reflect the receipt of an ack for a particular outstanding packet. * Also used to remove packets that are regarded as lost from the congestion window * * Parameters: sk - the socket where the connection is taking place * sn - the sequence number of the packet that has been acked * */static int credit_pkt (struct sock *sk, u32 sn){ struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp); u32 bo,gap,*rt; unsigned char *t; int rv = 0;#if DCP_DEBUG > 2 printk ("credit request %d\n",sn); #endif /* rsem lock held */ /* opposite of charge pkt, in reaction to rcvd ack on cwndvector */ if (tp->cv_ts == tp->cv_hs) /* empty */ goto ackofack_q; 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) /* probably from past */ { /* printk ("excessive gap %d (sn=%d, ts=%d)\n",gap,sn,tp->cv_ts); */ goto ackofack_q; } // four bytes for each entry bo = gap*4; t = tp->cv_tp+bo; if (t >= (tp->cwndvector + (tp->cv_sz*4))) /* wrapped */ t -= tp->cv_sz*4; rt = (u32 *) t; if (*rt) /* packets were set */ { tp->outstanding--; #if DCP_DEBUG > 2 printk ("%d Giving Credit for %d - %d\n",tp->whoami,sn,*rt); #endif rv++; dcp_writeable(sk); /* for polling sleepers */ *rt = 0; /* clear the packet in vector */ rt = (u32 *) tp->cv_tp; // moving the tail pointer ahead to the first un-credited packet in the cwnd, or the head pointer // whichever comes first while ((tp->cv_hs != tp->cv_ts) && (! *rt)) { tp->cv_tp += 4; if (tp->cv_tp >= (tp->cwndvector + (tp->cv_sz*4))) tp->cv_tp = tp->cwndvector; /* wrap */ tp->cv_ts += 1; if (tp->cv_ts == 0x1000000) tp->cv_ts = 0; rt = (u32 *) tp->cv_tp; } if (tp->rto_num == sn) /* timer was set for this packet */ { /* see if we've got another outstanding pkt */ if (tp->outstanding && (tp->cv_hs != tp->cv_ts)) { tp->rto_num = tp->cv_ts; tp->retransmit_timer.expires = *rt + tp->rto; mod_timer (&tp->retransmit_timer,tp->retransmit_timer.expires); } else { tp->rto_num = 0x1000000; /* not used */ del_timer_sync (&tp->retransmit_timer); /* cancel it */ } } return rv; }ackofack_q: check_clist (tp,sn); /* maybe an ack of ack? */ return rv;}/* Adds a packet to the congestion window * * Parameters: sk - the socket on which the connection is taking place * sn - the sequence number of the packet being sent * */static inline void charge_pkt (struct sock *sk, u32 sn){ /* assume a lock */ /* charge a sending packet against cwnd - store it's sn so we can credit cwnd when it gets acked */ struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp); u32 tc, gap; unsigned char *n,*t; u32 *rt; // only needed for CCID 2 if (tp->ccid !=2) return; // congestion window is empty so we're the first entry if (tp->cv_ts == tp->cv_hs) tp->cv_ts = tp->cv_hs = sn; 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 ; /* probably from past */ tp->outstanding++; // setting the timer if necessary if (tp->rto_num == 0x1000000) /* no timer set */ { tp->rto_num = sn; tp->retransmit_timer.function = (void *) dccp_charged_timeout; tp->retransmit_timer.data = (unsigned long) sk; tp->retransmit_timer.expires = jiffies + tp->rto; add_timer (&tp->retransmit_timer); } t = tp->cv_tp+(gap*4); if (t >= (tp->cwndvector + (tp->cv_sz*4))) /* wrapped */ t -= tp->cv_sz*4; rt = (u32 *) t; *rt = jiffies; /* set bits */#if DCP_DEBUG > 2 printk ("%d Charging for %d - %p\n",tp->whoami,sn,t);#endif // we haven't increment sn yet tp->cv_hs = sn +1; if (tp->cv_hs == 0x1000000) tp->cv_hs = 0; tp->cv_hp = t; if (gap > (tp->cv_sz - 128)) /* running out of room, should expand cwnd vector */ { //n = kmalloc (tp->cv_sz*8,GFP_ATOMIC); /* a doubling */ n = vmalloc (tp->cv_sz*8); /* a doubling */ memset (n+tp->cv_sz*4,0x00,tp->cv_sz*4); /* new half all missing */ tc = (tp->cwndvector + (tp->cv_sz*4)) - tp->cv_tp; memcpy (n,tp->cv_tp, tc); /* tail to end */ memcpy (n+tc,tp->cwndvector,tp->cv_tp - tp->cwndvector); /* start to tail */ tp->cv_tp = n; tp->cv_sz = tp->cv_sz * 2; /* counted in items, so it's a doubling */ //kfree (tp->cwndvector); vfree(tp->cwndvector); tp->cwndvector = n; tp->cv_hp = tp->cv_tp +(gap*4); }#if DCP_DEBUG > 2 printk ("dccp %d: charge pkt [%d] - outstanding now %d\n",tp->whoami,sn,tp->outstanding);#endif return;}/* Updates the ack vector when a packet has been received. * * Parameters: sk - the socket the packet was received on * sn - the sequence number of the received packet * */static inline int increment_ackvector (struct sock *sk, u32 sn){ /* assume a lock */ /* we've recvd a packet, and want to put it in the local ackvector so that when we send it off the av, it will be included */ struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp); u32 offset, tc,gap; unsigned char *n,*t; tp->av_ts = tp->av_hs = sn; if (sn >= tp->av_ts) { gap = (sn - tp->av_ts); } else /* sn has wrapped but ts hasn't */ { gap = (sn + (0x1000000 - tp->av_ts)); } offset = gap %4; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -