source: mainline/uspace/srv/net/nil/nildummy/nildummy.c@ 0eff68e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0eff68e 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
RevLine 
[21580dd]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
[14f1db0]30 * @{
[21580dd]31 */
32
33/** @file
[14f1db0]34 * Dummy network interface layer module implementation.
35 * @see nildummy.h
[21580dd]36 */
37
38#include <async.h>
39#include <malloc.h>
40#include <mem.h>
41#include <stdio.h>
[19f857a]42#include <str.h>
[fe8dfa6]43#include <ipc/nil.h>
[514ee46]44#include <ipc/net.h>
[21580dd]45#include <ipc/services.h>
46
[c7a8442]47#include <net/modules.h>
[e526f08]48#include <net/device.h>
[797b704]49#include <il_remote.h>
[849ed54]50#include <adt/measured_strings.h>
[c69d327]51#include <net/packet.h>
[14f1db0]52#include <packet_remote.h>
[774e6d1a]53#include <netif_remote.h>
[fe8dfa6]54#include <nil_skel.h>
[21580dd]55
[79ae36dd]56// FIXME: remove this header
57#include <kernel/ipc/ipc_methods.h>
58
[21580dd]59#include "nildummy.h"
60
[3cd95ef]61/** The module name. */
[24ab58b3]62#define NAME "nildummy"
[849ed54]63
[3cd95ef]64/** Default maximum transmission unit. */
[14f1db0]65#define NET_DEFAULT_MTU 1500
[21580dd]66
[3cd95ef]67/** Network interface layer module global data. */
[14f1db0]68nildummy_globals_t nildummy_globals;
[21580dd]69
[14f1db0]70DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t);
[21580dd]71
[14f1db0]72int nil_device_state_msg_local(int nil_phone, device_id_t device_id, int state)
73{
[aadf01e]74 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
[14f1db0]75 if (nildummy_globals.proto.phone)
[3cd95ef]76 il_device_state_msg(nildummy_globals.proto.phone, device_id,
77 state, nildummy_globals.proto.service);
[aadf01e]78 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
[14f1db0]79
[21580dd]80 return EOK;
81}
82
[14f1db0]83int nil_initialize(int net_phone)
84{
[aadf01e]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);
[14f1db0]89
[21580dd]90 nildummy_globals.net_phone = net_phone;
91 nildummy_globals.proto.phone = 0;
[fe8dfa6]92 int rc = nildummy_devices_initialize(&nildummy_globals.devices);
[14f1db0]93
[aadf01e]94 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
95 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
[14f1db0]96
[093c0a1]97 return rc;
[21580dd]98}
99
[fe8dfa6]100/** Process IPC messages from the registered device driver modules
101 *
102 * @param[in] iid Message identifier.
103 * @param[in,out] icall Message parameters.
[14f1db0]104 *
105 */
[3cd95ef]106static void nildummy_receiver(ipc_callid_t iid, ipc_call_t *icall)
107{
[46d4d9f]108 packet_t *packet;
[093c0a1]109 int rc;
[fe8dfa6]110
[3cd95ef]111 while (true) {
[228e490]112 switch (IPC_GET_IMETHOD(*icall)) {
[3cd95ef]113 case NET_NIL_DEVICE_STATE:
[093c0a1]114 rc = nil_device_state_msg_local(0,
[774e6d1a]115 IPC_GET_DEVICE(*icall), IPC_GET_STATE(*icall));
[ffa2c8ef]116 async_answer_0(iid, (sysarg_t) rc);
[3cd95ef]117 break;
118
119 case NET_NIL_RECEIVED:
[093c0a1]120 rc = packet_translate_remote(nildummy_globals.net_phone,
[774e6d1a]121 &packet, IPC_GET_PACKET(*icall));
[797b704]122 if (rc == EOK)
[093c0a1]123 rc = nil_received_msg_local(0,
[774e6d1a]124 IPC_GET_DEVICE(*icall), packet, 0);
[797b704]125
[ffa2c8ef]126 async_answer_0(iid, (sysarg_t) rc);
[3cd95ef]127 break;
128
129 default:
[ffa2c8ef]130 async_answer_0(iid, (sysarg_t) ENOTSUP);
[14f1db0]131 }
[3cd95ef]132
[14f1db0]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 *
[fe8dfa6]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 *
[14f1db0]153 */
[fb04cba8]154static int nildummy_device_message(device_id_t device_id, services_t service,
155 size_t mtu)
[14f1db0]156{
[aadf01e]157 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
[fe8dfa6]158
[fb04cba8]159 /* An existing device? */
[fe8dfa6]160 nildummy_device_t *device =
161 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]162 if (device) {
163 if (device->service != service) {
[aadf01e]164 printf("Device %d already exists\n", device->device_id);
[3cd95ef]165 fibril_rwlock_write_unlock(
166 &nildummy_globals.devices_lock);
[21580dd]167 return EEXIST;
168 }
[3cd95ef]169
[fb04cba8]170 /* Update MTU */
[3cd95ef]171 if (mtu > 0)
[21580dd]172 device->mtu = mtu;
[3cd95ef]173 else
[21580dd]174 device->mtu = NET_DEFAULT_MTU;
[3cd95ef]175
[7e752b2]176 printf("Device %d already exists:\tMTU\t= %zu\n",
[3cd95ef]177 device->device_id, device->mtu);
178 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
179
[fb04cba8]180 /* Notify the upper layer module */
[3cd95ef]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);
[21580dd]186 }
[3cd95ef]187 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
188
189 return EOK;
190 }
191
[fb04cba8]192 /* Create a new device */
[4e5c7ba]193 device = (nildummy_device_t *) malloc(sizeof(nildummy_device_t));
[3cd95ef]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
[fb04cba8]204 /* Bind the device driver */
[3cd95ef]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
[fb04cba8]213 /* Get hardware address */
[fe8dfa6]214 int rc = netif_get_addr_req(device->phone, device->device_id,
215 &device->addr, &device->addr_data);
[093c0a1]216 if (rc != EOK) {
[3cd95ef]217 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
218 free(device);
[093c0a1]219 return rc;
[21580dd]220 }
[3cd95ef]221
[fb04cba8]222 /* Add to the cache */
[fe8dfa6]223 int index = nildummy_devices_add(&nildummy_globals.devices,
[3cd95ef]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
[7e752b2]233 printf("%s: Device registered (id: %d, service: %d, mtu: %zu)\n",
[3cd95ef]234 NAME, device->device_id, device->service, device->mtu);
[aadf01e]235 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
[21580dd]236 return EOK;
237}
238
[14f1db0]239/** Return the device hardware address.
240 *
[fe8dfa6]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.
[14f1db0]247 *
248 */
[fb04cba8]249static int nildummy_addr_message(device_id_t device_id,
[4eca056]250 measured_string_t **address)
[14f1db0]251{
[3cd95ef]252 if (!address)
[aadf01e]253 return EBADMEM;
[3cd95ef]254
[aadf01e]255 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
[fe8dfa6]256
257 nildummy_device_t *device =
258 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]259 if (!device) {
[aadf01e]260 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[21580dd]261 return ENOENT;
262 }
[fe8dfa6]263
[aadf01e]264 *address = device->addr;
[fe8dfa6]265
[aadf01e]266 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[3cd95ef]267
[aadf01e]268 return (*address) ? EOK : ENOENT;
[21580dd]269}
270
[14f1db0]271/** Return the device packet dimensions for sending.
272 *
[fe8dfa6]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.
[14f1db0]282 *
283 */
[fb04cba8]284static int nildummy_packet_space_message(device_id_t device_id, size_t *addr_len,
[3cd95ef]285 size_t *prefix, size_t *content, size_t *suffix)
[14f1db0]286{
[fe8dfa6]287 if ((!addr_len) || (!prefix) || (!content) || (!suffix))
[aadf01e]288 return EBADMEM;
[3cd95ef]289
[aadf01e]290 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
[fe8dfa6]291
292 nildummy_device_t *device =
293 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]294 if (!device) {
[aadf01e]295 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[21580dd]296 return ENOENT;
297 }
[fe8dfa6]298
[aadf01e]299 *content = device->mtu;
[fe8dfa6]300
[aadf01e]301 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[3cd95ef]302
[aadf01e]303 *addr_len = 0;
304 *prefix = 0;
305 *suffix = 0;
[21580dd]306 return EOK;
307}
308
[fb04cba8]309int nil_received_msg_local(int nil_phone, device_id_t device_id,
[46d4d9f]310 packet_t *packet, services_t target)
[3cd95ef]311{
[aadf01e]312 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
[fe8dfa6]313
[3cd95ef]314 if (nildummy_globals.proto.phone) {
315 do {
[fe8dfa6]316 packet_t *next = pq_detach(packet);
[3cd95ef]317 il_received_msg(nildummy_globals.proto.phone, device_id,
318 packet, nildummy_globals.proto.service);
[21580dd]319 packet = next;
[fe8dfa6]320 } while (packet);
[21580dd]321 }
[fe8dfa6]322
[aadf01e]323 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
[3cd95ef]324
[21580dd]325 return EOK;
326}
327
[14f1db0]328/** Register receiving module service.
329 *
330 * Pass received packets for this service.
331 *
[fe8dfa6]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 *
[14f1db0]339 */
340static int nildummy_register_message(services_t service, int phone)
341{
[aadf01e]342 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
[21580dd]343 nildummy_globals.proto.service = service;
344 nildummy_globals.proto.phone = phone;
[24ab58b3]345
346 printf("%s: Protocol registered (service: %d, phone: %d)\n",
347 NAME, nildummy_globals.proto.service, nildummy_globals.proto.phone);
348
[aadf01e]349 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
[21580dd]350 return EOK;
351}
352
[14f1db0]353/** Send the packet queue.
354 *
[fe8dfa6]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 *
[14f1db0]363 */
[46d4d9f]364static int nildummy_send_message(device_id_t device_id, packet_t *packet,
[fb04cba8]365 services_t sender)
[14f1db0]366{
[aadf01e]367 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
[fe8dfa6]368
369 nildummy_device_t *device =
370 nildummy_devices_find(&nildummy_globals.devices, device_id);
[3cd95ef]371 if (!device) {
[aadf01e]372 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[21580dd]373 return ENOENT;
374 }
[fe8dfa6]375
[fb04cba8]376 /* Send packet queue */
[3cd95ef]377 if (packet)
378 netif_send_msg(device->phone, device_id, packet,
379 SERVICE_NILDUMMY);
[fe8dfa6]380
[aadf01e]381 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
[fe8dfa6]382
[21580dd]383 return EOK;
384}
385
[fe8dfa6]386int nil_module_message(ipc_callid_t callid, ipc_call_t *call,
387 ipc_call_t *answer, size_t *answer_count)
[24ab58b3]388{
[4eca056]389 measured_string_t *address;
[46d4d9f]390 packet_t *packet;
[e417b96]391 size_t addrlen;
392 size_t prefix;
393 size_t suffix;
394 size_t content;
[093c0a1]395 int rc;
[24ab58b3]396
[aadf01e]397 *answer_count = 0;
[79ae36dd]398
399 if (!IPC_GET_IMETHOD(*call))
[3cd95ef]400 return EOK;
401
[79ae36dd]402 switch (IPC_GET_IMETHOD(*call)) {
[3cd95ef]403 case NET_NIL_DEVICE:
[774e6d1a]404 return nildummy_device_message(IPC_GET_DEVICE(*call),
405 IPC_GET_SERVICE(*call), IPC_GET_MTU(*call));
[3cd95ef]406
407 case NET_NIL_SEND:
[093c0a1]408 rc = packet_translate_remote(nildummy_globals.net_phone,
[774e6d1a]409 &packet, IPC_GET_PACKET(*call));
[093c0a1]410 if (rc != EOK)
411 return rc;
[774e6d1a]412 return nildummy_send_message(IPC_GET_DEVICE(*call), packet,
413 IPC_GET_SERVICE(*call));
[3cd95ef]414
415 case NET_NIL_PACKET_SPACE:
[774e6d1a]416 rc = nildummy_packet_space_message(IPC_GET_DEVICE(*call),
[093c0a1]417 &addrlen, &prefix, &content, &suffix);
418 if (rc != EOK)
419 return rc;
[774e6d1a]420 IPC_SET_ADDR(*answer, addrlen);
421 IPC_SET_PREFIX(*answer, prefix);
422 IPC_SET_CONTENT(*answer, content);
423 IPC_SET_SUFFIX(*answer, suffix);
[3cd95ef]424 *answer_count = 4;
425 return EOK;
426
427 case NET_NIL_ADDR:
[774e6d1a]428 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &address);
[093c0a1]429 if (rc != EOK)
430 return rc;
[3cd95ef]431 return measured_strings_reply(address, 1);
432
433 case NET_NIL_BROADCAST_ADDR:
[774e6d1a]434 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &address);
[093c0a1]435 if (rc != EOK)
436 return rc;
[3cd95ef]437 return measured_strings_reply(address, 1);
438
439 case IPC_M_CONNECT_TO_ME:
[774e6d1a]440 return nildummy_register_message(NIL_GET_PROTO(*call),
441 IPC_GET_PHONE(*call));
[21580dd]442 }
[24ab58b3]443
[21580dd]444 return ENOTSUP;
445}
446
[849ed54]447int main(int argc, char *argv[])
448{
449 /* Start the module */
[fe8dfa6]450 return nil_module_start(SERVICE_NILDUMMY);
[849ed54]451}
452
[21580dd]453/** @}
454 */
Note: See TracBrowser for help on using the repository browser.