source: mainline/uspace/srv/net/nil/nildummy/nildummy.c@ 1b11576d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1b11576d was 514ee46, checked in by Jakub Jermar <jakub@…>, 15 years ago

Move the rest of net_messages.h to standard library.

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