int
ip_defrag_stub(struct ip *iph, struct ip **defrag)
{
  int offset, flags, tot_len;
  struct sk_buff *skb;

  numpack++;
  timenow = 0;
  while (timer_head && timer_head->expires < jiffies()) {
    this_host = ((struct ipq *) (timer_head->data))->hf;
    timer_head->function(timer_head->data);
  }
  offset = ntohs(iph->ip_off);
  flags = offset & ~IP_OFFSET;
  offset &= IP_OFFSET;
  if (((flags & IP_MF) == 0) && (offset == 0)) {
    ip_defrag(iph, 0);
    return IPF_NOTF;
  }
  tot_len = ntohs(iph->ip_len);
  skb = (struct sk_buff *) malloc(tot_len + sizeof(struct sk_buff));
  skb->data = (char *) (skb + 1);
  memcpy(skb->data, iph, tot_len);
  skb->truesize = tot_len + 16 + nids_params.dev_addon;
  skb->truesize = (skb->truesize + 15) & ~15;
  skb->truesize += nids_params.sk_buff_size;

  if ((*defrag = (struct ip *)ip_defrag((struct ip *) (skb->data), skb)))
    return IPF_NEW;

  return IPF_ISF;
}
void Performance::Get_Perf_Data(DWORD perf_data_type, int snapshot) {
	// Get the performance data stored by the system.
#if _DEBUG
	cout << "   Getting system performance data." << endl << flush;
#endif

	time_counter[snapshot] = jiffies();
	if (snapshot == LAST_SNAPSHOT) {
		// calculate time diff in clock ticks..
		timediff = (time_counter[LAST_SNAPSHOT] - time_counter[FIRST_SNAPSHOT]);
	}
	
	switch (perf_data_type)	{
	case PERF_PROCESSOR:
		Get_CPU_Counters(snapshot);
		break;
	case PERF_NETWORK_TCP:
		Get_TCP_Counters(snapshot);
		break;
	case PERF_NETWORK_INTERFACE:
		Get_NI_Counters(snapshot);
		break;
	default:
		break;
	}
}
// 疑问: 这一个应该要修改this_host的 ip_frag_mem变量吧????
// 输入:
//      ip头
// 返回:
//      ip队列,这个ip队列已经被挂载到host上了
static struct ipq *
ip_create(struct ip * iph)
{
	struct ipq *qp;
	int ihlen;

	// 调用malloc,申请一个空间
	qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
	if (qp == NULL)
	{
		// NETDEBUG(printk("IP: create: no memory left !\n"));
		nids_params.no_mem("ip_create");
		return (NULL);
	}
	// 填充为0
	memset(qp, 0, sizeof(struct ipq));

	/* Allocate memory for the IP header (plus 8 octets for ICMP). */
	// 多分配8字节,需要保存ip头以及头后面8字节,因为icmp的内容就是ip头+8字节
	ihlen = iph->ip_hl * 4;
	qp->iph = (struct ip *) frag_kmalloc(64 + 8, GFP_ATOMIC);
	if (qp->iph == NULL)
	{
		//NETDEBUG(printk("IP: create: no memory left !\n"));
		nids_params.no_mem("ip_create");
		frag_kfree_s(qp, sizeof(struct ipq));
		return (NULL);
	}
	// 将ip头+8字节的内容保存在iph变量中。
	// 到时候iph变量就能够直接作为icmp的内容,如果有必要发送icmp的话
	memcpy(qp->iph, iph, ihlen + 8);
	// 队列长度=0, 头长度,碎片队列
	qp->len = 0;
	qp->ihlen = ihlen;
	qp->fragments = NULL;
	// 挂载到当前host上
	qp->hf = this_host;

	/* Start a timer for this entry. */
	// jiffies函数返回当前时间,毫秒为单位
	qp->timer.expires = jiffies() + IP_FRAG_TIME;	/* about 30 seconds     */
	// 设置关联
	qp->timer.data = (unsigned long) qp;	/* pointer to queue     */
	// 注册一个超时函数,当超时的时候,会回调这个函数
	qp->timer.function = ip_expire;	/* expire function      */
	// 将这个timer挂载到queue上
	add_timer(&qp->timer);

	/* Add this entry to the queue. */
	// 将这个队列挂载到当前host上
	qp->prev = NULL;
	qp->next = this_host->ipqueue;
	if (qp->next != NULL)
		qp->next->prev = qp;
	this_host->ipqueue = qp;

	return (qp);
}
Exemple #4
0
/*
  Add an entry to the 'ipq' queue for a newly received IP datagram.
  We will (hopefully :-) receive all other fragments of this datagram
  in time, so we just create a queue for this datagram, in which we
  will insert the received fragments at their respective positions.
*/
static struct ipq *
//! ip_create(struct ip * iph)
			ip_create(struct ip * iph,IP_THREAD_LOCAL_P  ip_thread_local_p) {
	struct ipq *qp;
	int ihlen;

//!   qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC);
	qp = (struct ipq *) frag_kmalloc(sizeof(struct ipq), GFP_ATOMIC,ip_thread_local_p);
	if (qp == NULL) {
		// NETDEBUG(printk("IP: create: no memory left !\n"));
		nids_params.no_mem("ip_create");
		return (NULL);
	}
	memset(qp, 0, sizeof(struct ipq));

	/* Allocate memory for the IP header (plus 8 octets for ICMP). */
	ihlen = iph->ip_hl * 4;
	qp->iph = (struct ip *) frag_kmalloc(64 + 8, GFP_ATOMIC, ip_thread_local_p);
	if (qp->iph == NULL) {
		//NETDEBUG(printk("IP: create: no memory left !\n"));
		nids_params.no_mem("ip_create");
//!     frag_kfree_s(qp, sizeof(struct ipq));
		frag_kfree_s(qp, sizeof(struct ipq),ip_thread_local_p);
		return (NULL);
	}
	memcpy(qp->iph, iph, ihlen + 8);
	qp->len = 0;
	qp->ihlen = ihlen;
	qp->fragments = NULL;
//!   qp->hf = this_host;
	qp->hf = ip_thread_local_p->this_host;

	/* Start a timer for this entry. */
//!   qp->timer.expires = jiffies() + IP_FRAG_TIME;	/* about 30 seconds     */
	qp->timer.expires = jiffies(ip_thread_local_p) + IP_FRAG_TIME;	/* about 30 seconds     */
	qp->timer.data = (unsigned long) qp;	/* pointer to queue     */
	qp->timer.function = ip_expire;	/* expire function      */
//!   add_timer(&qp->timer);
	add_timer(&qp->timer,ip_thread_local_p);

	/* Add this entry to the queue. */
	qp->prev = NULL;
//!   qp->next = this_host->ipqueue;
	qp->next = ip_thread_local_p->this_host->ipqueue;
	if (qp->next != NULL)
		qp->next->prev = qp;
//!   this_host->ipqueue = qp;
	ip_thread_local_p->this_host->ipqueue = qp;

	return (qp);
}
Exemple #5
0
__export void __idle(void)
{
    if (jiffies() - _IdleTimer < TICKS_TO_IDLE)
	return;

    if (idle_hook_func && idle_hook_func())
	return;			/* Nonzero return = do not idle */

    sti();
    if (NoHalt)
	cpu_relax();
    else
	hlt();
}
Exemple #6
0
/* Process an incoming IP datagram fragment. */
static char *
ip_defrag(struct ip *iph, struct sk_buff *skb)
{
  struct ipfrag *prev, *next, *tmp;
  struct ipfrag *tfp;
  struct ipq *qp;
  char *skb2;
  unsigned char *ptr;
  int flags, offset;
  int i, ihl, end;

  if (!hostfrag_find(iph) && skb)
    hostfrag_create(iph);

  /* Start by cleaning up the memory. */
  if (this_host)
    if (this_host->ip_frag_mem > IPFRAG_HIGH_THRESH)
      ip_evictor();

  /* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
  if (this_host)
    qp = ip_find(iph);
  else
    qp = 0;

  /* Is this a non-fragmented datagram? */
  offset = ntohs(iph->ip_off);
  flags = offset & ~IP_OFFSET;
  offset &= IP_OFFSET;
  if (((flags & IP_MF) == 0) && (offset == 0)) {
    if (qp != NULL)
      ip_free(qp);		/* Fragmented frame replaced by full
				   unfragmented copy */
    return 0;
  }

  /* ip_evictor() could have removed all queues for the current host */
  if (!this_host)
    hostfrag_create(iph);

  offset <<= 3;			/* offset is in 8-byte chunks */
  ihl = iph->ip_hl * 4;

  /*
    If the queue already existed, keep restarting its timer as long as
    we still are receiving fragments.  Otherwise, create a fresh queue
    entry.
  */
  if (qp != NULL) {
    /* ANK. If the first fragment is received, we should remember the correct
       IP header (with options) */
    if (offset == 0) {
      qp->ihlen = ihl;
      memcpy(qp->iph, iph, ihl + 8);
    }
    del_timer(&qp->timer);
    qp->timer.expires = jiffies() + IP_FRAG_TIME;	/* about 30 seconds */
    qp->timer.data = (unsigned long) qp;	/* pointer to queue */
    qp->timer.function = ip_expire;	/* expire function */
    add_timer(&qp->timer);
  }
  else {
    /* If we failed to create it, then discard the frame. */
    if ((qp = ip_create(iph)) == NULL) {
      kfree_skb(skb, FREE_READ);
      return NULL;
    }
  }
  /* Attempt to construct an oversize packet. */
  if (ntohs(iph->ip_len) + (int) offset > 65535) {
    // NETDEBUG(printk("Oversized packet received from %s\n", int_ntoa(iph->ip_src.s_addr)));
    nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERSIZED, iph, 0);
    kfree_skb(skb, FREE_READ);
    return NULL;
  }
  /* Determine the position of this fragment. */
  end = offset + ntohs(iph->ip_len) - ihl;

  /* Point into the IP datagram 'data' part. */
  ptr = (unsigned char *)(skb->data + ihl);

  /* Is this the final fragment? */
  if ((flags & IP_MF) == 0)
    qp->len = end;

  /*
    Find out which fragments are in front and at the back of us in the
    chain of fragments so far.  We must know where to put this
    fragment, right?
  */
  prev = NULL;
  for (next = qp->fragments; next != NULL; next = next->next) {
    if (next->offset >= offset)
      break;			/* bingo! */
    prev = next;
  }
  /*
    We found where to put this one.  Check for overlap with preceding
    fragment, and, if needed, align things so that any overlaps are
    eliminated.
  */
  if (prev != NULL && offset < prev->end) {
    nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);
    i = prev->end - offset;
    offset += i;		/* ptr into datagram */
    ptr += i;			/* ptr into fragment data */
  }
  /*
    Look for overlap with succeeding segments.
    If we can merge fragments, do it.
  */
  for (tmp = next; tmp != NULL; tmp = tfp) {
    tfp = tmp->next;
    if (tmp->offset >= end)
      break;			/* no overlaps at all */
    nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);

    i = end - next->offset;	/* overlap is 'i' bytes */
    tmp->len -= i;		/* so reduce size of    */
    tmp->offset += i;		/* next fragment        */
    tmp->ptr += i;
    /*
      If we get a frag size of <= 0, remove it and the packet that it
      goes with. We never throw the new frag away, so the frag being
      dumped has always been charged for.
    */
    if (tmp->len <= 0) {
      if (tmp->prev != NULL)
	tmp->prev->next = tmp->next;
      else
	qp->fragments = tmp->next;

      if (tmp->next != NULL)
	tmp->next->prev = tmp->prev;

      next = tfp;		/* We have killed the original next frame */

      frag_kfree_skb(tmp->skb, FREE_READ);
      frag_kfree_s(tmp, sizeof(struct ipfrag));
    }
  }
  /* Insert this fragment in the chain of fragments. */
  tfp = NULL;
  tfp = ip_frag_create(offset, end, skb, ptr);

  /*
    No memory to save the fragment - so throw the lot. If we failed
    the frag_create we haven't charged the queue.
  */
  if (!tfp) {
    nids_params.no_mem("ip_defrag");
    kfree_skb(skb, FREE_READ);
    return NULL;
  }
  /* From now on our buffer is charged to the queues. */
  tfp->prev = prev;
  tfp->next = next;
  if (prev != NULL)
    prev->next = tfp;
  else
    qp->fragments = tfp;

  if (next != NULL)
    next->prev = tfp;

  /*
    OK, so we inserted this new fragment into the chain.  Check if we
    now have a full IP datagram which we can bump up to the IP
    layer...
  */
  if (ip_done(qp)) {
    skb2 = ip_glue(qp);		/* glue together the fragments */
    fprintf(stderr,"this is ipfragment.sd");
	return (skb2);
  }
  return (NULL);
}
Exemple #7
0
/*
 * Get a fresh packet if the buffer is drained, and we haven't hit
 * EOF yet.  The buffer should be filled immediately after draining!
 */
static void tftp_get_packet(struct inode *inode)
{
    uint16_t last_pkt;
    const uint8_t *timeout_ptr;
    uint8_t timeout;
    uint16_t buffersize;
    uint16_t serial;
    jiffies_t oldtime;
    struct tftp_packet *pkt = NULL;
    uint16_t buf_len;
    struct pxe_pvt_inode *socket = PVT(inode);
    uint16_t src_port;
    uint32_t src_ip;
    int err;

    /*
     * Start by ACKing the previous packet; this should cause
     * the next packet to be sent.
     */
    timeout_ptr = TimeoutTable;
    timeout = *timeout_ptr++;
    oldtime = jiffies();

ack_again:
    ack_packet(inode, socket->tftp_lastpkt);

    while (timeout) {
        buf_len = socket->tftp_blksize + 4;
        err = core_udp_recv(socket, socket->tftp_pktbuf, &buf_len,
                            &src_ip, &src_port);
        if (err) {
            jiffies_t now = jiffies();

            if (now-oldtime >= timeout) {
                oldtime = now;
                timeout = *timeout_ptr++;
                if (!timeout)
                    break;
                goto ack_again;
            }
            continue;
        }

        if (buf_len < 4)	/* Bad size for a DATA packet */
            continue;

        pkt = (struct tftp_packet *)(socket->tftp_pktbuf);
        if (pkt->opcode != TFTP_DATA)    /* Not a data packet */
            continue;

        /* If goes here, recevie OK, break */
        break;
    }

    /* time runs out */
    if (timeout == 0)
        kaboom();

    last_pkt = socket->tftp_lastpkt;
    last_pkt++;
    serial = ntohs(pkt->serial);
    if (serial != last_pkt) {
        /*
         * Wrong packet, ACK the packet and try again.
         * This is presumably because the ACK got lost,
         * so the server just resent the previous packet.
         */
#if 0
        printf("Wrong packet, wanted %04x, got %04x\n", \
               htons(last_pkt), htons(*(uint16_t *)(data+2)));
#endif
        goto ack_again;
    }

    /* It's the packet we want.  We're also EOF if the size < blocksize */
    socket->tftp_lastpkt = last_pkt;    /* Update last packet number */
    buffersize = buf_len - 4;		/* Skip TFTP header */
    socket->tftp_dataptr = socket->tftp_pktbuf + 4;
    socket->tftp_filepos += buffersize;
    socket->tftp_bytesleft = buffersize;
    if (buffersize < socket->tftp_blksize) {
        /* it's the last block, ACK packet immediately */
        ack_packet(inode, serial);

        /* Make sure we know we are at end of file */
        inode->size 		= socket->tftp_filepos;
        socket->tftp_goteof	= 1;
        tftp_close_file(inode);
    }
}
Exemple #8
0
/**
 * Send a file to a TFTP  server
 *
 * @param:inode, the inode to store our state in
 * @param:ip, the ip to contact to get the file
 * @param:filename, the file we wanna push
 *
 * @out: open_file_t structure, stores in file->open_file
 * @out: the lenght of this file, stores in file->file_len
 *
 */
__export int tftp_put(struct url_info *url, int flags, struct inode *inode,
                      const char **redir, char *data, int data_length)
{
    struct pxe_pvt_inode *socket = PVT(inode);
    char *buf;
    uint16_t buf_len;
    static const char wrq_tail[] = "octet";
    char wrq_packet_buf[512+4+6];
    char reply_packet_buf[PKTBUF_SIZE];
    int err;
    int wrq_len;
    const uint8_t  *timeout_ptr;
    jiffies_t timeout;
    jiffies_t oldtime;
    uint16_t opcode;
    uint16_t src_port = url->port;
    uint32_t src_ip;
    uint16_t seq = 0;
    size_t chunk = 0;
    int len = data_length;
    int return_code = -ntohs(TFTP_EUNDEF);

    (void)redir;		/* TFTP does not redirect */
    (void)flags;

    if (url->type != URL_OLD_TFTP) {
        /*
         * The TFTP URL specification allows the TFTP to end with a
         * ;mode= which we just ignore.
         */
        url_unescape(url->path, ';');
    }

    if (!src_port)
        src_port = TFTP_PORT;

//    socket->ops = &tftp_conn_ops;
    if (core_udp_open(socket))
        return return_code;

    buf = wrq_packet_buf;
    *(uint16_t *)buf = TFTP_WRQ;  /* TFTP opcode */
    buf += 2;

    buf += strlcpy(buf, url->path, 512);

    buf++;			/* Point *past* the final NULL */
    memcpy(buf, wrq_tail, sizeof wrq_tail);
    buf += sizeof wrq_tail;

    wrq_len = buf - wrq_packet_buf;

    timeout_ptr = TimeoutTable;   /* Reset timeout */
sendreq:
    timeout = *timeout_ptr++;
    if (!timeout)
        return return_code;			/* No file available... */
    oldtime = jiffies();

    core_udp_sendto(socket, wrq_packet_buf, wrq_len, url->ip, src_port);

    /* If the WRITE call fails, we let the timeout take care of it... */
    for (;;) {
        buf_len = sizeof(reply_packet_buf);

        err = core_udp_recv(socket, reply_packet_buf, &buf_len,
                            &src_ip, &src_port);
        if (err) {
            jiffies_t now = jiffies();
            if (now - oldtime >= timeout)
                goto sendreq;
        } else {
            /* Make sure the packet actually came from the server and
               is long enough for a TFTP opcode */
            dprintf("tftp_put: got packet buflen=%d from server %u.%u.%u.%u(%u.%u.%u.%u)\n",
                    buf_len,
                    ((uint8_t *)&src_ip)[0],
                    ((uint8_t *)&src_ip)[1],
                    ((uint8_t *)&src_ip)[2],
                    ((uint8_t *)&src_ip)[3],
                    ((uint8_t *)&url->ip)[0],
                    ((uint8_t *)&url->ip)[1],
                    ((uint8_t *)&url->ip)[2],
                    ((uint8_t *)&url->ip)[3]);
            if ((src_ip == url->ip) && (buf_len >= 2))
                break;
        }
    }

    core_udp_disconnect(socket);
    core_udp_connect(socket, src_ip, src_port);

    /* filesize <- -1 == unknown */
    inode->size = -1;
    socket->tftp_blksize = TFTP_BLOCKSIZE;

    /*
     * Get the opcode type, and parse it
     */
    opcode = *(uint16_t *)reply_packet_buf;
    switch (opcode) {
    case TFTP_ERROR:
        dprintf("tftp_push: received a TFTP_ERROR\n");
        struct tftp_error *te = (struct tftp_error *)(reply_packet_buf+1);
        return_code = -ntohs(te->errcode);
        inode->size = 0;
        goto done;        /* ERROR reply; don't try again */

    case TFTP_ACK:
        dprintf("tftp_push: received a TFTP_ACK\n");
        /* We received a ACK packet, sending the associated data packet */

        /* If data was completly sent, we can stop here */
        if (len == 0) {
            return_code = -ntohs(TFTP_OK);
            goto done;
        }

        /* If the server sequence is not aligned with our, we have an issue
         * Let's break the transmission for now but could be improved later */
        uint16_t srv_seq = ntohs(*(uint16_t *)(reply_packet_buf+2));
        if (srv_seq != seq) {
            printf("tftp_push: server sequence (%"PRIu16") is not aligned with our sequence (%"PRIu16"\n", srv_seq, seq);
            return_code = -ntohs(TFTP_EBADOP);
            goto done;
        }

        /* Let's transmit the data block */
        chunk = len >= 512 ? 512 : len;
        buf = wrq_packet_buf;
        *(uint16_t *)buf = TFTP_DATA;  /* TFTP opcode */
        *((uint16_t *)(buf+2)) = htons(++seq);
        memcpy(buf+4, data, chunk);
        wrq_len = chunk + 4;
        data += chunk;
        len -= chunk;
        timeout_ptr = TimeoutTable;   /* Reset timeout */
        goto sendreq;

    default:
        dprintf("tftp_push: unknown opcode %d\n", ntohs(opcode));
        return_code = -ntohs(TFTP_EOPTNEG);
        goto err_reply;
    }

err_reply:
    /* Build the TFTP error packet */
    dprintf("tftp_push: Failure\n");
    tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error");
    inode->size = 0;

done:
    if (!inode->size)
        core_udp_close(socket);

    return return_code;
}
Exemple #9
0
/**
 * Open a TFTP connection to the server
 *
 * @param:inode, the inode to store our state in
 * @param:ip, the ip to contact to get the file
 * @param:filename, the file we wanna open
 *
 * @out: open_file_t structure, stores in file->open_file
 * @out: the lenght of this file, stores in file->file_len
 *
 */
void tftp_open(struct url_info *url, int flags, struct inode *inode,
               const char **redir)
{
    struct pxe_pvt_inode *socket = PVT(inode);
    char *buf;
    uint16_t buf_len;
    char *p;
    char *options;
    char *data;
    static const char rrq_tail[] = "octet\0""tsize\0""0\0""blksize\0""1408";
    char rrq_packet_buf[2+2*FILENAME_MAX+sizeof rrq_tail];
    char reply_packet_buf[PKTBUF_SIZE];
    int err;
    int buffersize;
    int rrq_len;
    const uint8_t  *timeout_ptr;
    jiffies_t timeout;
    jiffies_t oldtime;
    uint16_t opcode;
    uint16_t blk_num;
    uint64_t opdata;
    uint16_t src_port;
    uint32_t src_ip;

    (void)redir;		/* TFTP does not redirect */
    (void)flags;

    if (url->type != URL_OLD_TFTP) {
        /*
         * The TFTP URL specification allows the TFTP to end with a
         * ;mode= which we just ignore.
         */
        url_unescape(url->path, ';');
    }

    if (!url->port)
        url->port = TFTP_PORT;

    socket->ops = &tftp_conn_ops;
    if (core_udp_open(socket))
        return;

    buf = rrq_packet_buf;
    *(uint16_t *)buf = TFTP_RRQ;  /* TFTP opcode */
    buf += 2;

    buf = stpcpy(buf, url->path);

    buf++;			/* Point *past* the final NULL */
    memcpy(buf, rrq_tail, sizeof rrq_tail);
    buf += sizeof rrq_tail;

    rrq_len = buf - rrq_packet_buf;

    timeout_ptr = TimeoutTable;   /* Reset timeout */
sendreq:
    timeout = *timeout_ptr++;
    if (!timeout)
        return;			/* No file available... */
    oldtime = jiffies();

    core_udp_sendto(socket, rrq_packet_buf, rrq_len, url->ip, url->port);

    /* If the WRITE call fails, we let the timeout take care of it... */
wait_pkt:
    for (;;) {
        buf_len = sizeof(reply_packet_buf);

        err = core_udp_recv(socket, reply_packet_buf, &buf_len,
                            &src_ip, &src_port);
        if (err) {
            jiffies_t now = jiffies();
            if (now - oldtime >= timeout)
                goto sendreq;
        } else {
            /* Make sure the packet actually came from the server and
               is long enough for a TFTP opcode */
            dprintf("tftp_open: got packet buflen=%d from server %u.%u.%u.%u(%u.%u.%u.%u)\n",
                    buf_len,
                    ((uint8_t *)&src_ip)[0],
                    ((uint8_t *)&src_ip)[1],
                    ((uint8_t *)&src_ip)[2],
                    ((uint8_t *)&src_ip)[3],
                    ((uint8_t *)&url->ip)[0],
                    ((uint8_t *)&url->ip)[1],
                    ((uint8_t *)&url->ip)[2],
                    ((uint8_t *)&url->ip)[3]);
            if ((src_ip == url->ip) && (buf_len >= 2))
                break;
        }
    }

    core_udp_disconnect(socket);
    core_udp_connect(socket, src_ip, src_port);

    /* filesize <- -1 == unknown */
    inode->size = -1;
    socket->tftp_blksize = TFTP_BLOCKSIZE;
    buffersize = buf_len - 2;	  /* bytes after opcode */

    /*
     * Get the opcode type, and parse it
     */
    opcode = *(uint16_t *)reply_packet_buf;
    switch (opcode) {
    case TFTP_ERROR:
        inode->size = 0;
        goto done;        /* ERROR reply; don't try again */

    case TFTP_DATA:
        /*
         * If the server doesn't support any options, we'll get a
         * DATA reply instead of OACK. Stash the data in the file
         * buffer and go with the default value for all options...
         *
         * We got a DATA packet, meaning no options are
         * suported. Save the data away and consider the
         * length undefined, *unless* this is the only
         * data packet...
         */
        buffersize -= 2;
        if (buffersize < 0)
            goto wait_pkt;
        data = reply_packet_buf + 2;
        blk_num = ntohs(*(uint16_t *)data);
        data += 2;
        if (blk_num != 1)
            goto wait_pkt;
        socket->tftp_lastpkt = blk_num;
        if (buffersize > TFTP_BLOCKSIZE)
            goto err_reply;	/* Corrupt */

        socket->tftp_pktbuf = malloc(TFTP_BLOCKSIZE + 4);
        if (!socket->tftp_pktbuf)
            goto err_reply;	/* Internal error */

        if (buffersize < TFTP_BLOCKSIZE) {
            /*
             * This is the final EOF packet, already...
             * We know the filesize, but we also want to
             * ack the packet and set the EOF flag.
             */
            inode->size = buffersize;
            socket->tftp_goteof = 1;
            ack_packet(inode, blk_num);
        }

        socket->tftp_bytesleft = buffersize;
        socket->tftp_dataptr = socket->tftp_pktbuf;
        memcpy(socket->tftp_pktbuf, data, buffersize);
        goto done;

    case TFTP_OACK:
        /*
         * Now we need to parse the OACK packet to get the transfer
         * and packet sizes.
         */

        options = reply_packet_buf + 2;
        p = options;

        while (buffersize) {
            const char *opt = p;

            /*
             * If we find an option which starts with a NUL byte,
             * (a null option), we're either seeing garbage that some
             * TFTP servers add to the end of the packet, or we have
             * no clue how to parse the rest of the packet (what is
             * an option name and what is a value?)  In either case,
             * discard the rest.
             */
            if (!*opt)
                goto done;

            while (buffersize) {
                if (!*p)
                    break;	/* Found a final null */
                *p++ |= 0x20;
                buffersize--;
            }
            if (!buffersize)
                break;		/* Unterminated option */

            /* Consume the terminal null */
            p++;
            buffersize--;

            if (!buffersize)
                break;		/* No option data */

            opdata = 0;

            /* do convert a number-string to decimal number, just like atoi */
            while (buffersize--) {
                uint8_t d = *p++;
                if (d == '\0')
                    break;              /* found a final null */
                d -= '0';
                if (d > 9)
                    goto err_reply;     /* Not a decimal digit */
                opdata = opdata*10 + d;
            }

            if (!strcmp(opt, "tsize"))
                inode->size = opdata;
            else if (!strcmp(opt, "blksize"))
                socket->tftp_blksize = opdata;
            else
                goto err_reply; /* Non-negotitated option returned,
				   no idea what it means ...*/


        }

        if (socket->tftp_blksize < 64 || socket->tftp_blksize > PKTBUF_SIZE)
            goto err_reply;

        /* Parsing successful, allocate buffer */
        socket->tftp_pktbuf = malloc(socket->tftp_blksize + 4);
        if (!socket->tftp_pktbuf)
            goto err_reply;
        else
            goto done;

    default:
        printf("TFTP unknown opcode %d\n", ntohs(opcode));
        goto err_reply;
    }

err_reply:
    /* Build the TFTP error packet */
    tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error");
    inode->size = 0;

done:
    if (!inode->size)
        core_udp_close(socket);

    return;
}
Exemple #10
0
void reset_idle(void)
{
    _IdleTimer = jiffies();
    sti();	/* Guard against BIOS/PXE brokenness... */
}
// 每重组一个ip碎片,就会更新对应ipq的timer
//
//
static char *
ip_defrag(struct ip *iph, struct sk_buff *skb)
{
	struct ipfrag *prev, *next, *tmp;
	// 指向一个碎片
	struct ipfrag *tfp;
	// 指向一个队列
	struct ipq *qp;
	// 用来放返回值
	char *skb2;
	// 用来进行字节操作
	unsigned char *ptr;
	int flags, offset;
	int i, ihl, end;

	// 如果成功更新全局变量this_host, 并且skb是有内容的
	if (!hostfrag_find(iph) && skb)
		// 生成一个碎片
		hostfrag_create(iph);

	/* Start by cleaning up the memory. */
	// 如果当前host不为空
	if (this_host)
		// 如果大于上限
		if (this_host->ip_frag_mem > IPFRAG_HIGH_THRESH)
			// 裁剪掉一些ip碎片,直到 ip_frag_mem < IPFRAG_LOW_THRESH
			ip_evictor();

	/* Find the entry of this IP datagram in the "incomplete datagrams" queue. */
	// 如果host存在
	if (this_host)
		// 找到与这个ip头相关的ip队列
		qp = ip_find(iph);
	else
		// 否则设置队列为空
		qp = 0;
	

	/* Is this a non-fragmented datagram? */
	// ip_off是一个16位的字段,高3位用来保存标志信息,低12位用来保存当前碎片的偏移
	offset = ntohs(iph->ip_off);  /* 先把ip_offset这个字段取出来 */
	// 把高3位取出来
	flags = offset & ~IP_OFFSET;
	// 把低13位取出来
	offset &= IP_OFFSET;
	// IP_MF==0表示当前收到是碎片后面没有碎片了,并且当前收到碎片是第一个碎片,
	// 显然当前碎片虽在的ip报文仅仅有一个碎片
	// 那么当前碎片(刚刚收到的碎片)并不需要重组,因此可以返回了
	if (((flags & IP_MF) == 0) && (offset == 0))
	{
		// 如果队列不为空就释放掉
		if (qp != NULL)
			ip_free(qp);		/* Fragmented frame replaced by full unfragmented copy */
		return 0;
	}

	/* ip_evictor() could have removed all queues for the current host */
	// 如果host全部被移出了,那么重新创建一个,针对当前ip头的host
	// 但是,这个host并不会包括任何东西,它是一个空的,没有ip队列
	if (!this_host)
		hostfrag_create(iph);
	// 计算offset和头长度
	// 这个offset是刚刚收到的这个碎片的offset
	offset <<= 3;			/* offset is in 8-byte chunks */
	ihl = iph->ip_hl * 4;


	/*
	  If the queue already existed, keep restarting its timer as long as
	  we still are receiving fragments.  Otherwise, create a fresh queue
	  entry.
	*/
	// 如果队列存在
	if (qp != NULL)
	{
		/* ANK. If the first fragment is received, we should remember the correct
		   IP header (with options) */
		// 如果偏移量为0,可能是该pi报文中的第一个碎片,因此要把前8字节保存下来
		if (offset == 0)
		{
			// 保存头长度
			qp->ihlen = ihl;
			// 拷贝头信息+8字节
			memcpy(qp->iph, iph, ihl + 8);
		}
		// 停止计时
		del_timer(&qp->timer);
		// 重新计时
		qp->timer.expires = jiffies() + IP_FRAG_TIME;	/* about 30 seconds */
		// 设置关联
		qp->timer.data = (unsigned long) qp;	/* pointer to queue */
		// 注册回调函数
		qp->timer.function = ip_expire;	/* expire function */
		// 添加计数器
		add_timer(&qp->timer);
	}
	// 否则队列不存在
	else
	{
		/* If we failed to create it, then discard the frame. */
		// 试图创建一个
		if ((qp = ip_create(iph)) == NULL)
		{
			// 如果创建队列失败,那么释放当前碎片的空间并返回
			kfree_skb(skb, FREE_READ);
			return NULL;
		}
	}

	
	/* Attempt to construct an oversize packet. */
	// 如果头+长度 超长, 释放空间
	if (ntohs(iph->ip_len) + (int) offset > 65535)
	{
		// NETDEBUG(printk("Oversized packet received from %s\n", int_ntoa(iph->ip_src.s_addr)));
		nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERSIZED, iph, 0);
		kfree_skb(skb, FREE_READ);
		return NULL;
	}

	
	/* Determine the position of this fragment. */
	// 刚刚收到的碎片分组 + 刚刚收到的碎片ip包大小 - 刚刚收到的碎片ip包头大小
	// = 刚刚收到的分组的结尾
	end = offset + ntohs(iph->ip_len) - ihl;

	/* Point into the IP datagram 'data' part. */
	// 将指针,指向刚刚收到的碎片ip包的数据开头部分
	// prt 指向肉
	ptr = (unsigned char *)(skb->data + ihl);

	/* Is this the final fragment? */
	// 如果这是最后一个碎片,那么,整个队列的长度,就是当前的end
	// 否则qp->len会在后面更改,因为会有重叠部分
	if ((flags & IP_MF) == 0)
		qp->len = end;

	/*
	  Find out which fragments are in front and at the back of us in the
	  chain of fragments so far.  We must know where to put this
	  fragment, right?
	*/
	prev = NULL;
	// 给定一个offset,在所有的fragments中找到第一个
	// 拥有不小于给定offset的offset的碎片,然后终止循环
	// 由此可以猜测,这一个函数,其实是将某一个新来的碎片插入到
	// 队列合适的位置,保证offset升序排列
	// next 指向的是第一个不小于当前offset的碎片
	// pre指向的是前一个碎片
	for (next = qp->fragments; next != NULL; next = next->next)
	{
		if (next->offset >= offset)
			break;			/* bingo! */
		prev = next;
	}
	/*--------------------------------------------------------------
	注意: 
		next 指向的是第一个排在当前碎片后面的 碎片;
		pre  指向的是第一个排在当前碎片前面的 碎片。
		next 有可能offset与当前碎片的offset一样
	----------------------------------------------------------------*/
	
	
	/*
	  We found where to put this one.  Check for overlap with preceding
	  fragment, and, if needed, align things so that any overlaps are
	  eliminated.
	*/
	// 如果有排在当前碎片前面的分组,并且, 该分组的结束比当前分组的offset大
	// 说明有重叠,应噶修正当前offset,以先来的为准
	if (prev != NULL && offset < prev->end)
	{
		nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);
		i = prev->end - offset;
		// 将当前收到的碎片的offset增加i
		offset += i;		/* ptr into datagram */
		// 将当前收到的碎片的指正向后移动i
		ptr += i;			/* ptr into fragment data */
	}
	
	/*
	  Look for overlap with succeeding segments.
	  If we can merge fragments, do it.
	*/
	// 现在往后查看是否有重叠的
	// 从next开始
	for (tmp = next; tmp != NULL; tmp = tfp)
	{
		// temp总是等于next
		tfp = tmp->next;
		// 如果next的 offset >= 当前分组的end,那就没有问题
		if (tmp->offset >= end)
			break;			/* no overlaps at all */

		// 否则警报
		nids_params.syslog(NIDS_WARN_IP, NIDS_WARN_IP_OVERLAP, iph, 0);
		// 记录当前的结束与下一个碎片的开始重叠多少
		i = end - next->offset;	/* overlap is 'i' bytes */
		// 将next碎片的长度减少i
		tmp->len -= i;		/* so reduce size of    */
		// 将next碎片的开始增加i
		tmp->offset += i;		/* next fragment        */
		// 将指针也要向后移动i
		tmp->ptr += i;
		/*
		  If we get a frag size of <= 0, remove it and the packet that it
		  goes with. We never throw the new frag away, so the frag being
		  dumped has always been charged for.
		*/
		// 如果此时next碎片的长度小于0, 那么摘掉next节点
		if (tmp->len <= 0)
		{
			if (tmp->prev != NULL)
				tmp->prev->next = tmp->next;
			else
				qp->fragments = tmp->next;

			if (tmp->next != NULL)
				tmp->next->prev = tmp->prev;

			// tfp原来就等于next->next,所以原来的next节点被摘掉了
			next = tfp;		/* We have killed the original "next" frame */

			// 释放掉frag节点对应的内存
			frag_kfree_skb(tmp->skb, FREE_READ);
			// 释放掉frag节点
			frag_kfree_s(tmp, sizeof(struct ipfrag));
		}
	}

	
	/* Insert this fragment in the chain of fragments. */
	tfp = NULL;
	// offset是刚刚接收到的碎片偏移,按字节
	// end   是刚刚接收到的碎片的结束字节
	// skb   是传进来的一个内存空间,应该事先分配好
	// prt   是指向这个碎片第一个数据的指针
	tfp = ip_frag_create(offset, end, skb, ptr);
	/*---------------------------------------------------
	注意:  
		ip_frag_create函数只是创建一个ip_frag,还没有吧
		它挂载到队列中
	-----------------------------------------------------*/

	/*
	  No memory to save the fragment - so throw the lot. If we failed
	  the frag_create we haven't charged the queue.
	*/
	if (!tfp)
	{
		nids_params.no_mem("ip_defrag");
		kfree_skb(skb, FREE_READ);
		return NULL;
	}
	
	/* From now on our buffer is charged to the queues. */
	// 将刚刚创建的ip_frag挂载到队列中去了
	tfp->prev = prev;
	tfp->next = next;
	if (prev != NULL)
		prev->next = tfp;
	else
		qp->fragments = tfp;

	if (next != NULL)
		next->prev = tfp;

	/*
	  OK, so we inserted this new fragment into the chain.  Check if we
	  now have a full IP datagram which we can bump up to the IP
	  layer...
	*/
	// 检查是否完整
	if (ip_done(qp))
	{
		skb2 = ip_glue(qp);		/* glue together the fragments */
		return (skb2);
	}

	// 如果没有完整,那么返回空,继续执行
	return (NULL);
}
// 传入一个ip头 和一个 将要被修改的ip
// 返回适当的信号,说明是否有ip 碎片到来,或者是否需要调用回调函数
// 传入的defrag参数,是一个部分重组了的ip数据报
int
ip_defrag_stub(struct ip *iph, struct ip **defrag)
{
	int offset, flags, tot_len;
	struct sk_buff *skb;

	// 包数量增加
	numpack++;
	// 初始化时间
	timenow = 0;
	// 检查第一个超时计时器是否超时,超时,则进入while循环
	// 为什么只是第一个计时器?
	// 因为新的计时器总是在链表尾加入的,所以前面的一定先超时
	while (timer_head && timer_head->expires < jiffies())
	{
		// 将这个超时计时器对应的host加载到this_host全局变量中
		this_host = ((struct ipq *) (timer_head->data))->hf;
		// 执行回调函数,这个回调函数是:
		// ip_expire, 参数是到期了的ip队列,然后把ip队列删除
		timer_head->function(timer_head->data);
	}

	// 获得16为的标志信息位
	offset = ntohs(iph->ip_off);
	// 高3位是分组标志
	flags = offset & ~IP_OFFSET;
	// 低13位是当前ip分组的偏移量,8字节为单位
	offset &= IP_OFFSET;

	// 如果没有更多分组,并且是第一个分组,说明本ip只有一个碎片
	if (((flags & IP_MF) == 0) && (offset == 0))
	{
		// 不需要缓存
		ip_defrag(iph, 0);
		// 直接调用nofiy通知回调
		return IPF_NOTF;
	}

	// 否则是一个正常碎片, 继续往下执行

	// 刚刚收到的ip的总长度
	tot_len = ntohs(iph->ip_len);
	// 申请一块空间
	// 大小为 ip分组长度 + sk_buff大小,后面的sk_buff空间用来作为
	// ip_defrag函数的第二个参数
	skb = (struct sk_buff *) malloc(tot_len + sizeof(struct sk_buff));
	if (!skb)
		nids_params.no_mem("ip_defrag_stub");
	// skb的data段指向自己的开头+sizeof(struct sk_buff)字节
	// 也就是指向自己后面一个sk_buff空间,这就是为什么它多申请了一个sk_buff空间
	skb->data = (char *) (skb + 1);
	// 将ip分组拷贝到这里,应该是整个ip分组的长度
	memcpy(skb->data, iph, tot_len);
	// 总长度 + 16 + sk_buff保留长度
	skb->truesize = tot_len + 16 + nids_params.dev_addon;
	// +15 然后除以16
	skb->truesize = (skb->truesize + 15) & ~15;
	// + sk_buff的大小,默认为168
	skb->truesize += nids_params.sk_buff_size;

	// 关于ip_defrag 的两个参数
	// 其实是两块相邻的空间, skb->data指向的是skb后一个skb
	// 应该返回一个整理好的碎片组
	if ((*defrag = (struct ip *)ip_defrag((struct ip *) (skb->data), skb)))
		// 如果成功,返回: 有新ip碎片到来
		return IPF_NEW;

	// 否则返回其他,出错
	return IPF_ISF;
}