source: mainline/uspace/lib/c/generic/iplink_srv.c@ 8610c2c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8610c2c was 25a179e, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

IPC return values are always errno constants. Adjust types to reflect that.

In principle, IPC server is not allowed to return non-errno values via
the "main" return value, because kernel interprets it (e.g. EHANGUP).
It's still possible to return arbitrary additional return values alongside EOK,
which are not interpreted in normal communication.

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 * Copyright (c) 2012 Jiri Svoboda
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 libc
30 * @{
31 */
32/**
33 * @file
34 * @brief IP link server stub
35 */
36
37#include <errno.h>
38#include <ipc/iplink.h>
39#include <stdlib.h>
40#include <stddef.h>
41#include <inet/addr.h>
42#include <inet/iplink_srv.h>
43
44static void iplink_get_mtu_srv(iplink_srv_t *srv, ipc_callid_t callid,
45 ipc_call_t *call)
46{
47 size_t mtu;
48 int rc = srv->ops->get_mtu(srv, &mtu);
49 async_answer_1(callid, rc, mtu);
50}
51
52static void iplink_get_mac48_srv(iplink_srv_t *srv, ipc_callid_t iid,
53 ipc_call_t *icall)
54{
55 addr48_t mac;
56 int rc = srv->ops->get_mac48(srv, &mac);
57 if (rc != EOK) {
58 async_answer_0(iid, rc);
59 return;
60 }
61
62 ipc_callid_t callid;
63 size_t size;
64 if (!async_data_read_receive(&callid, &size)) {
65 async_answer_0(callid, EREFUSED);
66 async_answer_0(iid, EREFUSED);
67 return;
68 }
69
70 if (size != sizeof(addr48_t)) {
71 async_answer_0(callid, EINVAL);
72 async_answer_0(iid, EINVAL);
73 return;
74 }
75
76 rc = async_data_read_finalize(callid, &mac, size);
77 if (rc != EOK)
78 async_answer_0(callid, rc);
79
80 async_answer_0(iid, rc);
81}
82
83static void iplink_set_mac48_srv(iplink_srv_t *srv, ipc_callid_t iid,
84 ipc_call_t *icall)
85{
86 int rc;
87 size_t size;
88 addr48_t mac;
89 ipc_callid_t callid;
90
91 if (!async_data_write_receive(&callid, &size)) {
92 async_answer_0(callid, EREFUSED);
93 async_answer_0(iid, EREFUSED);
94 }
95
96 rc = srv->ops->set_mac48(srv, &mac);
97 if (rc != EOK) {
98 async_answer_0(iid, rc);
99 return;
100 }
101
102 rc = async_data_read_finalize(callid, &mac, sizeof(addr48_t));
103 if (rc != EOK)
104 async_answer_0(callid, rc);
105
106 async_answer_0(iid, rc);
107}
108
109static void iplink_addr_add_srv(iplink_srv_t *srv, ipc_callid_t iid,
110 ipc_call_t *icall)
111{
112 ipc_callid_t callid;
113 size_t size;
114 if (!async_data_write_receive(&callid, &size)) {
115 async_answer_0(callid, EREFUSED);
116 async_answer_0(iid, EREFUSED);
117 return;
118 }
119
120 if (size != sizeof(inet_addr_t)) {
121 async_answer_0(callid, EINVAL);
122 async_answer_0(iid, EINVAL);
123 return;
124 }
125
126 inet_addr_t addr;
127 int rc = async_data_write_finalize(callid, &addr, size);
128 if (rc != EOK) {
129 async_answer_0(callid, rc);
130 async_answer_0(iid, rc);
131 }
132
133 rc = srv->ops->addr_add(srv, &addr);
134 async_answer_0(iid, rc);
135}
136
137static void iplink_addr_remove_srv(iplink_srv_t *srv, ipc_callid_t iid,
138 ipc_call_t *icall)
139{
140 ipc_callid_t callid;
141 size_t size;
142 if (!async_data_write_receive(&callid, &size)) {
143 async_answer_0(callid, EREFUSED);
144 async_answer_0(iid, EREFUSED);
145 return;
146 }
147
148 if (size != sizeof(inet_addr_t)) {
149 async_answer_0(callid, EINVAL);
150 async_answer_0(iid, EINVAL);
151 return;
152 }
153
154 inet_addr_t addr;
155 int rc = async_data_write_finalize(callid, &addr, size);
156 if (rc != EOK) {
157 async_answer_0(callid, rc);
158 async_answer_0(iid, rc);
159 }
160
161 rc = srv->ops->addr_remove(srv, &addr);
162 async_answer_0(iid, rc);
163}
164
165static void iplink_send_srv(iplink_srv_t *srv, ipc_callid_t iid,
166 ipc_call_t *icall)
167{
168 iplink_sdu_t sdu;
169
170 sdu.src = IPC_GET_ARG1(*icall);
171 sdu.dest = IPC_GET_ARG2(*icall);
172
173 int rc = async_data_write_accept(&sdu.data, false, 0, 0, 0,
174 &sdu.size);
175 if (rc != EOK) {
176 async_answer_0(iid, rc);
177 return;
178 }
179
180 rc = srv->ops->send(srv, &sdu);
181 free(sdu.data);
182 async_answer_0(iid, rc);
183}
184
185static void iplink_send6_srv(iplink_srv_t *srv, ipc_callid_t iid,
186 ipc_call_t *icall)
187{
188 iplink_sdu6_t sdu;
189
190 ipc_callid_t callid;
191 size_t size;
192 if (!async_data_write_receive(&callid, &size)) {
193 async_answer_0(callid, EREFUSED);
194 async_answer_0(iid, EREFUSED);
195 return;
196 }
197
198 if (size != sizeof(addr48_t)) {
199 async_answer_0(callid, EINVAL);
200 async_answer_0(iid, EINVAL);
201 return;
202 }
203
204 int rc = async_data_write_finalize(callid, &sdu.dest, size);
205 if (rc != EOK) {
206 async_answer_0(callid, rc);
207 async_answer_0(iid, rc);
208 }
209
210 rc = async_data_write_accept(&sdu.data, false, 0, 0, 0,
211 &sdu.size);
212 if (rc != EOK) {
213 async_answer_0(iid, rc);
214 return;
215 }
216
217 rc = srv->ops->send6(srv, &sdu);
218 free(sdu.data);
219 async_answer_0(iid, rc);
220}
221
222void iplink_srv_init(iplink_srv_t *srv)
223{
224 fibril_mutex_initialize(&srv->lock);
225 srv->connected = false;
226 srv->ops = NULL;
227 srv->arg = NULL;
228 srv->client_sess = NULL;
229}
230
231int iplink_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
232{
233 iplink_srv_t *srv = (iplink_srv_t *) arg;
234 int rc;
235
236 fibril_mutex_lock(&srv->lock);
237 if (srv->connected) {
238 fibril_mutex_unlock(&srv->lock);
239 async_answer_0(iid, EBUSY);
240 return EBUSY;
241 }
242
243 srv->connected = true;
244 fibril_mutex_unlock(&srv->lock);
245
246 /* Accept the connection */
247 async_answer_0(iid, EOK);
248
249 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
250 if (sess == NULL)
251 return ENOMEM;
252
253 srv->client_sess = sess;
254
255 rc = srv->ops->open(srv);
256 if (rc != EOK)
257 return rc;
258
259 while (true) {
260 ipc_call_t call;
261 ipc_callid_t callid = async_get_call(&call);
262 sysarg_t method = IPC_GET_IMETHOD(call);
263
264 if (!method) {
265 /* The other side has hung up */
266 fibril_mutex_lock(&srv->lock);
267 srv->connected = false;
268 fibril_mutex_unlock(&srv->lock);
269 async_answer_0(callid, EOK);
270 break;
271 }
272
273 switch (method) {
274 case IPLINK_GET_MTU:
275 iplink_get_mtu_srv(srv, callid, &call);
276 break;
277 case IPLINK_GET_MAC48:
278 iplink_get_mac48_srv(srv, callid, &call);
279 break;
280 case IPLINK_SET_MAC48:
281 iplink_set_mac48_srv(srv, callid, &call);
282 break;
283 case IPLINK_SEND:
284 iplink_send_srv(srv, callid, &call);
285 break;
286 case IPLINK_SEND6:
287 iplink_send6_srv(srv, callid, &call);
288 break;
289 case IPLINK_ADDR_ADD:
290 iplink_addr_add_srv(srv, callid, &call);
291 break;
292 case IPLINK_ADDR_REMOVE:
293 iplink_addr_remove_srv(srv, callid, &call);
294 break;
295 default:
296 async_answer_0(callid, EINVAL);
297 }
298 }
299
300 return srv->ops->close(srv);
301}
302
303/* XXX Version should be part of @a sdu */
304int iplink_ev_recv(iplink_srv_t *srv, iplink_recv_sdu_t *sdu, ip_ver_t ver)
305{
306 if (srv->client_sess == NULL)
307 return EIO;
308
309 async_exch_t *exch = async_exchange_begin(srv->client_sess);
310
311 ipc_call_t answer;
312 aid_t req = async_send_1(exch, IPLINK_EV_RECV, (sysarg_t)ver,
313 &answer);
314
315 int rc = async_data_write_start(exch, sdu->data, sdu->size);
316 async_exchange_end(exch);
317
318 if (rc != EOK) {
319 async_forget(req);
320 return rc;
321 }
322
323 int retval;
324 async_wait_for(req, &retval);
325 if (retval != EOK)
326 return retval;
327
328 return EOK;
329}
330
331int iplink_ev_change_addr(iplink_srv_t *srv, addr48_t *addr)
332{
333 if (srv->client_sess == NULL)
334 return EIO;
335
336 async_exch_t *exch = async_exchange_begin(srv->client_sess);
337
338 ipc_call_t answer;
339 aid_t req = async_send_0(exch, IPLINK_EV_CHANGE_ADDR, &answer);
340
341 int rc = async_data_write_start(exch, addr, sizeof(addr48_t));
342 async_exchange_end(exch);
343
344 if (rc != EOK) {
345 async_forget(req);
346 return rc;
347 }
348
349 int retval;
350 async_wait_for(req, &retval);
351 if (retval != EOK)
352 return retval;
353
354 return EOK;
355}
356
357/** @}
358 */
Note: See TracBrowser for help on using the repository browser.