source: mainline/uspace/srv/net/nil/nildummy/nildummy.c@ 4c3ad56

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4c3ad56 was 49bd793b, checked in by Martin Decky <martin@…>, 14 years ago

networking fixes

  • use sysarg_t for packet_id_t to avoid potential overflow
  • fix the confusion in the order of arguments for nil_received_msg(), this fixes the strange ping timeout on 127.0.0.1
  • Property mode set to 100644
File size: 12.2 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * Copyright (c) 2011 Radim Vansa
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 nildummy
31 * @{
32 */
33
34/** @file
35 * Dummy network interface layer module implementation.
36 * @see nildummy.h
37 */
38
39#include <assert.h>
40#include <async.h>
41#include <malloc.h>
42#include <mem.h>
43#include <stdio.h>
44#include <str.h>
45#include <ipc/nil.h>
46#include <ipc/net.h>
47#include <ipc/services.h>
48#include <net/modules.h>
49#include <net/device.h>
50#include <il_remote.h>
51#include <adt/measured_strings.h>
52#include <net/packet.h>
53#include <packet_remote.h>
54#include <packet_client.h>
55#include <devman.h>
56#include <device/nic.h>
57#include <nil_skel.h>
58#include "nildummy.h"
59
60/** The module name. */
61#define NAME "nildummy"
62
63/** Default maximum transmission unit. */
64#define NET_DEFAULT_MTU 1500
65
66/** Network interface layer module global data. */
67nildummy_globals_t nildummy_globals;
68
69DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t);
70
71int nil_device_state_msg_local(nic_device_id_t device_id, sysarg_t state)
72{
73 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
74 if (nildummy_globals.proto.sess)
75 il_device_state_msg(nildummy_globals.proto.sess, device_id,
76 state, nildummy_globals.proto.service);
77 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
78
79 return EOK;
80}
81
82int nil_initialize(async_sess_t *sess)
83{
84 fibril_rwlock_initialize(&nildummy_globals.devices_lock);
85 fibril_rwlock_initialize(&nildummy_globals.protos_lock);
86 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
87 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
88
89 nildummy_globals.net_sess = sess;
90 nildummy_globals.proto.sess = NULL;
91 int rc = nildummy_devices_initialize(&nildummy_globals.devices);
92
93 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
94 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
95
96 return rc;
97}
98
99/** Register new device or updates the MTU of an existing one.
100 *
101 * Determine the device local hardware address.
102 *
103 * @param[in] device_id New device identifier.
104 * @param[in] service Device driver service.
105 * @param[in] mtu Device maximum transmission unit.
106 *
107 * @return EOK on success.
108 * @return EEXIST if the device with the different service exists.
109 * @return ENOMEM if there is not enough memory left.
110 * @return Other error codes as defined for the
111 * netif_bind_service() function.
112 * @return Other error codes as defined for the
113 * netif_get_addr_req() function.
114 *
115 */
116static int nildummy_device_message(nic_device_id_t device_id,
117 devman_handle_t handle, size_t mtu)
118{
119 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
120
121 /* An existing device? */
122 nildummy_device_t *device =
123 nildummy_devices_find(&nildummy_globals.devices, device_id);
124 if (device) {
125 if (device->handle != handle) {
126 printf("Device %d exists, handles do not match\n",
127 device->device_id);
128 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
129 return EEXIST;
130 }
131
132 /* Update MTU */
133 if (mtu > 0)
134 device->mtu = mtu;
135 else
136 device->mtu = NET_DEFAULT_MTU;
137
138 printf("Device %d already exists (mtu: %zu)\n", device->device_id,
139 device->mtu);
140 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
141
142 /* Notify the upper layer module */
143 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
144 if (nildummy_globals.proto.sess) {
145 il_mtu_changed_msg(nildummy_globals.proto.sess,
146 device->device_id, device->mtu,
147 nildummy_globals.proto.service);
148 }
149 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
150
151 return EOK;
152 }
153
154 /* Create a new device */
155 device = (nildummy_device_t *) malloc(sizeof(nildummy_device_t));
156 if (!device)
157 return ENOMEM;
158
159 device->device_id = device_id;
160 device->handle = handle;
161 if (mtu > 0)
162 device->mtu = mtu;
163 else
164 device->mtu = NET_DEFAULT_MTU;
165
166 /* Bind the device driver */
167 device->sess = devman_device_connect(EXCHANGE_SERIALIZE, handle,
168 IPC_FLAG_BLOCKING);
169 if (device->sess == NULL) {
170 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
171 free(device);
172 return ENOENT;
173 }
174
175 nic_connect_to_nil(device->sess, SERVICE_NILDUMMY, device_id);
176
177 /* Get hardware address */
178 int rc = nic_get_address(device->sess, &device->addr);
179 if (rc != EOK) {
180 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
181 free(device);
182 return rc;
183 }
184
185 device->addr_len = ETH_ADDR;
186
187 /* Add to the cache */
188 int index = nildummy_devices_add(&nildummy_globals.devices,
189 device->device_id, device);
190 if (index < 0) {
191 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
192 free(device);
193 return index;
194 }
195
196 printf("%s: Device registered (id: %d, mtu: %zu)\n", NAME,
197 device->device_id, device->mtu);
198 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
199 return EOK;
200}
201
202/** Return the device hardware address.
203 *
204 * @param[in] device_id Device identifier.
205 * @param[out] address Device hardware address.
206 *
207 * @return EOK on success.
208 * @return EBADMEM if the address parameter is NULL.
209 * @return ENOENT if there no such device.
210 *
211 */
212static int nildummy_addr_message(nic_device_id_t device_id, size_t *addrlen)
213{
214 if (!addrlen)
215 return EBADMEM;
216
217 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
218
219 nildummy_device_t *device =
220 nildummy_devices_find(&nildummy_globals.devices, device_id);
221 if (!device) {
222 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
223 return ENOENT;
224 }
225
226 ipc_callid_t callid;
227 size_t max_len;
228 if (!async_data_read_receive(&callid, &max_len)) {
229 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
230 return EREFUSED;
231 }
232
233 if (max_len < device->addr_len) {
234 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
235 async_data_read_finalize(callid, NULL, 0);
236 return ELIMIT;
237 }
238
239 int rc = async_data_read_finalize(callid,
240 (uint8_t *) &device->addr.address, device->addr_len);
241 if (rc != EOK) {
242 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
243 return rc;
244 }
245
246 *addrlen = device->addr_len;
247
248 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
249 return EOK;
250}
251
252/** Return the device packet dimensions for sending.
253 *
254 * @param[in] device_id Device identifier.
255 * @param[out] addr_len Minimum reserved address length.
256 * @param[out] prefix Minimum reserved prefix size.
257 * @param[out] content Maximum content size.
258 * @param[out] suffix Minimum reserved suffix size.
259 *
260 * @return EOK on success.
261 * @return EBADMEM if either one of the parameters is NULL.
262 * @return ENOENT if there is no such device.
263 *
264 */
265static int nildummy_packet_space_message(nic_device_id_t device_id,
266 size_t *addr_len, size_t *prefix, size_t *content, size_t *suffix)
267{
268 if ((!addr_len) || (!prefix) || (!content) || (!suffix))
269 return EBADMEM;
270
271 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
272
273 nildummy_device_t *device =
274 nildummy_devices_find(&nildummy_globals.devices, device_id);
275 if (!device) {
276 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
277 return ENOENT;
278 }
279
280 *content = device->mtu;
281
282 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
283
284 *addr_len = 0;
285 *prefix = 0;
286 *suffix = 0;
287 return EOK;
288}
289
290int nil_received_msg_local(nic_device_id_t device_id, packet_t *packet)
291{
292 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
293
294 if (nildummy_globals.proto.sess) {
295 do {
296 packet_t *next = pq_detach(packet);
297 il_received_msg(nildummy_globals.proto.sess, device_id,
298 packet, nildummy_globals.proto.service);
299 packet = next;
300 } while (packet);
301 }
302
303 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
304
305 return EOK;
306}
307
308/** Register receiving module service.
309 *
310 * Pass received packets for this service.
311 *
312 * @param[in] service Module service.
313 * @param[in] sess Service session.
314 *
315 * @return EOK on success.
316 * @return ENOENT if the service is not known.
317 * @return ENOMEM if there is not enough memory left.
318 *
319 */
320static int nildummy_register_message(services_t service, async_sess_t *sess)
321{
322 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
323 nildummy_globals.proto.service = service;
324 nildummy_globals.proto.sess = sess;
325
326 printf("%s: Protocol registered (service: %#x)\n",
327 NAME, nildummy_globals.proto.service);
328
329 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
330 return EOK;
331}
332
333/** Send the packet queue.
334 *
335 * @param[in] device_id Device identifier.
336 * @param[in] packet Packet queue.
337 * @param[in] sender Sending module service.
338 *
339 * @return EOK on success.
340 * @return ENOENT if there no such device.
341 * @return EINVAL if the service parameter is not known.
342 *
343 */
344static int nildummy_send_message(nic_device_id_t device_id, packet_t *packet,
345 services_t sender)
346{
347 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
348
349 nildummy_device_t *device =
350 nildummy_devices_find(&nildummy_globals.devices, device_id);
351 if (!device) {
352 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
353 return ENOENT;
354 }
355
356 /* Send packet queue */
357 if (packet)
358 nic_send_message(device->sess, packet_get_id(packet));
359
360 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
361
362 return EOK;
363}
364
365int nil_module_message(ipc_callid_t callid, ipc_call_t *call,
366 ipc_call_t *answer, size_t *answer_count)
367{
368 packet_t *packet;
369 size_t addrlen;
370 size_t prefix;
371 size_t suffix;
372 size_t content;
373 int rc;
374
375 *answer_count = 0;
376
377 if (!IPC_GET_IMETHOD(*call))
378 return EOK;
379
380 async_sess_t *callback =
381 async_callback_receive_start(EXCHANGE_SERIALIZE, call);
382 if (callback)
383 return nildummy_register_message(NIL_GET_PROTO(*call), callback);
384
385 switch (IPC_GET_IMETHOD(*call)) {
386 case NET_NIL_DEVICE:
387 return nildummy_device_message(IPC_GET_DEVICE(*call),
388 IPC_GET_DEVICE_HANDLE(*call), IPC_GET_MTU(*call));
389
390 case NET_NIL_SEND:
391 rc = packet_translate_remote(nildummy_globals.net_sess,
392 &packet, IPC_GET_PACKET(*call));
393 if (rc != EOK)
394 return rc;
395 return nildummy_send_message(IPC_GET_DEVICE(*call), packet,
396 IPC_GET_SERVICE(*call));
397
398 case NET_NIL_PACKET_SPACE:
399 rc = nildummy_packet_space_message(IPC_GET_DEVICE(*call),
400 &addrlen, &prefix, &content, &suffix);
401 if (rc != EOK)
402 return rc;
403 IPC_SET_ADDR(*answer, addrlen);
404 IPC_SET_PREFIX(*answer, prefix);
405 IPC_SET_CONTENT(*answer, content);
406 IPC_SET_SUFFIX(*answer, suffix);
407 *answer_count = 4;
408 return EOK;
409
410 case NET_NIL_ADDR:
411 case NET_NIL_BROADCAST_ADDR:
412 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &addrlen);
413 if (rc != EOK)
414 return rc;
415
416 IPC_SET_ADDR(*answer, addrlen);
417 *answer_count = 1;
418 return rc;
419 case NET_NIL_DEVICE_STATE:
420 rc = nil_device_state_msg_local(IPC_GET_DEVICE(*call),
421 IPC_GET_STATE(*call));
422 async_answer_0(callid, (sysarg_t) rc);
423 return rc;
424
425 case NET_NIL_RECEIVED:
426 rc = packet_translate_remote(nildummy_globals.net_sess, &packet,
427 IPC_GET_ARG2(*call));
428 if (rc == EOK)
429 rc = nil_received_msg_local(IPC_GET_ARG1(*call), packet);
430
431 async_answer_0(callid, (sysarg_t) rc);
432 return rc;
433 }
434
435 return ENOTSUP;
436}
437
438int main(int argc, char *argv[])
439{
440 /* Start the module */
441 return nil_module_start(SERVICE_NILDUMMY);
442}
443
444/** @}
445 */
Note: See TracBrowser for help on using the repository browser.