Example #1
0
static int genetlink_call(__u16 family_id, __u8 cmd, void *header,
                          size_t header_len, void *request, size_t request_len,
                          void *reply, size_t reply_len)
{
	struct msg {
		struct nlmsghdr n;
		struct genlmsghdr g;
		char payload[0];
	};

	struct msg *request_msg;
	struct msg *reply_msg;
	int request_msg_size;
	int reply_msg_size;

	struct sockaddr_nl local;
	struct pollfd pfd;
	int sndbuf = 32*1024; /* 32k */
	int rcvbuf = 32*1024; /* 32k */
	int len;
	int sk;

	/*
	 * Prepare request/reply messages
	 */
	request_msg_size = NLMSG_LENGTH(GENL_HDRLEN + header_len + request_len);
	request_msg = malloc(request_msg_size);
	request_msg->n.nlmsg_len = request_msg_size;
	request_msg->n.nlmsg_type = family_id;
	request_msg->n.nlmsg_flags = NLM_F_REQUEST;
	request_msg->n.nlmsg_seq = 0;
	request_msg->n.nlmsg_pid = getpid();
	request_msg->g.cmd = cmd;
	request_msg->g.version = 0;
	if (header_len)
		memcpy(&request_msg->payload[0], header, header_len);
	if (request_len)
		memcpy(&request_msg->payload[header_len], request, request_len);

	reply_msg_size = NLMSG_LENGTH(GENL_HDRLEN + header_len + reply_len);
	reply_msg = malloc(reply_msg_size);

	/*
	 * Create socket
	 */
	memset(&local, 0, sizeof(local));
	local.nl_family = AF_NETLINK;

	if ((sk = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_GENERIC)) == -1)
		fatal("error creating Netlink socket\n");

	if ((bind(sk, (struct sockaddr*)&local, sizeof(local)) == -1) ||
	                (setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) == -1) ||
	                (setsockopt(sk, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) == -1)) {
		fatal("error creating Netlink socket\n");
	}

	/*
	 * Send request
	 */
	if (write_uninterrupted(sk, (char*)request_msg, request_msg_size) < 0)
		fatal("error sending message via Netlink\n");

	/*
	 * Wait for reply
	 */
	pfd.fd = sk;
	pfd.events = ~POLLOUT;
	if ((poll(&pfd, 1, 3000) != 1) || !(pfd.revents & POLLIN))
		fatal("no reply detected from Netlink\n");

	/*
	 * Read reply
	 */
	len = recv(sk, (char*)reply_msg, reply_msg_size, 0);
	if (len < 0)
		fatal("error receiving reply message via Netlink\n");

	close(sk);

	/*
	 * Validate response
	 */
	if (!NLMSG_OK(&reply_msg->n, len))
		fatal("invalid reply message received via Netlink\n");

	if (reply_msg->n.nlmsg_type == NLMSG_ERROR) {
		len = -1;
		goto out;
	}

	if ((request_msg->n.nlmsg_type != reply_msg->n.nlmsg_type) ||
	                (request_msg->n.nlmsg_seq != reply_msg->n.nlmsg_seq))
		fatal("unexpected message received via Netlink\n");

	/*
	 * Copy reply header
	 */
	len -= NLMSG_LENGTH(GENL_HDRLEN);
	if (len < header_len)
		fatal("too small reply message received via Netlink\n");
	if (header_len > 0)
		memcpy(header, &reply_msg->payload[0], header_len);

	/*
	 * Copy reply payload
	 */
	len -= header_len;
	if (len > reply_len)
		fatal("reply message too large to copy\n");
	if (len > 0)
		memcpy(reply, &reply_msg->payload[header_len], len);

out:
	free(request_msg);
	free(reply_msg);

	return len;
}
Example #2
0
// entry point
int
main (int argc, char **argv)
{

  int rc = 0;
  uint64_t seqnum = 0;
  int opt_index = 0;
  int c = 0;
  int fd = 0;
  char *tmp = NULL;
  char event_buf[8192];
  char event_buf_tmp[8292];	// has to hold event_buf plus an 8-byte sequence number
  char event_path[PATH_MAX + 1];

  bool have_seqnum = false;
  ssize_t nr = 0;
  char const *required_fields[] = {
    "\nSUBSYSTEM=",
    "\nDEVPATH=",
    NULL
  };

  char target_queues[PATH_MAX + 1];

  // default event queue
  memset (g_dev_events, 0, PATH_MAX + 1);
  memset (target_queues, 0, PATH_MAX + 1);
  memset (event_path, 0, PATH_MAX + 1);

  strcpy (g_dev_events, DEFAULT_DEV_EVENTS);

  static struct option opts[] = {
    {"source-queue", required_argument, 0, 's'},
    {"seqnum", required_argument, 0, 'n'},
    {"help", no_argument, 0, 'h'},
    {0, 0, 0, 0}
  };

  char const *optstr = "n:s:h";

  while (rc == 0 && c != -1)
    {

      c = getopt_long (argc, argv, optstr, opts, &opt_index);
      if (c == -1)
	{

	  break;
	}

      switch (c)
	{

	case 's':
	  {

	    memset (g_dev_events, 0, PATH_MAX);
	    strncpy (g_dev_events, optarg, PATH_MAX);
	    break;
	  }

	case 'n':
	  {

	    seqnum = (uint64_t) strtoull (optarg, &tmp, 10);
	    if (seqnum == 0 && (tmp == optarg || *tmp != '\0'))
	      {

		usage (argv[0]);
		exit (1);
	      }

	    have_seqnum = true;
	    break;
	  }

	case 'h':
	  {

	    help (argv[0]);
	    exit (0);
	  }

	default:
	  {

	    fprintf (stderr,
		     "[ERROR] %s: Unrecognized option '%c'\n", argv[0], c);
	    usage (argv[0]);
	    exit (1);
	  }
	}
    }

  // get the event 
  memset (event_buf, 0, 8192);
  nr = read_uninterrupted (STDIN_FILENO, event_buf, 8192);

  if (nr <= 0)
    {

      rc = -errno;
      fprintf (stderr,
	       "[ERROR] %s: Failed to read event from stdin: %s\n",
	       argv[0], strerror (-rc));
      exit (1);
    }
  // simple sanity check for requirements 
  for (int i = 0; required_fields[i] != NULL; i++)
    {

      if (strstr (event_buf, required_fields[i]) == NULL)
	{

	  // head of line? with no leading '\n'?
	  if (strncmp
	      (event_buf, required_fields[i] + 1,
	       strlen (required_fields[i]) - 1) != 0)
	    {

	      fprintf (stderr,
		       "[ERROR] %s: Missing required field '%s'\n",
		       argv[0], required_fields[i] + 1);
	      fprintf (stderr,
		       "[ERROR] %s: Pass -h for a list of required fields\n",
		       argv[0]);
	      exit (1);
	    }
	}
    }

  // do we have a seqnum?
  if (!have_seqnum)
    {

      char *seqnum_str = strstr (event_buf, "SEQNUM=");

      // go find it in the device event
      if (seqnum_str == NULL)
	{

	  fprintf (stderr,
		   "[ERROR] %s: Missing SEQNUM.  Pass -n or include SEQNUM= in the input.\n",
		   argv[0]);
	  exit (1);
	}
      // is it a valid seqnum?
      seqnum =
	(uint64_t) strtoull (seqnum_str + strlen ("SEQNUM="), &tmp, 10);
      if (seqnum == 0
	  && (tmp == seqnum_str + strlen ("SEQNUM=") || *tmp != '\n'))
	{

	  // invalid seqnum 
	  fprintf (stderr,
		   "[ERROR] %s: Invalid SEQNUM.  Pass -n or include a valid SEQNUM in the input.\n",
		   argv[0]);
	  exit (1);
	}
    }
  // send it off!
  make_event_path (seqnum, event_path);

  fd = open_event (event_path);
  if (fd < 0)
    {

      fprintf (stderr, "[ERROR] %s: Failed to open '%s': %s\n",
	       argv[0], event_path, strerror (-fd));
      exit (1);
    }

  rc = write_uninterrupted (fd, event_buf, nr);
  if (rc < 0)
    {

      fprintf (stderr, "[ERROR] %s: Failed to write '%s': %s\n",
	       argv[0], event_path, strerror (-fd));

      clear_event (event_buf);
      close (fd);
      exit (1);
    }
  // propagate....
  rc = multicast_event (seqnum, event_path);
  if (rc < 0)
    {

      fprintf (stderr, "[ERROR] %s: Failed to multicast '%s': %s\n",
	       argv[0], event_path, strerror (-rc));

      clear_event (event_buf);
      close (fd);
      exit (1);
    }
  // done!
  clear_event (event_path);
  close (fd);

  return 0;
}