source: mainline/uspace/srv/net/nil/nildummy/nildummy.c@ 41811af

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 41811af was 79ae36dd, checked in by Martin Decky <martin@…>, 15 years ago

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • Property mode set to 100644
File size: 12.3 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
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 nildummy
30 * @{
31 */
32
33/** @file
34 * Dummy network interface layer module implementation.
35 * @see nildummy.h
36 */
37
38#include <async.h>
39#include <malloc.h>
40#include <mem.h>
41#include <stdio.h>
42#include <str.h>
43#include <ipc/nil.h>
44#include <ipc/net.h>
45#include <ipc/services.h>
46
47#include <net/modules.h>
48#include <net/device.h>
49#include <il_remote.h>
50#include <adt/measured_strings.h>
51#include <net/packet.h>
52#include <packet_remote.h>
53#include <netif_remote.h>
54#include <nil_skel.h>
55
56// FIXME: remove this header
57#include <kernel/ipc/ipc_methods.h>
58
59#include "nildummy.h"
60
61/** The module name. */
62#define NAME "nildummy"
63
64/** Default maximum transmission unit. */
65#define NET_DEFAULT_MTU 1500
66
67/** Network interface layer module global data. */
68nildummy_globals_t nildummy_globals;
69
70DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t);
71
72int nil_device_state_msg_local(int nil_phone, device_id_t device_id, int state)
73{
74 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
75 if (nildummy_globals.proto.phone)
76 il_device_state_msg(nildummy_globals.proto.phone, device_id,
77 state, nildummy_globals.proto.service);
78 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
79
80 return EOK;
81}
82
83int nil_initialize(int net_phone)
84{
85 fibril_rwlock_initialize(&nildummy_globals.devices_lock);
86 fibril_rwlock_initialize(&nildummy_globals.protos_lock);
87 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
88 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
89
90 nildummy_globals.net_phone = net_phone;
91 nildummy_globals.proto.phone = 0;
92 int rc = nildummy_devices_initialize(&nildummy_globals.devices);
93
94 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
95 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
96
97 return rc;
98}
99
100/** Process IPC messages from the registered device driver modules
101 *
102 * @param[in] iid Message identifier.
103 * @param[in,out] icall Message parameters.
104 *
105 */
106static void nildummy_receiver(ipc_callid_t iid, ipc_call_t *icall)
107{
108 packet_t *packet;
109 int rc;
110
111 while (true) {
112 switch (IPC_GET_IMETHOD(*icall)) {
113 case NET_NIL_DEVICE_STATE:
114 rc = nil_device_state_msg_local(0,
115 IPC_GET_DEVICE(*icall), IPC_GET_STATE(*icall));
116 async_answer_0(iid, (sysarg_t) rc);
117 break;
118
119 case NET_NIL_RECEIVED:
120 rc = packet_translate_remote(nildummy_globals.net_phone,
121 &packet, IPC_GET_PACKET(*icall));
122 if (rc == EOK)
123 rc = nil_received_msg_local(0,
124 IPC_GET_DEVICE(*icall), packet, 0);
125
126 async_answer_0(iid, (sysarg_t) rc);
127 break;
128
129 default:
130 async_answer_0(iid, (sysarg_t) ENOTSUP);
131 }
132
133 iid = async_get_call(icall);
134 }
135}
136
137/** Register new device or updates the MTU of an existing one.
138 *
139 * Determine the device local hardware address.
140 *
141 * @param[in] device_id New device identifier.
142 * @param[in] service Device driver service.
143 * @param[in] mtu Device maximum transmission unit.
144 *
145 * @return EOK on success.
146 * @return EEXIST if the device with the different service exists.
147 * @return ENOMEM if there is not enough memory left.
148 * @return Other error codes as defined for the
149 * netif_bind_service() function.
150 * @return Other error codes as defined for the
151 * netif_get_addr_req() function.
152 *
153 */
154static int nildummy_device_message(device_id_t device_id, services_t service,
155 size_t mtu)
156{
157 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
158
159 /* An existing device? */
160 nildummy_device_t *device =
161 nildummy_devices_find(&nildummy_globals.devices, device_id);
162 if (device) {
163 if (device->service != service) {
164 printf("Device %d already exists\n", device->device_id);
165 fibril_rwlock_write_unlock(
166 &nildummy_globals.devices_lock);
167 return EEXIST;
168 }
169
170 /* Update MTU */
171 if (mtu > 0)
172 device->mtu = mtu;
173 else
174 device->mtu = NET_DEFAULT_MTU;
175
176 printf("Device %d already exists:\tMTU\t= %zu\n",
177 device->device_id, device->mtu);
178 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
179
180 /* Notify the upper layer module */
181 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
182 if (nildummy_globals.proto.phone) {
183 il_mtu_changed_msg(nildummy_globals.proto.phone,
184 device->device_id, device->mtu,
185 nildummy_globals.proto.service);
186 }
187 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
188
189 return EOK;
190 }
191
192 /* Create a new device */
193 device = (nildummy_device_t *) malloc(sizeof(nildummy_device_t));
194 if (!device)
195 return ENOMEM;
196
197 device->device_id = device_id;
198 device->service = service;
199 if (mtu > 0)
200 device->mtu = mtu;
201 else
202 device->mtu = NET_DEFAULT_MTU;
203
204 /* Bind the device driver */
205 device->phone = netif_bind_service(device->service, device->device_id,
206 SERVICE_ETHERNET, nildummy_receiver);
207 if (device->phone < 0) {
208 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
209 free(device);
210 return device->phone;
211 }
212
213 /* Get hardware address */
214 int rc = netif_get_addr_req(device->phone, device->device_id,
215 &device->addr, &device->addr_data);
216 if (rc != EOK) {
217 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
218 free(device);
219 return rc;
220 }
221
222 /* Add to the cache */
223 int index = nildummy_devices_add(&nildummy_globals.devices,
224 device->device_id, device);
225 if (index < 0) {
226 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
227 free(device->addr);
228 free(device->addr_data);
229 free(device);
230 return index;
231 }
232
233 printf("%s: Device registered (id: %d, service: %d, mtu: %zu)\n",
234 NAME, device->device_id, device->service, device->mtu);
235 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
236 return EOK;
237}
238
239/** Return the device hardware address.
240 *
241 * @param[in] device_id Device identifier.
242 * @param[out] address Device hardware address.
243 *
244 * @return EOK on success.
245 * @return EBADMEM if the address parameter is NULL.
246 * @return ENOENT if there no such device.
247 *
248 */
249static int nildummy_addr_message(device_id_t device_id,
250 measured_string_t **address)
251{
252 if (!address)
253 return EBADMEM;
254
255 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
256
257 nildummy_device_t *device =
258 nildummy_devices_find(&nildummy_globals.devices, device_id);
259 if (!device) {
260 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
261 return ENOENT;
262 }
263
264 *address = device->addr;
265
266 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
267
268 return (*address) ? EOK : ENOENT;
269}
270
271/** Return the device packet dimensions for sending.
272 *
273 * @param[in] device_id Device identifier.
274 * @param[out] addr_len Minimum reserved address length.
275 * @param[out] prefix Minimum reserved prefix size.
276 * @param[out] content Maximum content size.
277 * @param[out] suffix Minimum reserved suffix size.
278 *
279 * @return EOK on success.
280 * @return EBADMEM if either one of the parameters is NULL.
281 * @return ENOENT if there is no such device.
282 *
283 */
284static int nildummy_packet_space_message(device_id_t device_id, size_t *addr_len,
285 size_t *prefix, size_t *content, size_t *suffix)
286{
287 if ((!addr_len) || (!prefix) || (!content) || (!suffix))
288 return EBADMEM;
289
290 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
291
292 nildummy_device_t *device =
293 nildummy_devices_find(&nildummy_globals.devices, device_id);
294 if (!device) {
295 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
296 return ENOENT;
297 }
298
299 *content = device->mtu;
300
301 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
302
303 *addr_len = 0;
304 *prefix = 0;
305 *suffix = 0;
306 return EOK;
307}
308
309int nil_received_msg_local(int nil_phone, device_id_t device_id,
310 packet_t *packet, services_t target)
311{
312 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
313
314 if (nildummy_globals.proto.phone) {
315 do {
316 packet_t *next = pq_detach(packet);
317 il_received_msg(nildummy_globals.proto.phone, device_id,
318 packet, nildummy_globals.proto.service);
319 packet = next;
320 } while (packet);
321 }
322
323 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
324
325 return EOK;
326}
327
328/** Register receiving module service.
329 *
330 * Pass received packets for this service.
331 *
332 * @param[in] service Module service.
333 * @param[in] phone Service phone.
334 *
335 * @return EOK on success.
336 * @return ENOENT if the service is not known.
337 * @return ENOMEM if there is not enough memory left.
338 *
339 */
340static int nildummy_register_message(services_t service, int phone)
341{
342 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
343 nildummy_globals.proto.service = service;
344 nildummy_globals.proto.phone = phone;
345
346 printf("%s: Protocol registered (service: %d, phone: %d)\n",
347 NAME, nildummy_globals.proto.service, nildummy_globals.proto.phone);
348
349 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
350 return EOK;
351}
352
353/** Send the packet queue.
354 *
355 * @param[in] device_id Device identifier.
356 * @param[in] packet Packet queue.
357 * @param[in] sender Sending module service.
358 *
359 * @return EOK on success.
360 * @return ENOENT if there no such device.
361 * @return EINVAL if the service parameter is not known.
362 *
363 */
364static int nildummy_send_message(device_id_t device_id, packet_t *packet,
365 services_t sender)
366{
367 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
368
369 nildummy_device_t *device =
370 nildummy_devices_find(&nildummy_globals.devices, device_id);
371 if (!device) {
372 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
373 return ENOENT;
374 }
375
376 /* Send packet queue */
377 if (packet)
378 netif_send_msg(device->phone, device_id, packet,
379 SERVICE_NILDUMMY);
380
381 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
382
383 return EOK;
384}
385
386int nil_module_message(ipc_callid_t callid, ipc_call_t *call,
387 ipc_call_t *answer, size_t *answer_count)
388{
389 measured_string_t *address;
390 packet_t *packet;
391 size_t addrlen;
392 size_t prefix;
393 size_t suffix;
394 size_t content;
395 int rc;
396
397 *answer_count = 0;
398
399 if (!IPC_GET_IMETHOD(*call))
400 return EOK;
401
402 switch (IPC_GET_IMETHOD(*call)) {
403 case NET_NIL_DEVICE:
404 return nildummy_device_message(IPC_GET_DEVICE(*call),
405 IPC_GET_SERVICE(*call), IPC_GET_MTU(*call));
406
407 case NET_NIL_SEND:
408 rc = packet_translate_remote(nildummy_globals.net_phone,
409 &packet, IPC_GET_PACKET(*call));
410 if (rc != EOK)
411 return rc;
412 return nildummy_send_message(IPC_GET_DEVICE(*call), packet,
413 IPC_GET_SERVICE(*call));
414
415 case NET_NIL_PACKET_SPACE:
416 rc = nildummy_packet_space_message(IPC_GET_DEVICE(*call),
417 &addrlen, &prefix, &content, &suffix);
418 if (rc != EOK)
419 return rc;
420 IPC_SET_ADDR(*answer, addrlen);
421 IPC_SET_PREFIX(*answer, prefix);
422 IPC_SET_CONTENT(*answer, content);
423 IPC_SET_SUFFIX(*answer, suffix);
424 *answer_count = 4;
425 return EOK;
426
427 case NET_NIL_ADDR:
428 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &address);
429 if (rc != EOK)
430 return rc;
431 return measured_strings_reply(address, 1);
432
433 case NET_NIL_BROADCAST_ADDR:
434 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &address);
435 if (rc != EOK)
436 return rc;
437 return measured_strings_reply(address, 1);
438
439 case IPC_M_CONNECT_TO_ME:
440 return nildummy_register_message(NIL_GET_PROTO(*call),
441 IPC_GET_PHONE(*call));
442 }
443
444 return ENOTSUP;
445}
446
447int main(int argc, char *argv[])
448{
449 /* Start the module */
450 return nil_module_start(SERVICE_NILDUMMY);
451}
452
453/** @}
454 */
Note: See TracBrowser for help on using the repository browser.