source: mainline/uspace/srv/net/inetsrv/inetping.c@ 7ce8f88

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7ce8f88 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: 7.4 KB
Line 
1/*
2 * Copyright (c) 2013 Jiri Svoboda
3 * Copyright (c) 2013 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup inet
31 * @{
32 */
33/**
34 * @file
35 * @brief
36 */
37
38#include <async.h>
39#include <errno.h>
40#include <fibril_synch.h>
41#include <io/log.h>
42#include <ipc/inet.h>
43#include <loc.h>
44#include <stdlib.h>
45#include <stddef.h>
46#include <stdint.h>
47#include <types/inetping.h>
48#include "icmp.h"
49#include "icmpv6.h"
50#include "icmp_std.h"
51#include "inetsrv.h"
52#include "inetping.h"
53
54static FIBRIL_MUTEX_INITIALIZE(client_list_lock);
55static LIST_INITIALIZE(client_list);
56
57/** Last used session identifier. Protected by @c client_list_lock */
58static uint16_t inetping_ident = 0;
59
60static int inetping_send(inetping_client_t *client, inetping_sdu_t *sdu)
61{
62 if (sdu->src.version != sdu->dest.version)
63 return EINVAL;
64
65 switch (sdu->src.version) {
66 case ip_v4:
67 return icmp_ping_send(client->ident, sdu);
68 case ip_v6:
69 return icmpv6_ping_send(client->ident, sdu);
70 default:
71 return EINVAL;
72 }
73}
74
75static int inetping_get_srcaddr(inetping_client_t *client,
76 inet_addr_t *remote, inet_addr_t *local)
77{
78 return inet_get_srcaddr(remote, ICMP_TOS, local);
79}
80
81static inetping_client_t *inetping_client_find(uint16_t ident)
82{
83 fibril_mutex_lock(&client_list_lock);
84
85 list_foreach(client_list, client_list, inetping_client_t, client) {
86 if (client->ident == ident) {
87 fibril_mutex_unlock(&client_list_lock);
88 return client;
89 }
90 }
91
92 fibril_mutex_unlock(&client_list_lock);
93 return NULL;
94}
95
96int inetping_recv(uint16_t ident, inetping_sdu_t *sdu)
97{
98 inetping_client_t *client = inetping_client_find(ident);
99 if (client == NULL) {
100 log_msg(LOG_DEFAULT, LVL_DEBUG, "Unknown ICMP ident. Dropping.");
101 return ENOENT;
102 }
103
104 async_exch_t *exch = async_exchange_begin(client->sess);
105
106 ipc_call_t answer;
107 aid_t req = async_send_1(exch, INETPING_EV_RECV, sdu->seq_no, &answer);
108
109 int rc = async_data_write_start(exch, &sdu->src, sizeof(sdu->src));
110 if (rc != EOK) {
111 async_exchange_end(exch);
112 async_forget(req);
113 return rc;
114 }
115
116 rc = async_data_write_start(exch, &sdu->dest, sizeof(sdu->dest));
117 if (rc != EOK) {
118 async_exchange_end(exch);
119 async_forget(req);
120 return rc;
121 }
122
123 rc = async_data_write_start(exch, sdu->data, sdu->size);
124
125 async_exchange_end(exch);
126
127 if (rc != EOK) {
128 async_forget(req);
129 return rc;
130 }
131
132 int retval;
133 async_wait_for(req, &retval);
134
135 return retval;
136}
137
138static void inetping_send_srv(inetping_client_t *client, ipc_callid_t iid,
139 ipc_call_t *icall)
140{
141 log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_send_srv()");
142
143 inetping_sdu_t sdu;
144 int rc;
145
146 sdu.seq_no = IPC_GET_ARG1(*icall);
147
148 ipc_callid_t callid;
149 size_t size;
150 if (!async_data_write_receive(&callid, &size)) {
151 async_answer_0(callid, EREFUSED);
152 async_answer_0(iid, EREFUSED);
153 return;
154 }
155
156 if (size != sizeof(sdu.src)) {
157 async_answer_0(callid, EINVAL);
158 async_answer_0(iid, EINVAL);
159 return;
160 }
161
162 rc = async_data_write_finalize(callid, &sdu.src, size);
163 if (rc != EOK) {
164 async_answer_0(callid, rc);
165 async_answer_0(iid, rc);
166 return;
167 }
168
169 if (!async_data_write_receive(&callid, &size)) {
170 async_answer_0(callid, EREFUSED);
171 async_answer_0(iid, EREFUSED);
172 return;
173 }
174
175 if (size != sizeof(sdu.dest)) {
176 async_answer_0(callid, EINVAL);
177 async_answer_0(iid, EINVAL);
178 return;
179 }
180
181 rc = async_data_write_finalize(callid, &sdu.dest, size);
182 if (rc != EOK) {
183 async_answer_0(callid, rc);
184 async_answer_0(iid, rc);
185 return;
186 }
187
188 rc = async_data_write_accept((void **) &sdu.data, false, 0, 0, 0,
189 &sdu.size);
190 if (rc != EOK) {
191 async_answer_0(iid, rc);
192 return;
193 }
194
195 rc = inetping_send(client, &sdu);
196 free(sdu.data);
197
198 async_answer_0(iid, rc);
199}
200
201static void inetping_get_srcaddr_srv(inetping_client_t *client,
202 ipc_callid_t iid, ipc_call_t *icall)
203{
204 log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_get_srcaddr_srv()");
205
206 ipc_callid_t callid;
207 size_t size;
208
209 inet_addr_t local;
210 inet_addr_t remote;
211
212 if (!async_data_write_receive(&callid, &size)) {
213 async_answer_0(callid, EREFUSED);
214 async_answer_0(iid, EREFUSED);
215 return;
216 }
217
218 if (size != sizeof(remote)) {
219 async_answer_0(callid, EINVAL);
220 async_answer_0(iid, EINVAL);
221 return;
222 }
223
224 int rc = async_data_write_finalize(callid, &remote, size);
225 if (rc != EOK) {
226 async_answer_0(callid, rc);
227 async_answer_0(iid, rc);
228 return;
229 }
230
231 rc = inetping_get_srcaddr(client, &remote, &local);
232 if (rc != EOK) {
233 async_answer_0(iid, rc);
234 return;
235 }
236
237 if (!async_data_read_receive(&callid, &size)) {
238 async_answer_0(callid, EREFUSED);
239 async_answer_0(iid, EREFUSED);
240 return;
241 }
242
243 if (size != sizeof(local)) {
244 async_answer_0(callid, EINVAL);
245 async_answer_0(iid, EINVAL);
246 return;
247 }
248
249 rc = async_data_read_finalize(callid, &local, size);
250 if (rc != EOK)
251 async_answer_0(callid, rc);
252
253 async_answer_0(iid, rc);
254}
255
256static int inetping_client_init(inetping_client_t *client)
257{
258 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
259 if (sess == NULL)
260 return ENOMEM;
261
262 client->sess = sess;
263 link_initialize(&client->client_list);
264
265 fibril_mutex_lock(&client_list_lock);
266 client->ident = ++inetping_ident;
267 list_append(&client->client_list, &client_list);
268 fibril_mutex_unlock(&client_list_lock);
269
270 return EOK;
271}
272
273static void inetping_client_fini(inetping_client_t *client)
274{
275 async_hangup(client->sess);
276 client->sess = NULL;
277
278 fibril_mutex_lock(&client_list_lock);
279 list_remove(&client->client_list);
280 fibril_mutex_unlock(&client_list_lock);
281}
282
283void inetping_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
284{
285 log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_conn()");
286
287 /* Accept the connection */
288 async_answer_0(iid, EOK);
289
290 inetping_client_t client;
291 int rc = inetping_client_init(&client);
292 if (rc != EOK)
293 return;
294
295 while (true) {
296 ipc_call_t call;
297 ipc_callid_t callid = async_get_call(&call);
298 sysarg_t method = IPC_GET_IMETHOD(call);
299
300 if (!method) {
301 /* The other side has hung up */
302 async_answer_0(callid, EOK);
303 break;
304 }
305
306 switch (method) {
307 case INETPING_SEND:
308 inetping_send_srv(&client, callid, &call);
309 break;
310 case INETPING_GET_SRCADDR:
311 inetping_get_srcaddr_srv(&client, callid, &call);
312 break;
313 default:
314 async_answer_0(callid, EINVAL);
315 }
316 }
317
318 inetping_client_fini(&client);
319}
320
321/** @}
322 */
Note: See TracBrowser for help on using the repository browser.