source: mainline/uspace/srv/net/slip/slip.c@ 5a324d99

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5a324d99 was b11f6fb, checked in by Maurizio Lombardi <m.lombardi85@…>, 12 years ago

slip: return an error code in case of failure.

  • Property mode set to 100644
File size: 9.7 KB
Line 
1/*
2 * Copyright (c) 2013 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup slip
30 * @{
31 */
32/**
33 * @file
34 * @brief IP over serial line IP link provider.
35 */
36
37#include <stdio.h>
38#include <stdint.h>
39#include <loc.h>
40#include <net/socket_codes.h>
41#include <inet/addr.h>
42#include <inet/iplink_srv.h>
43#include <device/char_dev.h>
44#include <io/log.h>
45#include <errno.h>
46
47#define NAME "slip"
48#define CAT_IPLINK "iplink"
49
50#define SLIP_MTU 1006 /* as per RFC 1055 */
51
52#define SLIP_END 0300
53#define SLIP_ESC 0333
54#define SLIP_ESC_END 0334
55#define SLIP_ESC_ESC 0335
56
57static int slip_open(iplink_srv_t *);
58static int slip_close(iplink_srv_t *);
59static int slip_send(iplink_srv_t *, iplink_sdu_t *);
60static int slip_send6(iplink_srv_t *, iplink_sdu6_t *);
61static int slip_get_mtu(iplink_srv_t *, size_t *);
62static int slip_get_mac48(iplink_srv_t *, addr48_t *);
63static int slip_addr_add(iplink_srv_t *, inet_addr_t *);
64static int slip_addr_remove(iplink_srv_t *, inet_addr_t *);
65
66static iplink_srv_t slip_iplink;
67
68static iplink_ops_t slip_iplink_ops = {
69 .open = slip_open,
70 .close = slip_close,
71 .send = slip_send,
72 .send6 = slip_send6,
73 .get_mtu = slip_get_mtu,
74 .get_mac48 = slip_get_mac48,
75 .addr_add = slip_addr_add,
76 .addr_remove = slip_addr_remove
77};
78
79static uint8_t slip_send_buf[SLIP_MTU + 2];
80static size_t slip_send_pending;
81
82static uint8_t slip_recv_buf[SLIP_MTU + 2];
83static size_t slip_recv_pending;
84static size_t slip_recv_read;
85
86int slip_open(iplink_srv_t *srv)
87{
88 log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_open()");
89 return EOK;
90}
91
92int slip_close(iplink_srv_t *srv)
93{
94 log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_close()");
95 return EOK;
96}
97
98static void write_flush(async_sess_t *sess)
99{
100 size_t written = 0;
101
102 while (slip_send_pending > 0) {
103 ssize_t size;
104
105 size = char_dev_write(sess, &slip_send_buf[written],
106 slip_send_pending);
107 if (size < 0) {
108 log_msg(LOG_DEFAULT, LVL_ERROR,
109 "char_dev_write() returned %d",
110 (int) size);
111 slip_send_pending = 0;
112 break;
113 }
114 written += size;
115 slip_send_pending -= size;
116 }
117}
118
119static void write_buffered(async_sess_t *sess, uint8_t ch)
120{
121 if (slip_send_pending == sizeof(slip_send_buf))
122 write_flush(sess);
123 slip_send_buf[slip_send_pending++] = ch;
124}
125
126int slip_send(iplink_srv_t *srv, iplink_sdu_t *sdu)
127{
128 log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_send()");
129
130 async_sess_t *sess = (async_sess_t *) srv->arg;
131 uint8_t *data = sdu->data;
132
133 /*
134 * Strictly speaking, this is not prescribed by the RFC, but the RFC
135 * suggests to start with sending a SLIP_END byte as a synchronization
136 * measure for dealing with previous possible noise on the line.
137 */
138 write_buffered(sess, SLIP_END);
139
140 for (size_t i = 0; i < sdu->size; i++) {
141 switch (data[i]) {
142 case SLIP_END:
143 write_buffered(sess, SLIP_ESC);
144 write_buffered(sess, SLIP_ESC_END);
145 break;
146 case SLIP_ESC:
147 write_buffered(sess, SLIP_ESC);
148 write_buffered(sess, SLIP_ESC_ESC);
149 break;
150 default:
151 write_buffered(sess, data[i]);
152 break;
153 }
154 }
155
156 write_buffered(sess, SLIP_END);
157 write_flush(sess);
158
159 return EOK;
160}
161
162int slip_send6(iplink_srv_t *srv, iplink_sdu6_t *sdu)
163{
164 log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_send6()");
165
166 return ENOTSUP;
167}
168
169int slip_get_mtu(iplink_srv_t *srv, size_t *mtu)
170{
171 log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_get_mtu()");
172 *mtu = SLIP_MTU;
173 return EOK;
174}
175
176int slip_get_mac48(iplink_srv_t *src, addr48_t *mac)
177{
178 log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_get_mac48()");
179 return ENOTSUP;
180}
181
182int slip_addr_add(iplink_srv_t *srv, inet_addr_t *addr)
183{
184 log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_addr_add()");
185 return EOK;
186}
187
188int slip_addr_remove(iplink_srv_t *srv, inet_addr_t *addr)
189{
190 log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_addr_remove()");
191 return EOK;
192}
193
194static void usage(void)
195{
196 printf("Usage: " NAME " <service-name> <link-name>\n");
197}
198
199static void slip_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
200{
201 log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_client_conn()");
202 iplink_conn(iid, icall, &slip_iplink);
203}
204
205static uint8_t read_buffered(async_sess_t *sess)
206{
207 while (slip_recv_pending == 0) {
208 ssize_t size;
209
210 size = char_dev_read(sess, slip_recv_buf,
211 sizeof(slip_recv_buf));
212 if (size < 0) {
213 log_msg(LOG_DEFAULT, LVL_ERROR,
214 "char_dev_read() returned %d", (int) size);
215 return SLIP_END;
216 }
217 slip_recv_pending = size;
218 slip_recv_read = 0;
219 }
220 slip_recv_pending--;
221 return slip_recv_buf[slip_recv_read++];
222}
223
224static int slip_recv_fibril(void *arg)
225{
226 async_sess_t *sess = (async_sess_t *) arg;
227 static uint8_t recv_final[SLIP_MTU];
228 iplink_recv_sdu_t sdu;
229 uint8_t ch;
230 int rc;
231
232 sdu.data = recv_final;
233
234 while (true) {
235 for (sdu.size = 0; sdu.size < sizeof(recv_final); /**/) {
236 ch = read_buffered(sess);
237 switch (ch) {
238 case SLIP_END:
239 if (sdu.size == 0) {
240 /*
241 * Discard the empty SLIP datagram.
242 */
243 break;
244 }
245 goto pass;
246
247 case SLIP_ESC:
248 ch = read_buffered(sess);
249 if (ch == SLIP_ESC_END) {
250 recv_final[sdu.size++] = SLIP_END;
251 break;
252 } else if (ch == SLIP_ESC_ESC) {
253 recv_final[sdu.size++] = SLIP_ESC;
254 break;
255 }
256
257 /*
258 * The RFC suggests to simply insert the wrongly
259 * escaped character into the packet so we fall
260 * through.
261 */
262
263 default:
264 recv_final[sdu.size++] = ch;
265 break;
266 }
267
268 }
269
270 /*
271 * We have reached the limit of our MTU. Regardless of whether
272 * the datagram is properly ended with SLIP_END, pass it along.
273 * If the next character is really SLIP_END, nothing
274 * catastrophic happens. The algorithm will just see an
275 * artificially empty SLIP datagram and life will go on.
276 */
277
278pass:
279 rc = iplink_ev_recv(&slip_iplink, &sdu, AF_INET);
280 if (rc != EOK) {
281 log_msg(LOG_DEFAULT, LVL_ERROR,
282 "iplink_ev_recv() returned %d", rc);
283 }
284 }
285
286 return 0;
287}
288
289static int slip_init(const char *svcstr, const char *linkstr)
290{
291 service_id_t svcid;
292 service_id_t linksid;
293 category_id_t iplinkcid;
294 async_sess_t *sess_in = NULL;
295 async_sess_t *sess_out = NULL;
296 fid_t fid;
297 int rc;
298
299 iplink_srv_init(&slip_iplink);
300 slip_iplink.ops = &slip_iplink_ops;
301
302 async_set_client_connection(slip_client_conn);
303
304 rc = loc_server_register(NAME);
305 if (rc != EOK) {
306 log_msg(LOG_DEFAULT, LVL_ERROR,
307 "Failed registering server.");
308 return rc;
309 }
310
311 rc = loc_service_get_id(svcstr, &svcid, 0);
312 if (rc != EOK) {
313 log_msg(LOG_DEFAULT, LVL_ERROR,
314 "Failed getting ID for service %s", svcstr);
315 return rc;
316 }
317
318 rc = loc_category_get_id(CAT_IPLINK, &iplinkcid, 0);
319 if (rc != EOK) {
320 log_msg(LOG_DEFAULT, LVL_ERROR,
321 "Failed to get category ID for %s",
322 CAT_IPLINK);
323 return rc;
324 }
325
326 /*
327 * Create two sessions to allow to both read and write from the
328 * char_dev at the same time.
329 */
330 sess_out = loc_service_connect(EXCHANGE_SERIALIZE, svcid, 0);
331 if (!sess_out) {
332 log_msg(LOG_DEFAULT, LVL_ERROR,
333 "Failed to connect to service %s (ID=%d)",
334 svcstr, (int) svcid);
335 return ENOENT;
336 }
337 slip_iplink.arg = sess_out;
338
339 sess_in = loc_service_connect(EXCHANGE_SERIALIZE, svcid, 0);
340 if (!sess_in) {
341 log_msg(LOG_DEFAULT, LVL_ERROR,
342 "Failed to connect to service %s (ID=%d)",
343 svcstr, (int) svcid);
344 rc = ENOENT;
345 goto fail;
346 }
347
348 rc = loc_service_register(linkstr, &linksid);
349 if (rc != EOK) {
350 log_msg(LOG_DEFAULT, LVL_ERROR,
351 "Failed to register service %s",
352 linkstr);
353 goto fail;
354 }
355
356 rc = loc_service_add_to_cat(linksid, iplinkcid);
357 if (rc != EOK) {
358 log_msg(LOG_DEFAULT, LVL_ERROR,
359 "Failed to add service %d (%s) to category %d (%s).",
360 (int) linksid, linkstr, (int) iplinkcid, CAT_IPLINK);
361 goto fail;
362 }
363
364 fid = fibril_create(slip_recv_fibril, sess_in);
365 if (!fid) {
366 log_msg(LOG_DEFAULT, LVL_ERROR,
367 "Failed to create receive fibril.");
368 rc = ENOENT;
369 goto fail;
370 }
371 fibril_add_ready(fid);
372
373 return EOK;
374
375fail:
376 if (sess_out)
377 async_hangup(sess_out);
378 if (sess_in)
379 async_hangup(sess_in);
380
381 /*
382 * We assume that our registration at the location service will be
383 * cleaned up automatically as the service (i.e. this task) terminates.
384 */
385
386 return rc;
387}
388
389int main(int argc, char *argv[])
390{
391 int rc;
392
393 printf(NAME ": IP over serial line service\n");
394
395 if (argc != 3) {
396 usage();
397 return EINVAL;
398 }
399
400 rc = log_init(NAME);
401 if (rc != EOK) {
402 printf(NAME ": failed to initialize log\n");
403 return rc;
404 }
405
406 rc = slip_init(argv[1], argv[2]);
407 if (rc != EOK)
408 return 1;
409
410 printf(NAME ": Accepting connections.\n");
411 task_retval(0);
412 async_manager();
413
414 /* not reached */
415 return 0;
416}
417
418/** @}
419 */
Note: See TracBrowser for help on using the repository browser.