source: mainline/uspace/srv/net/nil/nildummy/nildummy.c@ 24ab58b3

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

more compact network startup messages (usually one line instead of multiple lines)
pass module name as an argument to nil_message() and friends
deeper cstyle changes (replace forward prototypes with proper extern declarations and static functions, change doxygen comments, stick more closely to the 80-column rule, no argument names in header files, spacing, comments, etc.)

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