source: mainline/uspace/srv/net/nil/nildummy/nildummy.c@ 40ffda8

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

do not intermix low-level IPC methods with async framework methods

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