Logo Search packages:      
Sourcecode: scamper version File versions  Download package

scamper_ip6.c

/*
 * scamper_ip6.c
 *
 * $Id: scamper_ip6.c,v 1.7 2007/05/10 02:45:53 mjl Exp $
 *
 * Copyright (C) 2006-2007 The University of Waikato
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 2.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#if defined(__APPLE__)
#include <stdint.h>
#endif

#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>

#if defined(__linux__)
#define __FAVOR_BSD
#endif

#include <netinet/in.h>
#include <netinet/ip6.h>
#include <arpa/inet.h>

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <stdio.h>

#if defined(DMALLOC)
#include <dmalloc.h>
#endif

#include "scamper_addr.h"
#include "scamper_dl.h"
#include "scamper_probe.h"
#include "scamper_ip6.h"

#include "scamper_debug.h"
#include "utils.h"

/*
 * ip6_ext_route0
 *
 * this function builds an IPv6 Routing Header of Type 0, as defined by
 * RFC 2460.  It does not set bytes 5-8, which were defined in RFC 1883
 * as being a loose/strict bitmap.  In RFC 2460, these bits are just set
 * to zero.
 */
static int ip6_ext_route0(struct ip6_hdr *ip6,
                    const scamper_probe_ipopt_t *opt,
                    uint8_t *buf, size_t *len)
{
  int i, addrc;
  ssize_t off;

  /* the header value is always at least 16 bytes in length */
  assert(opt->len >= 16);

  if(*len < (size_t)(opt->len + 8))
    {
      *len = opt->len + 8;
      return -1;
    }

  /* calculate how many addresses will be in the routing header */
  addrc = opt->len / 16;

  /*
   * the length field counts number of 8 octets, excluding the first 8 bytes
   * of routing header.
   * RFC 2460 says this value is twice the number of addresses in the header
   */
  buf[1] = addrc * 2;

  /* routing type = 0 */
  buf[2] = 0;

  /* number of segments left */
  buf[3] = addrc;

  /* set the next four bytes to zero */
  memset(buf+4, 0, 4);

  off = 8;

  /*
   * copy in addresses 1 .. N, skipping over the first address which is
   * swapped with ip6->ip6_dst after this loop
   */
  for(i=1; i<addrc; i++)
    {
      memcpy(buf+off, opt->val+(16 * i), 16);
      off += 16;
    }

  /*
   * the current destination address becomes the last address in the routing
   * header
   */
  memcpy(buf+off, &ip6->ip6_dst, 16);
  off += 16;

  /* the first address in the option becomes the destination address */
  memcpy(&ip6->ip6_dst, opt->val, 16);

  *len = off;
  return 0;
}

static int ip6_ext_frag(struct ip6_hdr *ip6,
                  const scamper_probe_ipopt_t *opt,
                  uint8_t *buf, size_t *len)
{
  /* the header value is always 6 bytes in length */
  assert(opt->len == 6);

  /* make sure the pktbuf has at least enough space left for this */
  if(*len < 8)
    {
      *len = 8;
      return -1;
    }

  /* the length of this header is set to zero since it is of fixed size */
  buf[1] = 0;

  /* copy in the fragmentation value */
  memcpy(buf+2, opt->val, 6);

  *len = 8;
  return 0;
}

/*
 * scamper_ip6_build
 *
 * given a scamper probe structure, and a place in the pktbuf to dump the
 * header, write the header.
 *
 * return 0 on success, -1 on fail.
 * on entry, buflen contains the length of the pktbuf left for the header.
 * on exit, buflen contains the length of the space used if zero was returned,
 * or the space that would be necessary on fail.
 *
 * the caller is still required to set ip6->ip6_plen when it knows how much
 * payload is going to be included.
 */
int scamper_ip6_build(scamper_probe_t *probe, uint8_t *buf, size_t *len)
{
  static int (*const func[])(struct ip6_hdr *, const scamper_probe_ipopt_t *,
                       uint8_t *, size_t *) = {
    ip6_ext_route0,  /* SCAMPER_PROBE_IPOPTS_V6ROUTE0 */
    ip6_ext_frag,    /* SCAMPER_PROBE_IPOPTS_V6FRAG */
  };

  static const int nxthdrval[] = {
    43, /* SCAMPER_PROBE_IPOPTS_V6ROUTE0 */
    44, /* SCAMPER_PROBE_IPOPTS_V6FRAG */
  };

  struct ip6_hdr        *ip6;
  scamper_probe_ipopt_t *opt;
  size_t                 off, tmp;
  int                    i;

  /* get a pointer to the first byte of the buf for the IPv6 header */
  ip6 = (struct ip6_hdr *)buf;
  off = sizeof(struct ip6_hdr);

  if(off <= *len)
    {
      /* build the ip6 header */
      ip6->ip6_flow = htonl(0x60000000 | probe->pr_ip_flow);
      ip6->ip6_hlim = probe->pr_ip_ttl;
      memcpy(&ip6->ip6_src, probe->pr_ip_src->addr, 16);
      memcpy(&ip6->ip6_dst, probe->pr_ip_dst->addr, 16);
    }

  /*
   * if there are no IPv6 extension headers, then the ip6_nxt field is set
   * to the underlying type of the packet
   */
  if(probe->pr_ipoptc == 0)
    {
      if(off <= *len)
      {
        ip6->ip6_nxt = probe->pr_ip_proto;
      }
      goto done;
    }

  /*
   * the next header field in the IPv6 header is set to the type of the
   * first extension header
   */
  if(off <= *len)
    {
      ip6->ip6_nxt = nxthdrval[probe->pr_ipopts[0].type];
    }

  /* build the body of the IPv6 extension headers area */
  for(i=0; i<probe->pr_ipoptc; i++)
    {
      if(off + 1 < *len)
      {
        /* the last extension header uses the ip protocol value */
        if(i == probe->pr_ipoptc-1)
          {
            buf[off] = probe->pr_ip_proto;
          }
        else
          {
            buf[off] = nxthdrval[probe->pr_ipopts[i+1].type];
          }
      }

      /* obtain a handy pointer to the current extension header */
      opt = &probe->pr_ipopts[i];

      /* work out how much space is left in the buf */
      tmp = *len - off;

      /* handle the extension header */
      func[opt->type](ip6, opt, buf, &tmp);

      off += tmp;
    }

 done:
  /*
   * figure out what to return based on if there was enough space in the
   * packet payload to compose the IPv6 header
   */
  if(off > *len)
    {
      *len = off;
      return -1;
    }

  *len = off;
  return 0;
}

/*
 * scamper_ip6_hlen
 *
 * given an IPv6 header outline in the probe structure, return how large
 * the IPv6 header length will be.
 */
int scamper_ip6_hlen(scamper_probe_t *probe, size_t *ip6hlen)
{
  *ip6hlen = 0;
  return scamper_ip6_build(probe, NULL, ip6hlen);
}

Generated by  Doxygen 1.6.0   Back to index