示例#1
0
// THIS NEEDS TO BE CHECKED FOR BUFFER OVERFLOWS
// IMPORTANT!!!!
int handle_firmware(node n, artnet_packet p) {
  int length, offset, block_length, total_blocks, block_id;
  artnet_firmware_status_code response_code = ARTNET_FIRMWARE_FAIL;

  // run callback if defined
  if (check_callback(n, p, n->callbacks.firmware))
    return ARTNET_EOK;

  /*
   * What happens if an upload is less than 512 bytes ?????
   */

  if ( p->data.firmware.type == ARTNET_FIRMWARE_FIRMFIRST ||
       p->data.firmware.type == ARTNET_FIRMWARE_UBEAFIRST) {
    // a new transfer is initiated

    if (n->firmware.peer.s_addr == 0) {
      //new transfer
      // these are 2 byte words, so we get a total of 1k of data per packet
      length = artnet_misc_nbytes_to_32( p->data.firmware.length ) *
        sizeof(p->data.firmware.data[0]);

      // set parameters
      n->firmware.peer.s_addr = p->from.s_addr;
      n->firmware.data = malloc(length);

      if (n->firmware.data  == NULL) {
        artnet_error_malloc();
        return ARTNET_EMEM;
      }
      n->firmware.bytes_total = length;
      n->firmware.last_time = time(NULL);
      n->firmware.expected_block = 1;

      // check if this is a ubea upload or not
      if (p->data.firmware.type == ARTNET_FIRMWARE_FIRMFIRST)
        n->firmware.ubea = 0;
      else
        n->firmware.ubea = 1;

      // take the minimum of the total length and the max packet size
      block_length = min((unsigned int) length, ARTNET_FIRMWARE_SIZE *
        sizeof(p->data.firmware.data[0]));

      memcpy(n->firmware.data, p->data.firmware.data, block_length);
      n->firmware.bytes_current = block_length;

      if (block_length == length) {
        // this is the first and last packet
        // upload was less than 1k bytes
        // this behaviour isn't in the spec, presumably no firmware will be less that 1k
        response_code = ARTNET_FIRMWARE_ALLGOOD;

        // do the callback here
        if (n->callbacks.firmware_c.fh != NULL)
          n->callbacks.firmware_c.fh(n,
                                     n->firmware.ubea,
                                     n->firmware.data,
                                     n->firmware.bytes_total,
                                     n->callbacks.firmware_c.data);

      } else {
        response_code = ARTNET_FIRMWARE_BLOCKGOOD;
      }

    } else {
      // already in a transfer
      printf("First, but already for a packet\n");

      // send a failure
      response_code = ARTNET_FIRMWARE_FAIL;
    }

  } else if (p->data.firmware.type == ARTNET_FIRMWARE_FIRMCONT ||
             p->data.firmware.type == ARTNET_FIRMWARE_UBEACONT) {
    // continued transfer
    length = artnet_misc_nbytes_to_32(p->data.firmware.length) *
      sizeof(p->data.firmware.data[0]);
    total_blocks = length / ARTNET_FIRMWARE_SIZE / 2 + 1;
    block_length = ARTNET_FIRMWARE_SIZE * sizeof(uint16_t);
    block_id = p->data.firmware.blockId;

    // ok the blockid field is only 1 byte, so it wraps back to 0x00 we
    // need to watch for this
    if (n->firmware.expected_block > UINT8_MAX &&
       (n->firmware.expected_block % (UINT8_MAX+1)) == p->data.firmware.blockId) {

      block_id = n->firmware.expected_block;
    }
    offset = block_id * ARTNET_FIRMWARE_SIZE;

    if (n->firmware.peer.s_addr == p->from.s_addr &&
        length == n->firmware.bytes_total &&
        block_id < total_blocks-1) {

      memcpy(n->firmware.data + offset, p->data.firmware.data, block_length);
      n->firmware.bytes_current += block_length;
      n->firmware.expected_block++;

      response_code = ARTNET_FIRMWARE_BLOCKGOOD;
    } else {
      printf("cont, ips don't match or length has changed or out of range block num\n" );

      // in a transfer not from this ip
      response_code = ARTNET_FIRMWARE_FAIL;
    }

  } else if (p->data.firmware.type == ARTNET_FIRMWARE_FIRMLAST ||
             p->data.firmware.type == ARTNET_FIRMWARE_UBEALAST) {
    length = artnet_misc_nbytes_to_32( p->data.firmware.length) *
      sizeof(p->data.firmware.data[0]);
    total_blocks = length / ARTNET_FIRMWARE_SIZE / 2 + 1;

    // length should be the remaining data
    block_length = n->firmware.bytes_total % (ARTNET_FIRMWARE_SIZE * sizeof(uint16_t));
    block_id = p->data.firmware.blockId;

    // ok the blockid field is only 1 byte, so it wraps back to 0x00 we
    // need to watch for this
    if (n->firmware.expected_block > UINT8_MAX &&
       (n->firmware.expected_block % (UINT8_MAX+1)) == p->data.firmware.blockId) {

      block_id = n->firmware.expected_block;
    }
    offset = block_id * ARTNET_FIRMWARE_SIZE;

    if (n->firmware.peer.s_addr == p->from.s_addr &&
        length == n->firmware.bytes_total &&
        block_id == total_blocks-1) {

      // all the checks work out
      memcpy(n->firmware.data + offset, p->data.firmware.data, block_length);
      n->firmware.bytes_current += block_length;

      // do the callback here
      if (n->callbacks.firmware_c.fh != NULL)
        n->callbacks.firmware_c.fh(n, n->firmware.ubea,
          n->firmware.data,
          n->firmware.bytes_total / sizeof(p->data.firmware.data[0]),
          n->callbacks.firmware_c.data);

      // reset values and free
      reset_firmware_upload(n);

      response_code = ARTNET_FIRMWARE_ALLGOOD;
      printf("Firmware upload complete\n");

    } else if (n->firmware.peer.s_addr != p->from.s_addr) {
      // in a transfer not from this ip
      printf("last, ips don't match\n" );
      response_code = ARTNET_FIRMWARE_FAIL;
    } else if (length != n->firmware.bytes_total) {
      // they changed the length mid way thru a transfer
      printf("last, lengths have changed %d %d\n", length, n->firmware.bytes_total);
      response_code = ARTNET_FIRMWARE_FAIL;
    } else if (block_id != total_blocks -1) {
      // the blocks don't match up
      printf("This is the last block, but not according to the lengths %d %d\n", block_id, total_blocks -1);
      response_code = ARTNET_FIRMWARE_FAIL;
    }
  }

  return artnet_tx_firmware_reply(n, p->from.s_addr, response_code);
}
示例#2
0
/*
 * Set if_head to point to a list of iface_t structures which represent the
 * interfaces on this machine
 * @param ift_head the address of the pointer to the head of the list
 */
static int get_ifaces(iface_t **if_head) {
  struct ifconf ifc;
  struct ifreq *ifr, ifrcopy;
  struct sockaddr_in *sin;
  int len, lastlen, flags;
  char *buf, *ptr;
  iface_t *if_tail, *iface;
  int ret = ARTNET_EOK;
  int sd;

  *if_head = if_tail = NULL;

  // create socket to get iface config
  sd = socket(PF_INET, SOCK_DGRAM, 0);

  if (sd < 0) {
    artnet_error("%s : Could not create socket %s", __FUNCTION__, strerror(errno));
    ret = ARTNET_ENET;
    goto e_return;
  }

  // first use ioctl to get a listing of interfaces
  lastlen = 0;
  len = INITIAL_IFACE_COUNT * sizeof(struct ifreq);

  for (;;) {
    buf = malloc(len);

    if (buf == NULL) {
      artnet_error_malloc();
      ret = ARTNET_EMEM;
      goto e_free;
    }

    ifc.ifc_len = len;
    ifc.ifc_buf = buf;
    if (ioctl(sd, SIOCGIFCONF, &ifc) < 0) {
      if (errno != EINVAL || lastlen != 0) {
        artnet_error("%s : ioctl error %s", __FUNCTION__, strerror(errno));
        ret = ARTNET_ENET;
        goto e_free;
      }
    } else {
      if (ifc.ifc_len == lastlen)
        break;
      lastlen = ifc.ifc_len;
    }
    len += IFACE_COUNT_INC * sizeof(struct ifreq);
    free(buf);
  }

  // loop through each iface
  for (ptr = buf; ptr < buf + ifc.ifc_len;) {
    ifr = (struct ifreq*) ptr;

    // work out length here
#ifdef HAVE_SOCKADDR_SA_LEN
    len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
#else
    switch (ifr->ifr_addr.sa_family) {
#ifdef  IPV6
      case AF_INET6:
        len = sizeof(struct sockaddr_in6);
        break;
#endif
      case AF_INET:
      default:
        len = sizeof(SA);
        break;
    }
#endif

    ptr += sizeof(ifr->ifr_name) + len;

    // look for AF_INET interfaces
    if (ifr->ifr_addr.sa_family == AF_INET) {
      ifrcopy = *ifr;
      if (ioctl(sd, SIOCGIFFLAGS, &ifrcopy) < 0) {
        artnet_error("%s : ioctl error %s" , __FUNCTION__, strerror(errno));
        ret = ARTNET_ENET;
        goto e_free_list;
      }

      flags = ifrcopy.ifr_flags;
      if ((flags & IFF_UP) == 0)
        continue; //skip down interfaces

      if ((flags & IFF_LOOPBACK))
        continue; //skip lookback

      iface = new_iface(if_head, &if_tail);
      if (!iface)
        goto e_free_list;

      sin = (struct sockaddr_in *) &ifr->ifr_addr;
      iface->ip_addr.sin_addr = sin->sin_addr;

      // fetch bcast address
#ifdef SIOCGIFBRDADDR
      if (flags & IFF_BROADCAST) {
        if (ioctl(sd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
          artnet_error("%s : ioctl error %s" , __FUNCTION__, strerror(errno));
          ret = ARTNET_ENET;
          goto e_free_list;
        }

        sin = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
        iface->bcast_addr.sin_addr = sin->sin_addr;
      }
#endif
      // fetch hardware address
#ifdef SIOCGIFHWADDR
      if (flags & SIOCGIFHWADDR) {
        if (ioctl(sd, SIOCGIFHWADDR, &ifrcopy) < 0) {
          artnet_error("%s : ioctl error %s", __FUNCTION__, strerror(errno));
          ret = ARTNET_ENET;
          goto e_free_list;
        }
        memcpy(&iface->hw_addr, ifrcopy.ifr_hwaddr.sa_data, ARTNET_MAC_SIZE);
      }
#endif

    /* ok, if that all failed we should prob try and use sysctl to work out the bcast
     * and hware addresses
     * i'll leave that for another day
     */
    }
  }
  free(buf);
  return ARTNET_EOK;

e_free_list:
  free_ifaces(*if_head);
e_free:
  free(buf);
  close(sd);
e_return:
  return ret;
}