+
+ netlink_packet_forward(st,buf);
+
+ BUF_ASSERT_FREE(buf);
+}
+
+/* Called by driver code when packet is received from kernel */
+/* cid should be NULL */
+/* buf should be allocated on entry, and is free on return */
+static void netlink_from_host(void *sst, void *cid, struct buffer_if *buf)
+{
+ struct netlink *st=sst;
+ uint32_t source,dest;
+ struct iphdr *iph;
+
+ BUF_ASSERT_USED(buf);
+ if (!netlink_check(st,buf)) {
+ Message(M_WARNING,"%s: bad IP packet from host\n",
+ st->name);
+ BUF_FREE(buf);
+ return;
+ }
+ iph=(struct iphdr *)buf->start;
+
+ source=ntohl(iph->saddr);
+ dest=ntohl(iph->daddr);
+
+ if (!subnet_match(&st->networks,source)) {
+ string_t s,d;
+ s=ipaddr_to_string(source);
+ d=ipaddr_to_string(dest);
+ Message(M_WARNING,"%s: outgoing packet with bad source address "
+ "(s=%s,d=%s)\n",st->name,s,d);
+ free(s); free(d);
+ BUF_FREE(buf);
+ return;
+ }
+ if (dest==st->secnet_address) {
+ netlink_packet_local(st,buf);
+ BUF_ASSERT_FREE(buf);
+ return;
+ }
+ netlink_packet_forward(st,buf);
+ BUF_ASSERT_FREE(buf);
+}
+
+static void netlink_set_delivery(void *sst, void *cid, bool_t can_deliver)
+{
+ struct netlink_client *c=cid;
+
+ c->can_deliver=can_deliver;
+}
+
+static void *netlink_regnets(void *sst, struct subnet_list *nets,
+ netlink_deliver_fn *deliver, void *dst,
+ uint32_t max_start_pad, uint32_t max_end_pad,
+ string_t client_name)
+{
+ struct netlink *st=sst;
+ struct netlink_client *c;
+
+ Message(M_DEBUG_CONFIG,"netlink_regnets: request for %d networks, "
+ "max_start_pad=%d, max_end_pad=%d\n",
+ nets->entries,max_start_pad,max_end_pad);
+
+ c=safe_malloc(sizeof(*c),"netlink_regnets");
+ c->networks=nets;
+ c->deliver=deliver;
+ c->dst=dst;
+ c->name=client_name; /* XXX copy it? */
+ c->can_deliver=False;
+ c->next=st->clients;
+ st->clients=c;
+ if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
+ if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
+
+ return c;
+}
+
+static netlink_deliver_fn *netlink_init(struct netlink *st,
+ void *dst, struct cloc loc,
+ dict_t *dict, string_t description,
+ netlink_deliver_fn *to_host)
+{
+ st->dst=dst;
+ st->cl.description=description;
+ st->cl.type=CL_NETLINK;
+ st->cl.apply=NULL;
+ st->cl.interface=&st->ops;
+ st->ops.st=st;
+ st->ops.regnets=netlink_regnets;
+ st->ops.deliver=netlink_from_tunnel;
+ st->ops.set_delivery=netlink_set_delivery;
+ st->max_start_pad=0;
+ st->max_end_pad=0;
+ st->clients=NULL;
+ st->deliver_to_host=to_host;
+
+ st->name=dict_read_string(dict,"name",False,"netlink",loc);
+ if (!st->name) st->name=description;
+ dict_read_subnet_list(dict, "networks", True, "netlink", loc,
+ &st->networks);
+ st->local_address=string_to_ipaddr(
+ dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
+ st->secnet_address=string_to_ipaddr(
+ dict_find_item(dict,"secnet-address", True, "netlink", loc),"netlink");
+ if (!subnet_match(&st->networks,st->local_address)) {
+ cfgfatal(loc,"netlink","local-address must be in local networks\n");
+ }
+ st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
+ buffer_new(&st->icmp,ICMP_BUFSIZE);
+
+ return netlink_from_host;
+}
+
+/* Connection to the kernel through userv-ipif */
+
+struct userv {
+ struct netlink nl;
+ int txfd; /* We transmit to userv */
+ int rxfd; /* We receive from userv */
+ string_t userv_path;
+ string_t service_user;
+ string_t service_name;
+ uint32_t txbuflen;
+ struct buffer_if *buff; /* We unstuff received packets into here
+ and send them to the site code. */
+ bool_t pending_esc;
+ netlink_deliver_fn *netlink_to_tunnel;
+};
+
+static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
+ int *timeout_io, const struct timeval *tv_now,
+ uint64_t *now)
+{
+ struct userv *st=sst;
+ *nfds_io=2;
+ fds[0].fd=st->txfd;
+ fds[0].events=POLLERR; /* Might want to pick up POLLOUT sometime */
+ fds[1].fd=st->rxfd;
+ fds[1].events=POLLIN|POLLERR|POLLHUP;
+ return 0;