+static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l)
+{
+ uint32_t i;
+
+ BUF_ASSERT_USED(st->buff);
+ for (i=0; i<l; i++) {
+ int outputchr;
+ enum { OUTPUT_END = 256, OUTPUT_NOTHING = 257 };
+
+ if (st->pending_esc) {
+ st->pending_esc=False;
+ switch(buf[i]) {
+ case SLIP_ESCEND:
+ outputchr=SLIP_END;
+ break;
+ case SLIP_ESCESC:
+ outputchr=SLIP_ESC;
+ break;
+ default:
+ if (!st->ignoring_packet) {
+ Message(M_WARNING, "userv_afterpoll: bad SLIP escape"
+ " character, dropping packet\n");
+ }
+ st->ignoring_packet=True;
+ outputchr=OUTPUT_NOTHING;
+ break;
+ }
+ } else {
+ switch (buf[i]) {
+ case SLIP_END:
+ outputchr=OUTPUT_END;
+ break;
+ case SLIP_ESC:
+ st->pending_esc=True;
+ outputchr=OUTPUT_NOTHING;
+ break;
+ default:
+ outputchr=buf[i];
+ break;
+ }
+ }
+
+ if (st->ignoring_packet) {
+ if (outputchr == OUTPUT_END) {
+ st->ignoring_packet=False;
+ buffer_init(st->buff,st->nl.max_start_pad);
+ }
+ } else {
+ if (outputchr == OUTPUT_END) {
+ if (st->buff->size>0) {
+ st->netlink_to_tunnel(&st->nl,st->buff);
+ BUF_ALLOC(st->buff,"userv_afterpoll");
+ }
+ buffer_init(st->buff,st->nl.max_start_pad);
+ } else if (outputchr != OUTPUT_NOTHING) {
+ if (st->buff->size < st->buff->len) {
+ buf_append_uint8(st->buff,outputchr);
+ } else {
+ Message(M_WARNING, "userv_afterpoll: dropping overlong"
+ " SLIP packet\n");
+ st->ignoring_packet=True;
+ }
+ }
+ }
+ }
+}
+
+static void slip_init(struct slip *st, struct cloc loc, dict_t *dict,
+ cstring_t name, netlink_deliver_fn *to_host)
+{
+ st->netlink_to_tunnel=
+ netlink_init(&st->nl,st,loc,dict,
+ "netlink-userv-ipif",NULL,to_host);
+ st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"name",loc);
+ st->local_address=string_item_to_ipaddr(
+ dict_find_item(dict,"local-address", True, name, loc),"netlink");
+ BUF_ALLOC(st->buff,"slip_init");
+ st->pending_esc=False;
+ st->ignoring_packet=False;
+}
+
+/* Connection to the kernel through userv-ipif */
+
+struct userv {
+ struct slip slip;
+ int txfd; /* We transmit to userv */
+ int rxfd; /* We receive from userv */
+ cstring_t userv_path;
+ cstring_t service_user;
+ cstring_t service_name;
+ pid_t pid;
+ bool_t expecting_userv_exit;
+};
+
+static int userv_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
+ int *timeout_io)
+{
+ struct userv *st=sst;
+
+ if (st->rxfd!=-1) {
+ *nfds_io=2;
+ fds[0].fd=st->txfd;
+ fds[0].events=0; /* Might want to pick up POLLOUT sometime */
+ fds[1].fd=st->rxfd;
+ fds[1].events=POLLIN;
+ } else {
+ *nfds_io=0;
+ }
+ return 0;
+}
+
+static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds)