source: mainline/uspace/srv/net/inetsrv/inetping.c@ 76f566d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 76f566d was a46e56b, checked in by Jakub Jermar <jakub@…>, 7 years ago

Prefer handle over ID in naming handle variables

  • Property mode set to 100644
File size: 7.7 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 errno_t 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 errno_t 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
96errno_t 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 errno_t 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 errno_t retval;
133 async_wait_for(req, &retval);
134
135 return retval;
136}
137
138static void inetping_send_srv(inetping_client_t *client, cap_call_handle_t icall_handle,
139 ipc_call_t *icall)
140{
141 log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_send_srv()");
142
143 inetping_sdu_t sdu;
144 errno_t rc;
145
146 sdu.seq_no = IPC_GET_ARG1(*icall);
147
148 cap_call_handle_t chandle;
149 size_t size;
150 if (!async_data_write_receive(&chandle, &size)) {
151 async_answer_0(chandle, EREFUSED);
152 async_answer_0(icall_handle, EREFUSED);
153 return;
154 }
155
156 if (size != sizeof(sdu.src)) {
157 async_answer_0(chandle, EINVAL);
158 async_answer_0(icall_handle, EINVAL);
159 return;
160 }
161
162 rc = async_data_write_finalize(chandle, &sdu.src, size);
163 if (rc != EOK) {
164 async_answer_0(chandle, rc);
165 async_answer_0(icall_handle, rc);
166 return;
167 }
168
169 if (!async_data_write_receive(&chandle, &size)) {
170 async_answer_0(chandle, EREFUSED);
171 async_answer_0(icall_handle, EREFUSED);
172 return;
173 }
174
175 if (size != sizeof(sdu.dest)) {
176 async_answer_0(chandle, EINVAL);
177 async_answer_0(icall_handle, EINVAL);
178 return;
179 }
180
181 rc = async_data_write_finalize(chandle, &sdu.dest, size);
182 if (rc != EOK) {
183 async_answer_0(chandle, rc);
184 async_answer_0(icall_handle, 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(icall_handle, rc);
192 return;
193 }
194
195 rc = inetping_send(client, &sdu);
196 free(sdu.data);
197
198 async_answer_0(icall_handle, rc);
199}
200
201static void inetping_get_srcaddr_srv(inetping_client_t *client,
202 cap_call_handle_t icall_handle, ipc_call_t *icall)
203{
204 log_msg(LOG_DEFAULT, LVL_DEBUG, "inetping_get_srcaddr_srv()");
205
206 cap_call_handle_t chandle;
207 size_t size;
208
209 inet_addr_t local;
210 inet_addr_t remote;
211
212 if (!async_data_write_receive(&chandle, &size)) {
213 async_answer_0(chandle, EREFUSED);
214 async_answer_0(icall_handle, EREFUSED);
215 return;
216 }
217
218 if (size != sizeof(remote)) {
219 async_answer_0(chandle, EINVAL);
220 async_answer_0(icall_handle, EINVAL);
221 return;
222 }
223
224 errno_t rc = async_data_write_finalize(chandle, &remote, size);
225 if (rc != EOK) {
226 async_answer_0(chandle, rc);
227 async_answer_0(icall_handle, rc);
228 return;
229 }
230
231 rc = inetping_get_srcaddr(client, &remote, &local);
232 if (rc != EOK) {
233 async_answer_0(icall_handle, rc);
234 return;
235 }
236
237 if (!async_data_read_receive(&chandle, &size)) {
238 async_answer_0(chandle, EREFUSED);
239 async_answer_0(icall_handle, EREFUSED);
240 return;
241 }
242
243 if (size != sizeof(local)) {
244 async_answer_0(chandle, EINVAL);
245 async_answer_0(icall_handle, EINVAL);
246 return;
247 }
248
249 rc = async_data_read_finalize(chandle, &local, size);
250 if (rc != EOK)
251 async_answer_0(chandle, rc);
252
253 async_answer_0(icall_handle, rc);
254}
255
256static errno_t 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(cap_call_handle_t icall_handle, 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(icall_handle, EOK);
289
290 inetping_client_t client;
291 errno_t rc = inetping_client_init(&client);
292 if (rc != EOK)
293 return;
294
295 while (true) {
296 ipc_call_t call;
297 cap_call_handle_t chandle = 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(chandle, EOK);
303 break;
304 }
305
306 switch (method) {
307 case INETPING_SEND:
308 inetping_send_srv(&client, chandle, &call);
309 break;
310 case INETPING_GET_SRCADDR:
311 inetping_get_srcaddr_srv(&client, chandle, &call);
312 break;
313 default:
314 async_answer_0(chandle, EINVAL);
315 }
316 }
317
318 inetping_client_fini(&client);
319}
320
321/** @}
322 */
Note: See TracBrowser for help on using the repository browser.