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
;
32 uint32_t local_address
; /* host interface address */
35 static int userv_beforepoll(void *sst
, struct pollfd
*fds
, int *nfds_io
,
36 int *timeout_io
, const struct timeval
*tv_now
,
42 fds
[0].events
=POLLERR
; /* Might want to pick up POLLOUT sometime */
44 fds
[1].events
=POLLIN
|POLLERR
|POLLHUP
;
48 static void userv_afterpoll(void *sst
, struct pollfd
*fds
, int nfds
,
49 const struct timeval
*tv_now
, uint64_t *now
)
52 uint8_t rxbuf
[DEFAULT_BUFSIZE
];
55 if (fds
[1].revents
&POLLERR
) {
56 Message(M_ERROR
,"%s: userv_afterpoll: hup!\n",st
->nl
.name
);
58 if (fds
[1].revents
&POLLIN
) {
59 l
=read(st
->rxfd
,rxbuf
,DEFAULT_BUFSIZE
);
61 fatal_perror("%s: userv_afterpoll: read(rxfd)",st
->nl
.name
);
64 fatal("%s: userv_afterpoll: read(rxfd)=0; userv gone away?\n",
67 /* XXX really crude unstuff code */
68 /* XXX check for buffer overflow */
69 BUF_ASSERT_USED(st
->buff
);
71 if (st
->pending_esc
) {
72 st
->pending_esc
=False
;
75 *(uint8_t *)buf_append(st
->buff
,1)=SLIP_END
;
78 *(uint8_t *)buf_append(st
->buff
,1)=SLIP_ESC
;
81 fatal("userv_afterpoll: bad SLIP escape character\n");
86 if (st
->buff
->size
>0) {
87 st
->netlink_to_tunnel(&st
->nl
,NULL
,
89 BUF_ALLOC(st
->buff
,"userv_afterpoll");
91 buffer_init(st
->buff
,st
->nl
.max_start_pad
);
97 *(uint8_t *)buf_append(st
->buff
,1)=rxbuf
[i
];
105 /* Send buf to the kernel. Free buf before returning. */
106 static void userv_deliver_to_kernel(void *sst
, void *cid
,
107 struct buffer_if
*buf
)
109 struct userv
*st
=sst
;
110 uint8_t txbuf
[DEFAULT_BUFSIZE
];
114 BUF_ASSERT_USED(buf
);
116 /* Spit the packet at userv-ipif: SLIP start marker, then
117 bytestuff the packet, then SLIP end marker */
118 /* XXX crunchy bytestuff code */
121 for (i
=buf
->start
; i
<(buf
->start
+buf
->size
); i
++) {
125 txbuf
[j
++]=SLIP_ESCEND
;
129 txbuf
[j
++]=SLIP_ESCESC
;
137 if (write(st
->txfd
,txbuf
,j
)<0) {
138 fatal_perror("userv_deliver_to_kernel: write()");
143 static void userv_phase_hook(void *sst
, uint32_t newphase
)
145 struct userv
*st
=sst
;
152 struct netlink_route
*r
;
155 /* This is where we actually invoke userv - all the networks we'll
156 be using should already have been registered. */
158 addrs
=safe_malloc(512,"userv_phase_hook:addrs");
159 snprintf(addrs
,512,"%s,%s,%d,slip",ipaddr_to_string(st
->local_address
),
160 ipaddr_to_string(st
->nl
.secnet_address
),st
->nl
.mtu
);
162 nets
=safe_malloc(1024,"userv_phase_hook:nets");
165 for (i
=0; i
<st
->nl
.n_routes
; i
++) {
168 s
=subnet_to_string(&r
[i
].net
);
174 nets
[strlen(nets
)-1]=0;
176 Message(M_INFO
,"%s: about to invoke: %s %s %s %s %s\n",st
->nl
.name
,
177 st
->userv_path
,st
->service_user
,st
->service_name
,addrs
,nets
);
179 /* Allocate buffer, plus space for padding. Make sure we end up
180 with the start of the packet well-aligned. */
181 /* ALIGN(st->max_start_pad,16); */
182 /* ALIGN(st->max_end_pad,16); */
184 st
->pending_esc
=False
;
187 if (pipe(c_stdin
)!=0) {
188 fatal_perror("userv_phase_hook: pipe(c_stdin)");
190 if (pipe(c_stdout
)!=0) {
191 fatal_perror("userv_phase_hook: pipe(c_stdout)");
194 st
->rxfd
=c_stdout
[0];
198 fatal_perror("userv_phase_hook: fork()");
203 /* We are the child. Modify our stdin and stdout, then exec userv */
209 /* The arguments are:
213 local-addr,secnet-addr,mtu,protocol
215 argv
=malloc(sizeof(*argv
)*6);
216 argv
[0]=st
->userv_path
;
217 argv
[1]=st
->service_user
;
218 argv
[2]=st
->service_name
;
222 execvp(st
->userv_path
,argv
);
223 perror("netlink-userv-ipif: execvp");
227 /* We are the parent... */
229 /* Register for poll() */
230 register_for_poll(st
, userv_beforepoll
, userv_afterpoll
, 2, st
->nl
.name
);
233 static list_t
*userv_apply(closure_t
*self
, struct cloc loc
, dict_t
*context
,
240 st
=safe_malloc(sizeof(*st
),"userv_apply");
242 /* First parameter must be a dict */
243 item
=list_elem(args
,0);
244 if (!item
|| item
->type
!=t_dict
)
245 cfgfatal(loc
,"userv-ipif","parameter must be a dictionary\n");
247 dict
=item
->data
.dict
;
249 st
->netlink_to_tunnel
=
250 netlink_init(&st
->nl
,st
,loc
,dict
,
251 "netlink-userv-ipif",NULL
,userv_deliver_to_kernel
);
253 st
->userv_path
=dict_read_string(dict
,"userv-path",False
,"userv-netlink",
255 st
->service_user
=dict_read_string(dict
,"service-user",False
,
256 "userv-netlink",loc
);
257 st
->service_name
=dict_read_string(dict
,"service-name",False
,
258 "userv-netlink",loc
);
259 if (!st
->userv_path
) st
->userv_path
="userv";
260 if (!st
->service_user
) st
->service_user
="root";
261 if (!st
->service_name
) st
->service_name
="ipif";
262 st
->buff
=find_cl_if(dict
,"buffer",CL_BUFFER
,True
,"userv-netlink",loc
);
263 st
->local_address
=string_to_ipaddr(
264 dict_find_item(dict
,"local-address", True
, "netlink", loc
),"netlink");
265 BUF_ALLOC(st
->buff
,"netlink:userv_apply");
267 st
->rxfd
=-1; st
->txfd
=-1;
268 add_hook(PHASE_DROPPRIV
,userv_phase_hook
,st
);
270 return new_closure(&st
->nl
.cl
);
273 init_module slip_module
;
274 void slip_module(dict_t
*dict
)
276 add_closure(dict
,"userv-ipif",userv_apply
);
279 add_closure(dict
,"pty-slip",ptyslip_apply
);
280 add_closure(dict
,"slipd",slipd_apply
);