📄 dcp.c
字号:
#define DCP_DATA_EVENT_OPEN ((tp->rcvq_h != tp->rcvq_t) || (sk->state != DCP_OPEN) || tp->shake_defer)#define wrapdec_24(i) ((!i) ? i=0xffffff : --i)//#define wrapdec_24(i) ((!i) ? 0xffffff : --i)//#define wrapdec_24(i) if (i >0) i--; else i=0xffffff; /* code *//* Gets an option from a provided option list and copies it into a buffer. * Designed for use with TFRC as standard DCCP options are dealt with in other functions, i.e. generic_option_parse() * * Parameters: options - the options list * optlen - the length of the options list * type - the option id that is being looked for * buffer - the buffer to copy the option into * buflen - the length of the buffer * */int dccp_get_option(char *options, int optlen, int type, char *buffer, int buflen){ int i, j, size; u_int8_t t; #if DCP_DEBUG > 0 printk("TFRC reckons it wants to get an OPTION\n");#endif for (i=0; i < optlen; ) { t = options[i++]; // options with codes less than 32 are only one byte if(t >= 32){ size = options[i++] - 2; if (t == type) { // buffer would overflow! if(size > buflen) return 0; // copying option code into the buffer for (j=0; j<size; j++) buffer[j] = options[i++]; return size; } i += size; } } /* If we get here the option was not found */ return 0;}/* Adds an option to the option list. * Used by TFRC to append TFRC-specific options. Standard DCCP options are dealt with in other functions * * Parameters: tp - the dcp_opt structure describing the current connection * type - the type of option to append * option - the option data * optlen - the length of the option data * */int dccp_add_option(struct dcp_opt *tp, u_int8_t type, char *option , u_int8_t optlen){ /* NOTE: Just in case you're confused, the +2 used throughout this function is because optlen does * not include the option type and size bytes, just the data. */ spin_lock (&tp->rsem); //lock this for the length feild to avoid race conditions #if DCP_DEBUG > 0 printk("TFRC reckons it wants to append an OPTION %i\n",type);#endif // making sure we've got space to add the option if (tp->opt_a_sz + optlen +2 > DCP_OPTASZ) {#if DCP_DEBUG > 2 printk("DCCP run out of space for %i len(%i) using %d of %d\n",type,optlen, tp->opt_a_sz, DCP_OPTASZ);#endif //shuldent spinlock be released befor return? I try, BJORN. spin_unlock(&tp->rsem); return 1; } tp->opt_append[tp->opt_a_sz++] = type; tp->opt_append[tp->opt_a_sz++] = optlen+2; memcpy(&tp->opt_append[tp->opt_a_sz],option,optlen); tp->opt_a_sz+=optlen; //+2 here creates a DOS attack that takes out the other side and ethereal. NICE.. // so is the above line wrong then??? - SHANE spin_unlock (&tp->rsem); //This should be easy enough! return 0;}//ASSUME LOCK HERE MOFO~!/* Schedules an ACK if necessary under TFRC * * Parameters: tp - the dcp_opt structure describing the connection * extra - unused * */int dccp_output(register struct dcp_opt *tp, unsigned char extra ){#if DCP_DEBUG > 0 printk("TFRC reckons it wants to SEND a packet\n");#endif // if an ack has been scheduled, start arranging for one if((!(tp->flags & FLAG_ACKSCHED))) {#if DCP_DEBUG > 0 printk("TFRC did schedule an ack\n");#endif // tp->atask.data =sk; tp->flags |= FLAG_ACKSCHED; schedule_task(&tp->atask); } //Told mcmanaus to schedule that sucker. //dccp_schedule_ack_locked(tp, sk); //HACKQ! atask hopefully holds the socket descriptor, if it doesn't it was like that when i found it.... // wake_up (&tp->newdata); //TODO: what does this actullay achieve, i just copied it from dccp_schedule_ack.. KERNEL_ASSERT(0); return 0;}/* Converts the packet buffer into a build_t structure - used for packets not involved with the connection handshake * * Parameters: b - a previously declared build_t structure * h - the packet buffer representing the header of the packet to be transmitted * hl - the length of the packet header * iov - the data portion of the packet * */inline static int mkbuildt (struct build_t *b, unsigned char *h, u16 hl, struct iovec *iov){ b->h = h; b->hl = hl; b->iov = iov; b->check = 0; b->kdb= NULL; /* occasionally (on handshake) we'll have data not from an iovec, but from a kernel buffer.. */ b->kdbl =0; return 0;}/* Converts the packet buffer into a build_t structure - used for connection handshake packets * * Parameters b - a previously declared build_t structure * h - the packet buffer representing the header of the packet to be transmitted * hl - the length of the packet header * kdb - the data portion of the packet * kbdl - the length of the data portion of the packet * */inline static int mkbuildt_k (struct build_t *b, unsigned char *h, u16 hl, unsigned char *kdb, int kdbl){ b->h = h; b->hl = hl; b->iov = NULL; b->check = 0; b->kdb=kdb; b->kdbl =kdbl; return 0;}/* A hash function for sockets, based on the remote address, remote port and local port * * Parameters: ra - the remote address for the connection that uses this socket * rp - the remote port for the connection that uses this socket * lp - the local port for the connection that uses this socket */static inline u16 skhash (u32 ra, u16 rp, u16 lp){ u32 t; t = ra * rp *lp + rp + lp +ra; return t % DCP_SK_HASH_SZ;}/* Finds a socket in the sock hashtable * * Parameters: locala - the IP address of the local end of the connection, needed for matching * remotea - the IP address of the remote end of the connection, needed for hashing and matching * svc - the service code for the socket, needed for matching bound sockets * lp - the port used at the local end of the connection, needed for hashing and matching * rp - the port used at the remote end of the connection, needed for hashing and matching * ptype - the type of packet received, used to distinguish between bound and connected sockets * */static struct sock *lookup_dccp_sk ( u32 locala, u32 remotea, u32 svc, u16 lp, u16 rp, unsigned char ptype){ struct dccp_sk_list_t *p, *el, *dccp_sk_list; u16 n,nl; /* bound sockets (not connected) have a zeroed ra and rport */ el = NULL; // if the packet is a request then we aren't connected yet, use 0 for ra and rp if (ptype == TYPE_REQUEST) n = skhash(0,0,lp); else n = skhash(remotea,rp,lp); nl = n & 0xF; read_lock (dccp_table_lock+nl); dccp_sk_list = dccp_sk_hash[n]; // cycle through the list of sockets matching the skhash, looking for a socket whose attributes match // the ones given as parameters if (ptype == TYPE_REQUEST) { /*printk ("looking for request in chain %d - %X %d %d\n",n,locala, ntohs(lp),ntohs(rp)); */ for (p = dccp_sk_list; (p && (!el)); p = p->n) { // ra and rp cannot be set because we aren't connected! if ( (!p->remotea) && (!p->rp) && (p->lp == lp) && (p->svc == svc) && ((!locala) || (locala == p->locala))) el = p; /*printk ("%p %X %d %X %d %X, %X %d %X %d %X\n",el, remotea, ntohs(rp), locala, ntohs(lp), svc, p->remotea, ntohs(p->rp), p->locala, ntohs(p->lp), p->svc); */ } } else { for (p = dccp_sk_list; (p && (!el)); p = p->n) if ((remotea == p->remotea) && (lp == p->lp) && (rp == p->rp) /* normal connected case */ && ((!locala) || (locala == p->locala))) /* svc isn't considerd here */ el = p; } read_unlock (dccp_table_lock+nl); // return NULL if we didn't find a matching socket return el ? el->sk : NULL;}/* inline static void output_stats( struct sock *sk;) {#if DCP_DEBUG > 2struct dcp_opt *tp;tp = &(sk->tp_pinfo.tp_dcp);printk("ackr:%d\trtt:%d\tcwnd:%d\trcvr:%d\twndcount:%djiffies:%ld\n", tp->ackratio, tp->rtt, tp->cwnd,tp->rcvr_ratio,tp->wndcount,jiffies);#endif}*//* Translates the DCCP header information into local variables * * Parameters: skb - the sk_buff containing the DCCP packet * la - the location IP address * ra - the remote IP address * svc - the service code * lp - the location port * rp - the remote port * */static unsigned char parse_dccp_pkt (struct sk_buff *skb, u32 *la, u32 *ra, u32 *svc, u16 *lp, u16 *rp){ u32 t; u16 rcheck,tc,lcheck; unsigned char cslen,hl,rv; if (skb->len < 12) return TYPE_INVALID; // saving a copy of the checksum and then zeroing it for computation memcpy (&rcheck,skb->data+10,2); memset (skb->data+10,0,2); /* zero it for computation */ // getting checksum coverage field cslen = skb->data[9] & 0x0F; /* OK, I think the processing of cslen here is not up to date with the latest specs * IF cslen is 0 then checksum covers the whole packet * Otherwise the checksum covers cslen - 1 * 4 bytes of the application data, plus all the headers, options etc * IF cslen - 1 * 4 is greater than the length of the application data, then the packet must be ignored. * - SHANE */ if (cslen==15) tc = skb->len; else { // hl = header length hl = skb->data[8]; tc = ((int)cslen+ (int)hl) *4; tc = (tc < skb->len) ? tc : skb->len; } // checksum is broken1 t = 0; t = csum_partial (skb->data,tc,t); lcheck = csum_fold (t); memcpy (skb->data+10,&rcheck,2); /* put it back */ if (rp) memcpy (rp,skb->data,2); if (lp) memcpy (lp,skb->data+2,2); // rv = packet type rv = skb->data[4] & 0xF0; if (lcheck != rcheck) {#if DCP_DEBUG > 0 printk ("dccp check-mismatch (%d: type %d) over %d of %d: sending %X, Rcv %X\n", ntohs (*lp),rv, tc,skb->len,rcheck,lcheck);#endif return TYPE_INVALID; } // svc = service code if (rv == TYPE_REQUEST) { if (skb->len < 16) return TYPE_INVALID; if (svc) memcpy (svc,skb->data+12,4); } else if (svc) *svc = 0; if (ra) *ra = skb->nh.iph->saddr; if (la) *la = skb->nh.iph->daddr; return rv;}/* Asks for the socket to send a CLOSE packet. Called via tp->ctask. * * Parameters: vsk - the socket which must send the CLOSE packet */static void dccp_safe_close (void *vsk){ struct sock *sk = vsk; dccp_send_close (sk,TYPE_CLOSE); /* send close */ return;}/* Asks for the socket to send a RESET packet. Called via tp->rtask. * * Parameters: sk - the socket which must send the CLOSE packet */static void dccp_safe_reset (void *vsk){ /* we are only invoked by server side when a close or reset comes int */ struct sock *sk = vsk; dccp_reset (sk,0); unregister_dccp_sk(sk); return;}/* Creates an ACK packet and sends it, as long as we've got too many unacked packets. Called via tp->atask. * * Parameters: vsk - the socket on which the connection is taking place */static void dccp_schedule_ack (void *vsk){ struct sock *sk = vsk; struct dcp_opt *tp; struct build_t b; unsigned char *pbuf,*ackv,*mt; struct ipcm_cookie ipc; struct rtable *rt; int ackvl,nma; spin_lock (&tp->rsem); tp = &(sk->tp_pinfo.tp_dcp); nma =1; //spin_lock (&tp->rsem); #if DCP_DEBUG > 2 printk ("acktimer\n"); #endif if ((sk->state == DCP_OPEN) && // we're due to send an ACK, according to the ACK vector (tp->unacked >= tp->ackratio)) { ipc.oif = sk->bound_dev_if; ipc.opt = sk->protinfo.af_inet.opt; ipc.addr = sk->daddr; pbuf = kmem_cache_alloc (dccp_slab,GFP_ATOMIC); memcpy (pbuf,&sk->sport,2); memcpy (pbuf+2,&sk->dport,2); pbuf[4] = TYPE_ACK; /* ack pkt, includes the 4 rsvd bits */ pbuf[8] = 0x04; /* header length - 4 32 bit words */ pbuf[9] = dcp_write_ndp (&tp->ndp,1); /* ndp=tp->ndp and cslen=15 */ memset (pbuf+10,0,2); /* checksum - starts at 0 for calc */ pbuf[12] = 0; /* reserved */ tp->unacked = 0; /* cause we're locked */ dccp_write_24 (&tp->ackn, pbuf+13,0); generic_option_negotiation (tp); /* cleaned out by genackvector */ ackv =dccp_generate_ackvector (sk, &ackvl); /* keep before seqno++ */ dccp_write_24 (&tp->seq, pbuf+5,1); /* incs sn for me */ // if we have an ack vector to append if (ackvl) { pbuf[8] += ackvl /4; if ((ackvl + 16) > MAX_DCP_REQUEST_SZ) //if the ackvl is too long to fit in pbuf, then make pbuf bigger { nma = 0; //mt = kmalloc(ackvl+16,GFP_ATOMIC); mt = vmalloc(ackvl+16); memcpy (mt,pbuf,16); kmem_cache_free (dccp_slab,pbuf); pbuf = mt; } memcpy (pbuf+16,ackv,ackvl); } // build and send our ACK ip_route_output(&rt, sk->daddr, sk->saddr,RT_CONN_FLAGS(sk) , ipc.oif); mkbuildt (&b, pbuf, 16+ackvl,NULL); ip_build_xmit (sk,dccp_getfrag, &b,16+ackvl,&ipc,rt,MSG_DONTWAIT); if (nma) kmem_cache_free (dccp_slab,pbuf); else{ vfree(pbuf); //kfree (pbuf); } //kfree (ackv); vfree(ackv); } // an ACK is no longer scheduled so update the flags tp->flags &= ~FLAG_ACKSCHED; spin_unlock (&tp->rsem); wake_up (&tp->newdata); return;}/* Closes the connection following the end of the TIMEWAIT state * * Parameters: s - the socket which is to be closed */static void *dcp_handle_timewait (unsigned long s){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -