1 /* When dealing with SLIP (to a pty, or ipif) we have separate rx, tx
2 and client buffers. When receiving we may read() any amount, not
3 just whole packets. When transmitting we need to bytestuff anyway,
4 and may be part-way through receiving. */
15 #define SLIP_ESCEND 220
16 #define SLIP_ESCESC 221
18 /* Connection to the kernel through userv-ipif */
22 int txfd
; /* We transmit to userv */
23 int rxfd
; /* We receive from userv */
25 string_t service_user
;
26 string_t service_name
;
28 struct buffer_if
*buff
; /* We unstuff received packets into here
29 and send them to the site code. */
31 netlink_deliver_fn
*netlink_to_tunnel
;
34 static int userv_beforepoll(void *sst
, struct pollfd
*fds
, int *nfds_io
,
35 int *timeout_io
, const struct timeval
*tv_now
,
41 fds
[0].events
=POLLERR
; /* Might want to pick up POLLOUT sometime */
43 fds
[1].events
=POLLIN
|POLLERR
|POLLHUP
;
47 static void userv_afterpoll(void *sst
, struct pollfd
*fds
, int nfds
,
48 const struct timeval
*tv_now
, uint64_t *now
)
51 uint8_t rxbuf
[DEFAULT_BUFSIZE
];
54 if (fds
[1].revents
&POLLERR
) {
55 Message(M_ERROR
,"%s: userv_afterpoll: hup!\n",st
->nl
.name
);
57 if (fds
[1].revents
&POLLIN
) {
58 l
=read(st
->rxfd
,rxbuf
,DEFAULT_BUFSIZE
);
60 fatal_perror("%s: userv_afterpoll: read(rxfd)",st
->nl
.name
);
63 fatal("%s: userv_afterpoll: read(rxfd)=0; userv gone away?\n",
66 /* XXX really crude unstuff code */
67 /* XXX check for buffer overflow */
68 BUF_ASSERT_USED(st
->buff
);
70 if (st
->pending_esc
) {
71 st
->pending_esc
=False
;
74 *(uint8_t *)buf_append(st
->buff
,1)=SLIP_END
;
77 *(uint8_t *)buf_append(st
->buff
,1)=SLIP_ESC
;
80 fatal("userv_afterpoll: bad SLIP escape character\n");
85 if (st
->buff
->size
>0) {
86 st
->netlink_to_tunnel(&st
->nl
,NULL
,
88 BUF_ALLOC(st
->buff
,"userv_afterpoll");
90 buffer_init(st
->buff
,st
->nl
.max_start_pad
);
96 *(uint8_t *)buf_append(st
->buff
,1)=rxbuf
[i
];
104 /* Send buf to the kernel. Free buf before returning. */
105 static void userv_deliver_to_kernel(void *sst
, void *cid
,
106 struct buffer_if
*buf
)
108 struct userv
*st
=sst
;
109 uint8_t txbuf
[DEFAULT_BUFSIZE
];
113 BUF_ASSERT_USED(buf
);
115 /* Spit the packet at userv-ipif: SLIP start marker, then
116 bytestuff the packet, then SLIP end marker */
117 /* XXX crunchy bytestuff code */
120 for (i
=buf
->start
; i
<(buf
->start
+buf
->size
); i
++) {
124 txbuf
[j
++]=SLIP_ESCEND
;
128 txbuf
[j
++]=SLIP_ESCESC
;
136 if (write(st
->txfd
,txbuf
,j
)<0) {
137 fatal_perror("userv_deliver_to_kernel: write()");
142 static void userv_phase_hook(void *sst
, uint32_t newphase
)
144 struct userv
*st
=sst
;
151 struct netlink_route
*r
;
154 /* This is where we actually invoke userv - all the networks we'll
155 be using should already have been registered. */
157 addrs
=safe_malloc(512,"userv_phase_hook:addrs");
158 snprintf(addrs
,512,"%s,%s,%d,slip",ipaddr_to_string(st
->nl
.local_address
),
159 ipaddr_to_string(st
->nl
.secnet_address
),st
->nl
.mtu
);
161 nets
=safe_malloc(1024,"userv_phase_hook:nets");
164 for (i
=0; i
<st
->nl
.n_routes
; i
++) {
167 s
=subnet_to_string(&r
[i
].net
);
173 nets
[strlen(nets
)-1]=0;
175 Message(M_INFO
,"%s: about to invoke: %s %s %s %s %s\n",st
->nl
.name
,
176 st
->userv_path
,st
->service_user
,st
->service_name
,addrs
,nets
);
178 /* Allocate buffer, plus space for padding. Make sure we end up
179 with the start of the packet well-aligned. */
180 /* ALIGN(st->max_start_pad,16); */
181 /* ALIGN(st->max_end_pad,16); */
183 st
->pending_esc
=False
;
186 if (pipe(c_stdin
)!=0) {
187 fatal_perror("userv_phase_hook: pipe(c_stdin)");
189 if (pipe(c_stdout
)!=0) {
190 fatal_perror("userv_phase_hook: pipe(c_stdout)");
193 st
->rxfd
=c_stdout
[0];
197 fatal_perror("userv_phase_hook: fork()");
202 /* We are the child. Modify our stdin and stdout, then exec userv */
208 /* The arguments are:
212 local-addr,secnet-addr,mtu,protocol
214 argv
=malloc(sizeof(*argv
)*6);
215 argv
[0]=st
->userv_path
;
216 argv
[1]=st
->service_user
;
217 argv
[2]=st
->service_name
;
221 execvp(st
->userv_path
,argv
);
222 perror("netlink-userv-ipif: execvp");
226 /* We are the parent... */
228 /* Register for poll() */
229 register_for_poll(st
, userv_beforepoll
, userv_afterpoll
, 2, st
->nl
.name
);
232 static list_t
*userv_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
239 st
=safe_malloc(sizeof(*st
),"userv_apply");
241 /* First parameter must be a dict */
242 item
=list_elem(args
,0);
243 if (!item
|| item
->type
!=t_dict
)
244 cfgfatal(loc
,"userv-ipif","parameter must be a dictionary\n");
246 dict
=item
->data
.dict
;
248 st
->netlink_to_tunnel
=
249 netlink_init(&st
->nl
,st
,loc
,dict
,
250 "netlink-userv-ipif",NULL
,userv_deliver_to_kernel
);
252 st
->userv_path
=dict_read_string(dict
,"userv-path",False
,"userv-netlink",
254 st
->service_user
=dict_read_string(dict
,"service-user",False
,
255 "userv-netlink",loc
);
256 st
->service_name
=dict_read_string(dict
,"service-name",False
,
257 "userv-netlink",loc
);
258 if (!st
->userv_path
) st
->userv_path
="userv";
259 if (!st
->service_user
) st
->service_user
="root";
260 if (!st
->service_name
) st
->service_name
="ipif";
261 st
->buff
=find_cl_if(dict
,"buffer",CL_BUFFER
,True
,"userv-netlink",loc
);
262 BUF_ALLOC(st
->buff
,"netlink:userv_apply");
264 st
->rxfd
=-1; st
->txfd
=-1;
265 add_hook(PHASE_DROPPRIV
,userv_phase_hook
,st
);
267 return new_closure(&st
->nl
.cl
);
270 init_module slip_module
;
271 void slip_module(dict_t
*dict
)
273 add_closure(dict
,"userv-ipif",userv_apply
);
276 add_closure(dict
,"pty-slip",ptyslip_apply
);
277 add_closure(dict
,"slipd",slipd_apply
);