Пример #1
0
usb_dev_handle *usb_open(struct usb_device *dev)
{
   // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Send packet
   pkt_init(pkt, UsbOpen);
   pkt_adduint(pkt, dev->bus->location);
   pkt_adduint(pkt, dev->devnum);
   pkt_send(pkt, fd);

   // Get response
   int res = -1, devfd = -1;
   if(pkt_recv(fd, pkt) > 0 && pkt_op(pkt) == UsbOpen) {
      Iterator it;
      pkt_begin(pkt, &it);
      res = iter_getint(&it);
      devfd = iter_getint(&it);
   }

   // Evaluate
   usb_dev_handle* udev = NULL;
   if(res >= 0) {
      udev = malloc(sizeof(usb_dev_handle));
      udev->fd = devfd;
      udev->device = dev;
      udev->bus = dev->bus;
      udev->config = udev->interface = udev->altsetting = -1;
   }

   pkt_release();
   debug_msg("returned %d (fd %d)", res, devfd);
   return udev;
}
Пример #2
0
/* libusb(5):
 * Interrupt transfers.
 */
int usb_interrupt_write(usb_dev_handle *dev, int ep, usb_buf_t bytes, int size, int timeout)
{
   // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Prepare packet
   pkt_init(pkt, UsbInterruptWrite);
   pkt_addint(pkt, dev->fd);
   pkt_addint(pkt, ep);
   pkt_addstr(pkt, size, bytes);
   pkt_addint(pkt, timeout);
   pkt_send(pkt, fd);

   // Get response
   int res = -1;
   if(pkt_recv(fd, pkt) > 0 && pkt_op(pkt) == UsbInterruptWrite) {
      Iterator it;
      pkt_begin(pkt, &it);
      res = iter_getint(&it);
   }

   // Return response
   pkt_release();
   debug_msg("returned %d", res);
   return res;
}
Пример #3
0
int usb_reset(usb_dev_handle *dev)
{
   // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Prepare packet
   pkt_init(pkt, UsbReset);
   pkt_addint(pkt, dev->fd);
   pkt_send(pkt, fd);

   // Get response
   int res = -1;
   if(pkt_recv(fd, pkt) > 0 && pkt_op(pkt) == UsbReset) {
      Iterator it;
      pkt_begin(pkt, &it);

      // Read result
      res = iter_getint(&it);
   }

   // Return response
   pkt_release();
   debug_msg("returned %d", res);
   return res;
}
Пример #4
0
int usb_get_driver_np(usb_dev_handle *dev, int interface, char *name, unsigned int namelen)
{
   // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Send packet
   pkt_init(pkt, UsbGetKernelDriver);
   pkt_addint(pkt,  dev->fd);
   pkt_addint(pkt,  interface);
   pkt_adduint(pkt, namelen);
   pkt_send(pkt, fd);

   // Get response
   int res = -1;
   if(pkt_recv(fd, pkt) > 0 && pkt_op(pkt) == UsbGetKernelDriver) {
      Iterator it;
      pkt_begin(pkt, &it);
      res = iter_getint(&it);

      // Error
      if(res) {
         error_msg("%s: could not get bound driver", __func__);
      }

      // Save string
      strncpy(name, iter_getstr(&it), namelen - 1);
      name[namelen - 1] = '\0';
   }

   pkt_release();
   debug_msg("returned %d (%s)", res, name);
   return res;
}
Пример #5
0
int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
{
   // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Prepare packet
   pkt_init(pkt, UsbInterruptRead);
   pkt_addint(pkt, dev->fd);
   pkt_addint(pkt, ep);
   pkt_addint(pkt, size);
   pkt_addint(pkt, timeout);
   pkt_send(pkt, fd);

   // Get response
   int res = -1;
   if(pkt_recv(fd, pkt) > 0 && pkt_op(pkt) == UsbInterruptRead) {
      Iterator it;
      pkt_begin(pkt, &it);
      res = iter_getint(&it);

      if(res > 0) {
         int minlen = (res > size) ? size : res;
         memcpy(bytes, it.val, minlen);
      }

   }

   // Return response
   pkt_release();
   debug_msg("returned %d", res);
   return res;
}
Пример #6
0
static BOOL modem_command (const char *cmd, const char *resp, int timeout)
{
  DWORD timer;
  int   len = cmd ? strlen (cmd) : strlen (resp);

  if (cmd)
     rc = pkt_send (cmd, len);  /**<\todo Bypass PKTDRVR ? */

  if (rc < len || !_eth_is_init)
     return (FALSE);

  timer = set_timeout (1000 * timeout);

  while (!chk_timeout(timer))
  {
    char *pkt = (char*) _eth_arrived (NULL NULL);

    if (!pkt)
       continue;

    outsn (pkt, len);                             /* print the modem echo */
    _eth_free (pkt, type);
    return (strncmp(pkt,resp,strlen(resp)) == 0); /* got modem response */
  }
  return (FALSE);
}
Пример #7
0
int usb_set_altinterface(usb_dev_handle *dev, int alternate)
{
   // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Prepare packet
   pkt_init(pkt, UsbSetAltInterface);
   pkt_addint(pkt, dev->fd);
   pkt_addint(pkt, alternate);
   pkt_send(pkt, fd);

   // Get response
   int res = -1;
   if(pkt_recv(fd, pkt) > 0 && pkt_op(pkt) == UsbSetAltInterface) {
      Iterator it;
      pkt_begin(pkt, &it);

      // Read result
      res = iter_getint(&it);

      // Read callback configuration
      alternate = iter_getint(&it);
   }

   // Save configuration
   dev->altsetting = alternate;

   // Return response
   pkt_release();
   debug_msg("returned %d", res);
   return res;
}
Пример #8
0
int usb_close(usb_dev_handle *dev)
{
   // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Send packet
   pkt_init(pkt, UsbClose);
   pkt_addint(pkt, dev->fd);
   pkt_send(pkt, fd);

   // Free device
   free(dev);

   // Get response
   int res = -1;
   if(pkt_recv(fd, pkt) > 0 && pkt_op(pkt) == UsbClose) {
      Iterator it;
      pkt_begin(pkt, &it);
      res = iter_getint(&it);
   }

   pkt_release();
   debug_msg("returned %d", res);
   return res;
}
Пример #9
0
static int tok_mac_xmit (const void *buf, WORD len)
{
  SIO_TRACE (("tok_mac_xmit, len %d", len));

  if (len > TOK_MAX)  /* Token-Ring has no min. length */
      len = TOK_MAX;
  return pkt_send (buf, len);
}
Пример #10
0
static int fddi_mac_xmit (const void *buf, WORD len)
{
  SIO_TRACE (("fddi_mac_xmit, len %d", len));

  if (len < FDDI_MIN)
       len = FDDI_MIN;
  else if (len > FDDI_MAX)
       len = FDDI_MAX;

  return pkt_send (buf, len);
}
Пример #11
0
static int arcnet_mac_xmit (const void *buf, WORD len)
{
  SIO_TRACE (("arcnet_mac_xmit, len %d", len));

  if (len < ARCNET_MIN)
       len = ARCNET_MIN;
  else if (len > ARCNET_MAX)
       len = ARCNET_MAX;

  return pkt_send (buf, len);
}
Пример #12
0
/**
 * Functions called via function pointer `mac_transmit' to
 * actually send the data.
 */
static int eth_mac_xmit (const void *buf, WORD len)
{
  SIO_TRACE (("eth_mac_xmit, len %d", len));

  if (len < ETH_MIN)
       len = ETH_MIN;  /* zero padding already done in eth_mac_format() */
  else if (len > ETH_MAX)
       len = ETH_MAX;

  return pkt_send (buf, len);
}
Пример #13
0
/** Initialize USB subsystem. */
void usb_init(void)
{
   // Initialize packet & remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Create buffer
   pkt_init(pkt, UsbInit);
   pkt_send(pkt, fd);
   pkt_release();

   // Initialize locally
   debug_msg("called");
}
Пример #14
0
int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
        int value, int index, char *bytes, int size, int timeout)
{
   // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Prepare packet
   pkt_init(pkt, UsbControlMsg);
   pkt_addint(pkt, dev->fd);
   pkt_addint(pkt, requesttype);
   pkt_addint(pkt, request);
   pkt_addint(pkt, value);
   pkt_addint(pkt, index);
   pkt_addstr(pkt, size, bytes);
   pkt_addint(pkt, timeout);
   pkt_send(pkt, fd);

   // Get response
   int res = -1;
   if(pkt_recv(fd, pkt) > 0 && pkt_op(pkt) == UsbControlMsg) {
      Iterator it;
      pkt_begin(pkt, &it);
      res = iter_getint(&it);

      if(res > 0) {
         int minlen = (res > size) ? size : res;
         memcpy(bytes, it.val, minlen);
      }

   }

   // Return response
   pkt_release();
   debug_msg("returned %d", res);
   return res;
}
Пример #15
0
int usb_detach_kernel_driver_np(usb_dev_handle *dev, int interface)
{
   // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Send packet
   pkt_init(pkt, UsbDetachKernelDriver);
   pkt_addint(pkt, dev->fd);
   pkt_addint(pkt, interface);
   pkt_send(pkt, fd);

   // Get response
   int res = -1;
   if(pkt_recv(fd, pkt) > 0 && pkt_op(pkt) == UsbDetachKernelDriver) {
      Iterator it;
      pkt_begin(pkt, &it);
      res = iter_getint(&it);
   }

   pkt_release();
   debug_msg("returned %d", res);
   return res;
}
Пример #16
0
/** Find busses on remote host.
    \warning Does not transfer busses to local virtual bus list.
  */
int usb_find_busses(void)
{
  // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Initialize pkt
   pkt_init(pkt, UsbFindBusses);
   pkt_send(pkt, fd);

   // Get number of changes
   int res = 0;
   Iterator it;
   if(pkt_recv(fd, pkt) > 0 && pkt_op(pkt) == UsbFindBusses) {
      if(pkt_begin(pkt, &it) != NULL) {
         res = iter_getint(&it);
      }
   }

   // Return remote result
   pkt_release();
   debug_msg("returned %d", res);
   return res;
}
Пример #17
0
/*---------------------------------------------------------------------------*/
void     icmp_pkt_rx (netif_t *netif, net_buf_t *net_buf)
{
    icmp_hdr_t *icmp_pkt_in, *icmp_pkt_out ;
    ipv4_hdr_t *ipv4_hdr_in, *ipv4_hdr_out ;
    eth_hdr_t  *eth_hdr_in ;
    pkt_t      *pkt ;

    eth_hdr_in  = (eth_hdr_t *)   ((usys) net_buf->data) ;
    ipv4_hdr_in = (ipv4_hdr_t *) (((usys) net_buf->data) + ETH_HDR_SIZE) ;
    icmp_pkt_in = (icmp_hdr_t *) (((usys) net_buf->data) + ETH_HDR_SIZE  + 
                                                           IPV4_HDR_SIZE) ;

    switch (icmp_pkt_in->type)
    {
        case MSG_TYPE_ECHO_REQUEST :

             /* Alloc the frame */
             if ((pkt = pkt_alloc (netif)) == NULL)
             {
                printf ("ERR: pkt_alloc() failed in handle_arp_pkt() !!\n") ;
                return ;
             }

	     /* Fill out the icmp header and data */
             icmp_pkt_out = (icmp_hdr_t *) (((usys) pkt)   +  
                                            ETH_HDR_SIZE   + 
                                            IPV4_HDR_SIZE) ;

	     icmp_pkt_out->type = MSG_TYPE_ECHO_REPLY ;
	     icmp_pkt_out->code = 0 ;
	     icmp_pkt_out->id   = icmp_pkt_in->id  ;
	     icmp_pkt_out->seq  = icmp_pkt_in->seq ;

	     memcpy (++icmp_pkt_out, ++icmp_pkt_in, 
                     ntohs(ipv4_hdr_in->len) - IPV4_HDR_SIZE - ICMP_HDR_SIZE) ;

	     icmp_pkt_out -- ;
	     icmp_pkt_out->csum = ~crc16_calc ((u8 *) icmp_pkt_out, 
                                              ntohs(ipv4_hdr_in->len) - 
                                              IPV4_HDR_SIZE) ;

	     /* Initialize the ip header */
             ipv4_hdr_out = (ipv4_hdr_t *) (((usys) pkt) + ETH_HDR_SIZE) ;

	     ipv4_hdr_init (netif, ipv4_hdr_out, 
                            ntohs(ipv4_hdr_in->len),
                            IPV4_PROTOCOL_ICMP, ntohl(ipv4_hdr_in->src)) ;


             /* Initialize the eth header */
             eth_hdr_init (netif, pkt, eth_hdr_in->src_mac, ETH_TYPE_IPV4) ;


	     pkt_send (netif, pkt, ntohs(ipv4_hdr_in->len) + 
                       ETH_HDR_SIZE) ;
	     pkt_free (netif, pkt) ;

	     break ;

        default :
             break ;
    }

} /* End of function icmp_pkt_rx () */
Пример #18
0
static int null_mac_xmit (const void *buf, WORD len)
{
  SIO_TRACE (("null_mac_xmit, len %d", len));

  return pkt_send (buf, len);
}
Пример #19
0
int nmrp_do(struct nmrpd_args *args)
{
	struct nmrp_pkt tx, rx;
	uint8_t *src, dest[6];
	uint16_t len, region;
	char *filename;
	time_t beg;
	int i, status, ulreqs, expect, upload_ok, autoip;
	struct ethsock *sock;
	uint32_t intf_addr;
	void (*sigh_orig)(int);
	struct {
		struct in_addr addr;
		struct in_addr mask;
	} PACKED ipconf;

	if (args->op != NMRP_UPLOAD_FW) {
		fprintf(stderr, "Operation not implemented.\n");
		return 1;
	}

	if (!mac_parse(args->mac, dest)) {
		fprintf(stderr, "Invalid MAC address '%s'.\n", args->mac);
		return 1;
	}

	if ((ipconf.mask.s_addr = inet_addr(args->ipmask)) == INADDR_NONE) {
		fprintf(stderr, "Invalid subnet mask '%s'.\n", args->ipmask);
		return 1;
	}

	if (!args->ipaddr) {
		autoip = true;
		/* The MAC of the device that was used to test this utility starts
		 * with a4:2b:8c, hence 164 (0xa4) and 183 (0x2b + 0x8c)
		 */
		args->ipaddr = "10.164.183.252";

		if (!args->ipaddr_intf) {
			args->ipaddr_intf = "10.164.183.253";
		}
	} else if (args->ipaddr_intf) {
		autoip = true;
	} else {
		autoip = false;
	}

	if ((ipconf.addr.s_addr = inet_addr(args->ipaddr)) == INADDR_NONE) {
		fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr);
		return 1;
	}

	if (args->ipaddr_intf && (intf_addr = inet_addr(args->ipaddr_intf)) == INADDR_NONE) {
		fprintf(stderr, "Invalid IP address '%s'.\n", args->ipaddr_intf);
		return 1;
	}

	if (args->file_local && strcmp(args->file_local, "-") && access(args->file_local, R_OK) == -1) {
		fprintf(stderr, "Error accessing file '%s'.\n", args->file_local);
		return 1;
	}

	if (args->file_remote) {
		if (!tftp_is_valid_filename(args->file_remote)) {
			fprintf(stderr, "Invalid remote filename '%s'.\n",
					args->file_remote);
			return 1;
		}
	}

	if (args->region) {
		region = htons(to_region_code(args->region));
		if (!region) {
			fprintf(stderr, "Invalid region code '%s'.\n", args->region);
			return 1;
		}
	} else {
		region = 0;
	}

	status = 1;

	sock = ethsock_create(args->intf, ETH_P_NMRP);
	if (!sock) {
		return 1;
	}

	gsock = sock;
	garp = 0;
	sigh_orig = signal(SIGINT, sigh);

	if (!autoip) {
		status = is_valid_ip(sock, &ipconf.addr, &ipconf.mask);
		if (status <= 0) {
			if (!status) {
				fprintf(stderr, "Address %s/%s cannot be used on interface %s.\n",
						args->ipaddr, args->ipmask, args->intf);
			}
			goto out;
		}
	} else {
		if (verbosity) {
			printf("Adding %s to interface %s.\n", args->ipaddr_intf, args->intf);
		}

		if (ethsock_ip_add(sock, intf_addr, ipconf.mask.s_addr, &gundo) != 0) {
			goto out;
		}
	}

	if (ethsock_set_timeout(sock, args->rx_timeout)) {
		goto out;
	}

	src = ethsock_get_hwaddr(sock);
	if (!src) {
		goto out;
	}

	memcpy(tx.eh.ether_shost, src, 6);
	memcpy(tx.eh.ether_dhost, dest, 6);
	tx.eh.ether_type = htons(ETH_P_NMRP);

	msg_init(&tx.msg, NMRP_C_ADVERTISE);
	msg_opt_add(&tx.msg, NMRP_O_MAGIC_NO, "NTGR", 4);
	msg_hton(&tx.msg);

	i = 0;
	upload_ok = 0;
	beg = time(NULL);

	while (1) {
		printf("\rAdvertising NMRP server on %s ... %c",
				args->intf, spinner[i]);
		fflush(stdout);
		i = (i + 1) & 3;

		if (pkt_send(sock, &tx) < 0) {
			perror("sendto");
			goto out;
		}

		status = pkt_recv(sock, &rx);
		if (status == 0 && memcmp(rx.eh.ether_dhost, src, 6) == 0) {
			break;
		} else if (status == 1) {
			goto out;
		} else {
			if ((time(NULL) - beg) >= 60) {
				printf("\nNo response after 60 seconds. Bailing out.\n");
				goto out;
			}
		}
	}

	printf("\n");

	expect = NMRP_C_CONF_REQ;
	ulreqs = 0;

	do {
		if (expect != NMRP_C_NONE && rx.msg.code != expect) {
			fprintf(stderr, "Received %s while waiting for %s!\n",
					msg_code_str(rx.msg.code), msg_code_str(expect));
		}

		msg_init(&tx.msg, NMRP_C_NONE);

		status = 1;

		switch (rx.msg.code) {
			case NMRP_C_ADVERTISE:
				printf("Received NMRP advertisement from %s.\n",
						mac_to_str(rx.eh.ether_shost));
				status = 1;
				goto out;
			case NMRP_C_CONF_REQ:
				tx.msg.code = NMRP_C_CONF_ACK;

				msg_opt_add(&tx.msg, NMRP_O_DEV_IP, &ipconf, 8);
				msg_opt_add(&tx.msg, NMRP_O_FW_UP, NULL, 0);

#ifdef NMRPFLASH_SET_REGION
				if (region) {
					msg_opt_add(&tx.msg, NMRP_O_DEV_REGION, &region, 2);
				}
#endif

				expect = NMRP_C_TFTP_UL_REQ;

				printf("Received configuration request from %s.\n",
						mac_to_str(rx.eh.ether_shost));

				memcpy(tx.eh.ether_dhost, rx.eh.ether_shost, 6);

				printf("Sending configuration: ip %s, mask %s.\n",
						args->ipaddr, args->ipmask);

				memcpy(arpmac, rx.eh.ether_shost, 6);
				memcpy(&arpip, &ipconf.addr, sizeof(ipconf.addr));

				if (ethsock_arp_add(sock, arpmac, &arpip) != 0) {
					goto out;
				}

				garp = 1;

				break;
			case NMRP_C_TFTP_UL_REQ:
				if (!upload_ok) {
					if (++ulreqs > 5) {
						printf("Bailing out after %d upload requests.\n",
								ulreqs);
						tx.msg.code = NMRP_C_CLOSE_REQ;
						break;
					}
				} else {
					if (verbosity) {
						printf("Ignoring extra upload request.\n");
					}
					ethsock_set_timeout(sock, args->ul_timeout);
					tx.msg.code = NMRP_C_KEEP_ALIVE_REQ;
					break;
				}

				len = 0;
				filename = msg_opt_data(&rx.msg, NMRP_O_FILE_NAME, &len);
				if (filename) {
					if (!args->file_remote) {
						args->file_remote = filename;
					}
					printf("Received upload request: filename '%.*s'.\n",
							len, filename);
				} else if (!args->file_remote) {
					args->file_remote = args->file_local;
					printf("Received upload request with empty filename.\n");
				}

				status = 0;

				if (args->tftpcmd) {
					printf("Executing '%s' ... \n", args->tftpcmd);
					setenv("IP", inet_ntoa(ipconf.addr), 1);
					setenv("MAC", mac_to_str(rx.eh.ether_shost), 1);
					setenv("NETMASK", inet_ntoa(ipconf.mask), 1);
					status = system(args->tftpcmd);
				}

				if (!status && args->file_local) {
					if (!autoip) {
						status = is_valid_ip(sock, &ipconf.addr, &ipconf.mask);
						if (status < 0) {
							goto out;
						} else if (!status) {
							printf("IP address of %s has changed. Please assign a "
									"static ip to the interface.\n", args->intf);
							tx.msg.code = NMRP_C_CLOSE_REQ;
							break;
						}
					}

					if (verbosity) {
						printf("Using remote filename '%s'.\n",
								args->file_remote);
					}

					if (!strcmp(args->file_local, "-")) {
						printf("Uploading from stdin ... ");
					} else {
						printf("Uploading %s ... ", leafname(args->file_local));
					}
					fflush(stdout);
					status = tftp_put(args);
				}

				if (!status) {
					printf("OK\nWaiting for remote to respond.\n");
					upload_ok = 1;
					ethsock_set_timeout(sock, args->ul_timeout);
					tx.msg.code = NMRP_C_KEEP_ALIVE_REQ;
					expect = NMRP_C_NONE;
				} else if (status == -2) {
					expect = NMRP_C_TFTP_UL_REQ;
				} else {
					goto out;
				}

				break;
			case NMRP_C_KEEP_ALIVE_REQ:
				tx.msg.code = NMRP_C_KEEP_ALIVE_ACK;
				ethsock_set_timeout(sock, args->ul_timeout);
				printf("Received keep-alive request.\n");
				break;
			case NMRP_C_CLOSE_REQ:
				tx.msg.code = NMRP_C_CLOSE_ACK;
				break;
			case NMRP_C_CLOSE_ACK:
				status = 0;
				goto out;
			default:
				fprintf(stderr, "Unknown message code 0x%02x!\n",
						rx.msg.code);
				msg_dump(&rx.msg, 0);
		}

		if (tx.msg.code != NMRP_C_NONE) {
			msg_hton(&tx.msg);

			if (pkt_send(sock, &tx) < 0) {
				perror("sendto");
				goto out;
			}

			if (tx.msg.code == NMRP_C_CLOSE_REQ) {
				goto out;
			}
		}

		if (rx.msg.code == NMRP_C_CLOSE_REQ) {
			printf("Remote finished. Closing connection.\n");
			break;
		}

		status = pkt_recv(sock, &rx);
		if (status) {
			if (status == 2) {
				fprintf(stderr, "Timeout while waiting for %s.\n",
						msg_code_str(expect));
			}
			goto out;
		}

		ethsock_set_timeout(sock, args->rx_timeout);

	} while (1);

	status = 0;

	if (ulreqs) {
		printf("Reboot your device now.\n");
	} else {
		printf("No upload request received.\n");
	}

out:
	signal(SIGINT, sigh_orig);
	gsock = NULL;
	ethsock_arp_del(sock, arpmac, &arpip);
	ethsock_ip_del(sock, &gundo);
	ethsock_close(sock);
	return status;
}
Пример #20
0
/** Find devices on remote host.
  * Create new devices on local virtual bus.
  * \warning Function replaces global usb_busses variable from libusb.
  */
int usb_find_devices(void)
{
   // Get remote fd
   Packet* pkt = pkt_claim();
   int fd = session_get();

   // Create buffer
   pkt_init(pkt, UsbFindDevices);
   pkt_send(pkt, fd);

   // Get number of changes
   int res = 0;
   Iterator it;
   if(pkt_recv(fd, pkt) > 0) {
      pkt_begin(pkt, &it);

      // Get return value
      res = iter_getint(&it);

      // Allocate virtualbus
      struct usb_bus vbus;
      vbus.next = __remote_bus;
      struct usb_bus* rbus = &vbus;

      // Get busses
      while(!iter_end(&it)) {

         // Evaluate
         if(it.type == StructureType) {
            iter_enter(&it);

            // Allocate bus
            if(rbus->next == NULL) {

               // Allocate next item
               struct usb_bus* nbus = malloc(sizeof(struct usb_bus));
               memset(nbus, 0, sizeof(struct usb_bus));
               rbus->next = nbus;
               nbus->prev = rbus;
               rbus = nbus;
            }
            else
               rbus = rbus->next;

            // Read dirname
            strcpy(rbus->dirname, iter_getstr(&it));

            // Read location
            rbus->location = iter_getuint(&it);

            // Read devices
            struct usb_device vdev;
            vdev.next = rbus->devices;
            struct usb_device* dev = &vdev;
            while(it.type == SequenceType) {
               iter_enter(&it);

               // Initialize
               if(dev->next == NULL) {
                  dev->next = malloc(sizeof(struct usb_device));
                  memset(dev->next, 0, sizeof(struct usb_device));
                  dev->next->bus = rbus;
                  if(dev != &vdev)
                     dev->next->prev = dev;
                  if(rbus->devices == NULL)
                     rbus->devices = dev->next;
               }

               dev = dev->next;

               // Read filename
               strcpy(dev->filename, iter_getstr(&it));

               // Read devnum
               dev->devnum = iter_getuint(&it);

               // Read descriptor
               // Apply byte-order conversion for 16/32bit integers
               memcpy(&dev->descriptor, it.val, it.len);
               dev->descriptor.bcdUSB = ntohs(dev->descriptor.bcdUSB);
               dev->descriptor.idVendor = ntohs(dev->descriptor.idVendor);
               dev->descriptor.idProduct = ntohs(dev->descriptor.idProduct);
               dev->descriptor.bcdDevice = ntohs(dev->descriptor.bcdDevice);
               iter_next(&it);

               // Alloc configurations
               unsigned cfgid = 0, cfgnum = dev->descriptor.bNumConfigurations;
               dev->config = NULL;
               if(cfgnum > 0) {
                  dev->config = malloc(cfgnum * sizeof(struct usb_config_descriptor));
                  memset(dev->config, 0, cfgnum * sizeof(struct usb_config_descriptor));
               }

               // Read config
               while(it.type == RawType && cfgid < cfgnum) {
                  struct usb_config_descriptor* cfg = &dev->config[cfgid];
                  ++cfgid;

                  // Ensure struct under/overlap
                  int szlen = sizeof(struct usb_config_descriptor);
                  if(szlen > it.len)
                     szlen = it.len;

                  // Read config and apply byte-order conversion
                  memcpy(cfg, it.val, szlen);
                  cfg->wTotalLength = ntohs(cfg->wTotalLength);

                  // Allocate interfaces
                  cfg->interface = NULL;
                  if(cfg->bNumInterfaces > 0) {
                     cfg->interface = malloc(cfg->bNumInterfaces * sizeof(struct usb_interface));
                  }

                  //! \test Implement usb_device extra interfaces - are they needed?
                  cfg->extralen = 0;
                  cfg->extra = NULL;
                  iter_next(&it);

                  // Load interfaces
                  unsigned i, j, k;
                  for(i = 0; i < cfg->bNumInterfaces; ++i) {
                     struct usb_interface* iface = &cfg->interface[i];

                     // Read altsettings count
                     iface->num_altsetting = iter_getint(&it);

                     // Allocate altsettings
                     if(iface->num_altsetting > 0) {
                        iface->altsetting = malloc(iface->num_altsetting * sizeof(struct usb_interface_descriptor));
                     }

                     // Load altsettings
                     for(j = 0; j < iface->num_altsetting; ++j) {

                        // Ensure struct under/overlap
                        struct usb_interface_descriptor* as = &iface->altsetting[j];
                        int szlen = sizeof(struct usb_interface_descriptor);
                        if(szlen > it.len)
                           szlen = it.len;

                        // Read altsettings - no conversions apply
                        memcpy(as, it.val, szlen);
                        iter_next(&it);

                        // Allocate endpoints
                        as->endpoint = NULL;
                        if(as->bNumEndpoints > 0) {
                           size_t epsize = as->bNumEndpoints * sizeof(struct usb_endpoint_descriptor);
                           as->endpoint = malloc(epsize);
                           memset(as->endpoint, 0, epsize);
                        }

                        // Load endpoints
                        for(k = 0; k < as->bNumEndpoints; ++k) {
                           struct usb_endpoint_descriptor* endpoint = &as->endpoint[k];
                           int szlen = sizeof(struct usb_endpoint_descriptor);
                           if(szlen > it.len)
                              szlen = it.len;

                           // Read endpoint and apply conversion
                           memcpy(endpoint, it.val, szlen);
                           endpoint->wMaxPacketSize = ntohs(endpoint->wMaxPacketSize);
                           iter_next(&it);

                           // Null extra descriptors.
                           endpoint->extralen = 0;
                           endpoint->extra = NULL;
                        }

                        // Read extra interface descriptors
                        as->extralen = as_int(it.val, it.len);
                        iter_next(&it);

                        if(as->extralen > 0){
                            as->extra = malloc(as->extralen);

                            int szlen = as->extralen;
                            if(szlen > it.len)
                                szlen = it.len;

                            memcpy(as->extra, it.val, szlen);
                            iter_next(&it);
                        }
                        else
                            as->extra = NULL;
                     }
                  }
               }

               //log_msg("Bus %s Device %s: ID %04x:%04x", rbus->dirname, dev->filename, dev->descriptor.idVendor, dev->descriptor.idProduct);
            }

            // Free unused devices
            while(dev->next != NULL) {
               struct usb_device* ddev = dev->next;
               debug_msg("deleting device %03d", ddev->devnum);
               dev->next = ddev->next;
               free(ddev);
            }

         }
         else {
            debug_msg("unexpected item identifier 0x%02x", it.type);
            iter_next(&it);
         }
      }

      // Deallocate unnecessary busses
      while(rbus->next != NULL) {
         debug_msg("deleting bus %03d", rbus->next->location);
         struct usb_bus* bus = rbus->next;
         rbus->next = bus->next;
      }

      // Save busses
      if(__remote_bus == NULL) {
         __orig_bus = usb_busses;
         debug_msg("overriding global usb_busses from %p to %p", usb_busses, vbus.next);
      }

      __remote_bus = vbus.next;
      usb_busses = __remote_bus;
   }

   // Return remote result
   pkt_release();
   debug_msg("returned %d", res);
   return res;
}