📄 dcp.c
字号:
* Parameters: tp - the DCCP-related information for the sending socket * type - the option number that is being confirmed * val - the value for the confirmed option */static inline void genanswer (struct dcp_opt *tp, unsigned char type, unsigned char val){ if (tp->opt_a_sz + 4 > DCP_OPTASZ) return; tp->opt_append[tp->opt_a_sz++] = DCP_OPT_ANSWER; tp->opt_append[tp->opt_a_sz++] = 4; tp->opt_append[tp->opt_a_sz++] = type; tp->opt_append[tp->opt_a_sz++] = val; return;}/* Generates a DCCP Choose option, i.e a prefer option, and adds it to the list of options to be included in the next outgoing packet * * Parameters: tp - the DCCP-related information for the sending socket * type - the option number that we are stating our preferences for * val - the prefered value for the option */// NOTE: It appears that we only allow a single preferred value - this is not in line with the protocol specs. We should support multiple// values.static inline void genchoose (struct dcp_opt *tp, unsigned char type, unsigned char val){ if (tp->opt_a_sz + 4 > DCP_OPTASZ) return; tp->opt_append[tp->opt_a_sz++] = DCP_OPT_CHOOSE; tp->opt_append[tp->opt_a_sz++] = 4; tp->opt_append[tp->opt_a_sz++] = type; tp->opt_append[tp->opt_a_sz++] = val; return;}/* Parses and deals with the options that follow the generic packet header * * Parameters: skb - the sk_buff containing the received packet * sk - the socket relating to the outgoing connection which will respond to the packet */static void generic_option_parse (struct sk_buff *skb, struct sock *sk){ unsigned char *p, *eop, *b, *t,g; struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp); if (skb->len < 16) return; // start of the options field p = skb->data + optionoffset (skb->data[4]); // end of the options field b = skb->data + (skb->data[8] * 4); //IS THIS A BUFFER OVERFLOW?? //This is a snaeky place to put it. while ( p < b) { // padding and discard options only take up a single byte if (*p < 32) eop = p+1; else { // making sure that the option does not go past the end of the packet if (!( ((p+1) - skb->data) < skb->len)) break; eop = p + p[1]; if ((eop - skb->data) > skb->len) break; } switch (*p) { case DCP_OPT_PAD: case DCP_OPT_DISCARD: case DCP_OPT_IGNORED: case DCP_OPT_ICOOKIE: case DCP_OPT_ACKV0: case DCP_OPT_ACKV1: case DCP_OPT_RBDROP: case DCP_OPT_TS_ECHO: case DCP_OPT_MOBILE: case DCP_OPT_BCD: break; /* essentially ignore because we're handled other places */ case DCP_OPT_WINCOUNT: /* CCID 3 specific */ if ((eop - p) == 3) { } break; case DCP_OPT_LOSSEVENT: /* CCID 3 specific */ if ((eop - p) == 6) { tp->losseventrate = ntohl((u32) *(p+2)); //is this right? } break; case DCP_OPT_TS: /* Timestamp */ if ((eop - p) == 6) // if statements like this are simple length checking { // copying the timestamp so that we can echo it back on the next packet tp->ts_r_stamp = jiffies; memcpy (&tp->ts_r,p+2,4); } break; case DCP_OPT_ASK: /* If we see this, then we are being asked to change the value of a feature at this location */ if ((eop-p)>=4) switch (p[2]) { case DCP_NEG_TYPE_CC: /* Congestion control negotiation */ g = 0; if (!(tp->negibuf & 0x01)) { // This for loop is a bit shoddy. Without braces, only the first value for CCID in the // ASK option will be used. With braces, only the last value will be used. // POSSIBLE FIX: replace current for statement with - for (t = p+3; t < eop && g == 0; t++) and // insert braces around loop. Close brace needs to be placed before if (!g). // // FIXED - SHANE for (t = p+3; t< eop && g == 0;t++) { if (*t == 2) {#if DCP_DEBUG > 1 printk ("%d: responding to ask ccid 2 by setting ccid and generating answer\n",tp->whoami);#endif tp->ccid = 2; genanswer (tp,DCP_NEG_TYPE_CC,2); g=1; break; } else if(*t ==3) { //This is CCID 3! #if DCP_DEBUG > 0 printk("%d: Got an ask for CCID 3\n",tp->whoami);#endif tp->ccid=3; genanswer(tp,DCP_NEG_TYPE_CC,3); g=1; //I think this means we setup a CCID.#if DCP_DEBUG > 0 printk("INIT RECV TFRC\n");#endif tp->recv_ccb = tfrc_recv_init(tp); break; } } // If none of the CCIDs in the ASK option are acceptable, tell the sender we like CCID 2 // SUGGESTION: We could also prefer CCID 3 as well! if (!g) genchoose (tp,DCP_NEG_TYPE_CC,2); } tp->negibuf |= 0x01; break; case DCP_NEG_TYPE_ACKRATIO: /* Ack Ratio negotiation */ if (!(tp->negibuf &0x02)) { // Are we only allowing one byte for ack ratio option, specs suggest two bytes should be used - SHANE if (p[3]) { tp->ackratio = p[3];#if DCP_DEBUG > 1 printk ("%d: responding to ask ackratio by setting acratio to %d, and generating answer\n",tp->whoami,p[3]);#endif } genanswer (tp,DCP_NEG_TYPE_ACKRATIO,tp->ackratio); } tp->negibuf |= 0x02; break; case DCP_NEG_TYPE_ACKVECTOR: /* Send Ack Vector option negotiation */ if (!(tp->negibuf & 0x04)) { if (p[3]) { tp->uav = p[3];#if DCP_DEBUG > 1 printk ("%d: responding to ask use ackvector by setting uav to %d, and generating answer\n",tp->whoami,p[3]);#endif } genanswer (tp,DCP_NEG_TYPE_ACKVECTOR,p[3]); } tp->negibuf |= 0x04; break; /* I guess it's too bad if we get any other options come through - SHANE */ default: break; } break; /* A Prefer option where the feature location specifies the options it prefers */ case DCP_OPT_CHOOSE: if ((eop-p)>=4) switch (p[2]) { // I guess we don't actually do anything in relation to the sender's preferred values. // Instead, we just go into a negotiation state. If we don't do anything about this later // on, I guess something could be done to make this better - SHANE case DCP_NEG_TYPE_CC: tp->ccid_state = DCP_OPT_STATE_ASKING; break; case DCP_NEG_TYPE_ACKRATIO: tp->rcvr_ratio_state = DCP_OPT_STATE_ASKING; break; case DCP_NEG_TYPE_ACKVECTOR: tp->uav_state = DCP_OPT_STATE_ASKING; break; default: break; } break; /* Confirm feature option */ // If Host A receives a confirm, that sets the value for the A to B half-connection case DCP_OPT_ANSWER: if ((eop-p)>=4) switch (p[2]) { case DCP_NEG_TYPE_CC:#if DCP_DEBUG > 1 printk ("%d confirmed assigned remote ccid of %d EEEEP %d\n",tp->whoami,p[3],tp->ccid);#endif tp->ccid_state = DCP_OPT_STATE_KNOWN; tp->ccid = p[3]; //Why is this not here before?? #if DCP_DEBUG > 0 printk ("ccid of %d %d EEEEP\n",tp->whoami,p[3]);#endif if (tp->ccid == 3) { ///WOOOH lets call some fbd stuff printk("LOADING TFRC\n"); tp->send_ccb = tfrc_send_init(tp); //This works too well it scares me lots } break; case DCP_NEG_TYPE_ACKRATIO:#if DCP_DEBUG > 1 printk ("%d confirmed assigned remote ackratio of %d\n",tp->whoami,p[3]);#endif tp->rcvr_ratio = p[3]; tp->rcvr_ratio_state = DCP_OPT_STATE_KNOWN; break; case DCP_NEG_TYPE_ACKVECTOR:#if DCP_DEBUG > 1 printk ("%d confirmed assigned remote use of ackvector of %d\n",tp->whoami,p[3]);#endif tp->uav_state = DCP_OPT_STATE_KNOWN; tp->uav = p[3]; break; default: break; } break; // unknown feature number default: if (tp->opt_a_sz + 4 <=DCP_OPTASZ) { tp->opt_append[tp->opt_a_sz++] = DCP_OPT_IGNORED; tp->opt_append[tp->opt_a_sz++] = 4; tp->opt_append[tp->opt_a_sz++] = *p; tp->opt_append[tp->opt_a_sz++] = ( (eop -p) > 2) ? p[2] : 0; } break; } p = eop; } return;}/* Puts a connection into the timewait state after receiving a RESET packet * * Parameters: sk - the socket on which the connection is taking place * */static void enter_timewait (struct sock *sk){ struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp);#if DCP_DEBUG > 2 printk ("entering TIMEWAIT\n"); #endif sk->state = DCP_TIMEWAIT; tp->rto_num = 0x1000000; // setting up a timer to expire when the timewait state should end del_timer_sync (&tp->timewait_t); tp->timewait_t.data = (unsigned long) sk; tp->timewait_t.function = (void *) dcp_handle_timewait; tp->timewait_t.expires = jiffies + DCP_TIMEWAIT_LEN; add_timer (&tp->timewait_t); return;}/* A continuation of processing a received packet. Here we deal with the acks attached to the packet, arrange * to ack this packet eventually, add the packet to the received queue, update the connection state if necessary, * and schedule the appropriate responses to CLOSEREQ, CLOSE and RESET packets * * Parameters: sk - the socket on which the packet was received * skb - the sk_buff containing the received packet */static int dccp_enq_rcv (struct sock *sk, struct sk_buff *skb){ int err; struct dcp_opt *tp = &(sk->tp_pinfo.tp_dcp); unsigned char type; err = 0; type =skb->data[4];#if DCP_DEBUG > 2 printk ("PACKET IN: Whoami=%02X, Type=%02X, state=%d, length=%d, interrupt=%d\n", tp->whoami,type,sk->state,skb->len,in_interrupt()); #endif spin_lock (&tp->rsem); dccp_update_ackn (&tp->ackn,skb); /* ackn is the ackn we send, taken from seqno in every pkt */ tp->unacked++; /* protected by rsem */ increment_ackvector (sk, whatis_seqno (skb)); /* note that recvd packet has to be acked */ intake_acks (sk,skb,type); /* give credit for acks received */ if (tp->whoami != WHOAMI_BINDER) generic_option_parse (skb,sk); if (tp->ccid ==3 && sk->state == DCP_OPEN) //don't do it if we're terming or everything will goto hell, and back {//McManus does some dirty so we have to shift right 4 to play nice tp->len_rcv = skb->len; //TODO is this right?? tp->type_rcv = skb->data[4] >> 4; tp->seq_rcv = whatis_seqno (skb); //Hope this works tp->ack_rcv = dccp_whatis_ackn (skb); tp->ndp_rcv = skb->data[9] & 0xf0; tp->ndp_rcv >>=4;// shift it left buddy#if DCP_DEBUG > 2 printk("Tell TFRC about packet of type %d recieved with %d len of opts\n", tp->type_rcv, (skb->data + (skb->data[8] * 4)) - ( skb->data + optionoffset (skb->data[4])));#endif //tell tfrc about this packet, i bet it would like to know.. tfrc_send_packet_recv(tp->send_ccb, skb->data + optionoffset (skb->data[4]), (skb->data + (skb->data[8] * 4)) - ( skb->data + optionoffset (skb->data[4]))); tfrc_recv_packet_recv(tp->recv_ccb, skb->data + optionoffset (skb->data[4]), (skb->data + (skb->data[8] * 4)) - ( skb->data + optionoffset (skb->data[4]))); } if ((type == TYPE_ACK) &&(sk->state == DCP_OPEN)) { kfree_skb(skb); /* todo - process options */ skb = NULL; } else // check we have space in the receive queue for the packet if (((tp->rcvq_t +1) %DCP_RCVQ_SZ) == tp->rcvq_h) err = -ENOBUFS; else { /* queue it */ tp->rcvq[tp->rcvq_t] = skb; if (++tp->rcvq_t == DCP_RCVQ_SZ) tp->rcvq_t = 0; } if (!err) { //TODO [TOM] maybe need to add CCID 3 here! /* if we've got too many unacked packets, we should schedule an ack - by the time that runs it may be obviated though. */ if ((tp->unacked >= tp->ackratio) && (!(tp->flags & FLAG_ACKSCHED)) && (tp->ccid == 2) && (sk->state == DCP_OPEN)) { tp->atask.data =sk; tp->flags |= FLAG_ACKSCHED; schedule_task(&tp->atask); } // we've been asked to close the connection by the client if ((tp->whoami == WHOAMI_SERVER) && ((type == TYPE_CLOSE)||(type==TYPE_RESET))&& ((sk->state == DCP_HALF_CLOSE) ||(sk->state == DCP_OPEN)) ) { if ( (sk->state == DCP_OPEN) || (type == TYPE_CLOSE)) { tp->rtask.data = sk; /* send reset */ schedule_task(&tp->rtask); } sk->state = DCP_CLOSED; } // we've been told by the server that the connection is being reset if ((tp->whoami == WHOAMI_CLIENT) && (type==TYPE_RESET) && ((sk->state == DCP_REQUESTING) || (sk->state == DCP_OPEN)) ) {#if DCP_DEBUG > 1 printk ("dccp client has been reset!\n");#endif enter_timewait (sk); } // the server has sent us a close request if ((tp->whoami == WHOAMI_CLIENT) && (type==TYPE_CLOSEREQ)&& (sk->state == DCP_OPEN)) {#if DCP_DEBUG > 2 printk ("closereq being acted upon\n");#endif sk->state = DCP_HALF_CLOSE; tp->ctask.data = sk; /* send close */ schedule_task(&tp->ctask); } } spin_unlock (&tp->rsem); if (!err) wake_up (&tp->newdata); return err;}/* Performs initial processing on a received packet *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -