~martin-decky/helenos/rcu

« back to all changes in this revision

Viewing changes to uspace/srv/net/inet/inetping.c

MergeĀ mainlineĀ changes

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 inet
 
30
 * @{
 
31
 */
 
32
/**
 
33
 * @file
 
34
 * @brief
 
35
 */
 
36
 
 
37
#include <async.h>
 
38
#include <errno.h>
 
39
#include <fibril_synch.h>
 
40
#include <io/log.h>
 
41
#include <ipc/inet.h>
 
42
#include <loc.h>
 
43
#include <stdlib.h>
 
44
#include <sys/types.h>
 
45
 
 
46
#include "icmp.h"
 
47
#include "icmp_std.h"
 
48
#include "inet.h"
 
49
#include "inetping.h"
 
50
 
 
51
static FIBRIL_MUTEX_INITIALIZE(client_list_lock);
 
52
static LIST_INITIALIZE(client_list);
 
53
 
 
54
/** Last used session identifier. Protected by @c client_list_lock */
 
55
static uint16_t inetping_ident = 0;
 
56
 
 
57
static inetping_client_t *inetping_client_find(uint16_t);
 
58
 
 
59
static int inetping_send(inetping_client_t *client, inetping_sdu_t *sdu)
 
60
{
 
61
        return icmp_ping_send(client->ident, sdu);
 
62
}
 
63
 
 
64
static int inetping_get_srcaddr(inetping_client_t *client, inet_addr_t *remote,
 
65
    inet_addr_t *local)
 
66
{
 
67
        return inet_get_srcaddr(remote, ICMP_TOS, local);
 
68
}
 
69
 
 
70
int inetping_recv(uint16_t ident, inetping_sdu_t *sdu)
 
71
{
 
72
        inetping_client_t *client;
 
73
        async_exch_t *exch;
 
74
        ipc_call_t answer;
 
75
 
 
76
        client = inetping_client_find(ident);
 
77
        if (client == NULL) {
 
78
                log_msg(LVL_DEBUG, "Unknown ICMP ident. Dropping.");
 
79
                return ENOENT;
 
80
        }
 
81
 
 
82
        exch = async_exchange_begin(client->sess);
 
83
 
 
84
        aid_t req = async_send_3(exch, INETPING_EV_RECV, sdu->src.ipv4,
 
85
            sdu->dest.ipv4, sdu->seq_no, &answer);
 
86
        int rc = async_data_write_start(exch, sdu->data, sdu->size);
 
87
        async_exchange_end(exch);
 
88
 
 
89
        if (rc != EOK) {
 
90
                async_forget(req);
 
91
                return rc;
 
92
        }
 
93
 
 
94
        sysarg_t retval;
 
95
        async_wait_for(req, &retval);
 
96
        if (retval != EOK) {
 
97
                return retval;
 
98
        }
 
99
 
 
100
        return EOK;
 
101
}
 
102
 
 
103
static void inetping_send_srv(inetping_client_t *client, ipc_callid_t callid,
 
104
    ipc_call_t *call)
 
105
{
 
106
        inetping_sdu_t sdu;
 
107
        int rc;
 
108
 
 
109
        log_msg(LVL_DEBUG, "inetping_send_srv()");
 
110
 
 
111
        rc = async_data_write_accept((void **) &sdu.data, false, 0, 0, 0,
 
112
            &sdu.size);
 
113
        if (rc != EOK) {
 
114
                async_answer_0(callid, rc);
 
115
                return;
 
116
        }
 
117
 
 
118
        sdu.src.ipv4 = IPC_GET_ARG1(*call);
 
119
        sdu.dest.ipv4 = IPC_GET_ARG2(*call);
 
120
        sdu.seq_no = IPC_GET_ARG3(*call);
 
121
 
 
122
        rc = inetping_send(client, &sdu);
 
123
        free(sdu.data);
 
124
 
 
125
        async_answer_0(callid, rc);
 
126
}
 
127
 
 
128
static void inetping_get_srcaddr_srv(inetping_client_t *client,
 
129
    ipc_callid_t callid, ipc_call_t *call)
 
130
{
 
131
        inet_addr_t remote;
 
132
        inet_addr_t local;
 
133
        int rc;
 
134
 
 
135
        log_msg(LVL_DEBUG, "inetping_get_srcaddr_srv()");
 
136
 
 
137
        remote.ipv4 = IPC_GET_ARG1(*call);
 
138
        local.ipv4 = 0;
 
139
 
 
140
        rc = inetping_get_srcaddr(client, &remote, &local);
 
141
        async_answer_1(callid, rc, local.ipv4);
 
142
}
 
143
 
 
144
static int inetping_client_init(inetping_client_t *client)
 
145
{
 
146
        async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
 
147
        if (sess == NULL)
 
148
                return ENOMEM;
 
149
 
 
150
        client->sess = sess;
 
151
        link_initialize(&client->client_list);
 
152
 
 
153
        fibril_mutex_lock(&client_list_lock);
 
154
        client->ident = ++inetping_ident;
 
155
        list_append(&client->client_list, &client_list);
 
156
        fibril_mutex_unlock(&client_list_lock);
 
157
 
 
158
        return EOK;
 
159
}
 
160
 
 
161
static void inetping_client_fini(inetping_client_t *client)
 
162
{
 
163
        async_hangup(client->sess);
 
164
        client->sess = NULL;
 
165
 
 
166
        fibril_mutex_lock(&client_list_lock);
 
167
        list_remove(&client->client_list);
 
168
        fibril_mutex_unlock(&client_list_lock);
 
169
}
 
170
 
 
171
static inetping_client_t *inetping_client_find(uint16_t ident)
 
172
{
 
173
        fibril_mutex_lock(&client_list_lock);
 
174
 
 
175
        list_foreach(client_list, link) {
 
176
                inetping_client_t *client = list_get_instance(link,
 
177
                    inetping_client_t, client_list);
 
178
 
 
179
                if (client->ident == ident) {
 
180
                        fibril_mutex_unlock(&client_list_lock);
 
181
                        return client;
 
182
                }
 
183
        }
 
184
 
 
185
        fibril_mutex_unlock(&client_list_lock);
 
186
        return NULL;
 
187
}
 
188
 
 
189
void inetping_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 
190
{
 
191
        inetping_client_t client;
 
192
        int rc;
 
193
 
 
194
        log_msg(LVL_DEBUG, "inetping_conn()");
 
195
 
 
196
        /* Accept the connection */
 
197
        async_answer_0(iid, EOK);
 
198
 
 
199
        rc = inetping_client_init(&client);
 
200
        if (rc != EOK)
 
201
                return;
 
202
 
 
203
        while (true) {
 
204
                ipc_call_t call;
 
205
                ipc_callid_t callid = async_get_call(&call);
 
206
                sysarg_t method = IPC_GET_IMETHOD(call);
 
207
 
 
208
                if (!method) {
 
209
                        /* The other side has hung up */
 
210
                        async_answer_0(callid, EOK);
 
211
                        break;
 
212
                }
 
213
 
 
214
                switch (method) {
 
215
                case INETPING_SEND:
 
216
                        inetping_send_srv(&client, callid, &call);
 
217
                        break;
 
218
                case INETPING_GET_SRCADDR:
 
219
                        inetping_get_srcaddr_srv(&client, callid, &call);
 
220
                        break;
 
221
                default:
 
222
                        async_answer_0(callid, EINVAL);
 
223
                }
 
224
        }
 
225
 
 
226
        inetping_client_fini(&client);
 
227
}
 
228
 
 
229
/** @}
 
230
 */