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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e417b96 was e417b96, checked in by Lukas Mejdrech <lukasmejdrech@…>, 16 years ago

IPC_[SG]ET_ARG macros refactored to be more explicit and safer

  • Property mode set to 100644
File size: 12.6 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 "../../err.h"
48#include "../../messages.h"
49#include "../../modules.h"
50
51#include "../../include/device.h"
52#include "../../include/netif_interface.h"
53#include "../../include/nil_interface.h"
54#include "../../include/il_interface.h"
55
56#include "../../structures/measured_strings.h"
57#include "../../structures/packet/packet.h"
58
59#include "../nil_module.h"
60
61#include "nildummy.h"
62
63/** Default maximum transmission unit.
64 */
65#define NET_DEFAULT_MTU 1500
66
67/** Network interface layer module global data.
68 */
69nildummy_globals_t nildummy_globals;
70
71/** @name Message processing functions
72 */
73/*@{*/
74
75/** Processes IPC messages from the registered device driver modules in an infinite loop.
76 * @param[in] iid The message identifier.
77 * @param[in,out] icall The message parameters.
78 */
79void nildummy_receiver(ipc_callid_t iid, ipc_call_t * icall);
80
81/** Registers new device or updates the MTU of an existing one.
82 * Determines the device local hardware address.
83 * @param[in] device_id The new device identifier.
84 * @param[in] service The device driver service.
85 * @param[in] mtu The device maximum transmission unit.
86 * @returns EOK on success.
87 * @returns EEXIST if the device with the different service exists.
88 * @returns ENOMEM if there is not enough memory left.
89 * @returns Other error codes as defined for the netif_bind_service() function.
90 * @returns Other error codes as defined for the netif_get_addr_req() function.
91 */
92int nildummy_device_message(device_id_t device_id, services_t service, size_t mtu);
93
94/** Returns the device packet dimensions for sending.
95 * @param[in] device_id The device identifier.
96 * @param[out] addr_len The minimum reserved address length.
97 * @param[out] prefix The minimum reserved prefix size.
98 * @param[out] content The maximum content size.
99 * @param[out] suffix The minimum reserved suffix size.
100 * @returns EOK on success.
101 * @returns EBADMEM if either one of the parameters is NULL.
102 * @returns ENOENT if there is no such device.
103 */
104int nildummy_packet_space_message(device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix);
105
106/** Registers receiving module service.
107 * Passes received packets for this service.
108 * @param[in] service The module service.
109 * @param[in] phone The service phone.
110 * @returns EOK on success.
111 * @returns ENOENT if the service is not known.
112 * @returns ENOMEM if there is not enough memory left.
113 */
114int nildummy_register_message(services_t service, int phone);
115
116/** Sends the packet queue.
117 * @param[in] device_id The device identifier.
118 * @param[in] packet The packet queue.
119 * @param[in] sender The sending module service.
120 * @returns EOK on success.
121 * @returns ENOENT if there no such device.
122 * @returns EINVAL if the service parameter is not known.
123 */
124int nildummy_send_message(device_id_t device_id, packet_t packet, services_t sender);
125
126/** Returns the device hardware address.
127 * @param[in] device_id The device identifier.
128 * @param[out] address The device hardware address.
129 * @returns EOK on success.
130 * @returns EBADMEM if the address parameter is NULL.
131 * @returns ENOENT if there no such device.
132 */
133int nildummy_addr_message(device_id_t device_id, measured_string_ref * address);
134
135/*@}*/
136
137DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t)
138
139int nil_device_state_msg(int nil_phone, device_id_t device_id, int state){
140 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
141 if(nildummy_globals.proto.phone){
142 il_device_state_msg(nildummy_globals.proto.phone, device_id, state, nildummy_globals.proto.service);
143 }
144 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
145 return EOK;
146}
147
148int nil_initialize(int net_phone){
149 ERROR_DECLARE;
150
151 fibril_rwlock_initialize(&nildummy_globals.devices_lock);
152 fibril_rwlock_initialize(&nildummy_globals.protos_lock);
153 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
154 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
155 nildummy_globals.net_phone = net_phone;
156 nildummy_globals.proto.phone = 0;
157 ERROR_PROPAGATE(nildummy_devices_initialize(&nildummy_globals.devices));
158 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
159 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
160 return EOK;
161}
162
163int nildummy_device_message(device_id_t device_id, services_t service, size_t mtu){
164 ERROR_DECLARE;
165
166 nildummy_device_ref device;
167 int index;
168
169 fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
170 // an existing device?
171 device = nildummy_devices_find(&nildummy_globals.devices, device_id);
172 if(device){
173 if(device->service != service){
174 printf("Device %d already exists\n", device->device_id);
175 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
176 return EEXIST;
177 }else{
178 // update mtu
179 if(mtu > 0){
180 device->mtu = mtu;
181 }else{
182 device->mtu = NET_DEFAULT_MTU;
183 }
184 printf("Device %d already exists:\tMTU\t= %d\n", device->device_id, device->mtu);
185 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
186 // notify the upper layer module
187 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
188 if(nildummy_globals.proto.phone){
189 il_mtu_changed_msg(nildummy_globals.proto.phone, device->device_id, device->mtu, nildummy_globals.proto.service);
190 }
191 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
192 return EOK;
193 }
194 }else{
195 // create a new device
196 device = (nildummy_device_ref) malloc(sizeof(nildummy_device_t));
197 if(! device){
198 return ENOMEM;
199 }
200 device->device_id = device_id;
201 device->service = service;
202 if(mtu > 0){
203 device->mtu = mtu;
204 }else{
205 device->mtu = NET_DEFAULT_MTU;
206 }
207 // bind the device driver
208 device->phone = netif_bind_service(device->service, device->device_id, SERVICE_ETHERNET, nildummy_receiver);
209 if(device->phone < 0){
210 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
211 free(device);
212 return device->phone;
213 }
214 // get hardware address
215 if(ERROR_OCCURRED(netif_get_addr_req(device->phone, device->device_id, &device->addr, &device->addr_data))){
216 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
217 free(device);
218 return ERROR_CODE;
219 }
220 // add to the cache
221 index = nildummy_devices_add(&nildummy_globals.devices, 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 printf("New device registered:\n\tid\t= %d\n\tservice\t= %d\n\tMTU\t= %d\n", device->device_id, device->service, device->mtu);
230 }
231 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
232 return EOK;
233}
234
235int nildummy_addr_message(device_id_t device_id, measured_string_ref * address){
236 nildummy_device_ref device;
237
238 if(! address){
239 return EBADMEM;
240 }
241 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
242 device = nildummy_devices_find(&nildummy_globals.devices, device_id);
243 if(! device){
244 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
245 return ENOENT;
246 }
247 *address = device->addr;
248 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
249 return (*address) ? EOK : ENOENT;
250}
251
252int nildummy_packet_space_message(device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix){
253 nildummy_device_ref device;
254
255 if(!(addr_len && prefix && content && suffix)){
256 return EBADMEM;
257 }
258 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
259 device = nildummy_devices_find(&nildummy_globals.devices, device_id);
260 if(! device){
261 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
262 return ENOENT;
263 }
264 *content = device->mtu;
265 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
266 *addr_len = 0;
267 *prefix = 0;
268 *suffix = 0;
269 return EOK;
270}
271
272int nil_received_msg(int nil_phone, device_id_t device_id, packet_t packet, services_t target){
273 packet_t next;
274
275 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
276 if(nildummy_globals.proto.phone){
277 do{
278 next = pq_detach(packet);
279 il_received_msg(nildummy_globals.proto.phone, device_id, packet, nildummy_globals.proto.service);
280 packet = next;
281 }while(packet);
282 }
283 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
284 return EOK;
285}
286
287int nildummy_register_message(services_t service, int phone){
288 fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
289 nildummy_globals.proto.service = service;
290 nildummy_globals.proto.phone = phone;
291 printf("New protocol registered:\n\tservice\t= %d\n\tphone\t= %d\n", nildummy_globals.proto.service, nildummy_globals.proto.phone);
292 fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
293 return EOK;
294}
295
296int nildummy_send_message(device_id_t device_id, packet_t packet, services_t sender){
297 nildummy_device_ref device;
298
299 fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
300 device = nildummy_devices_find(&nildummy_globals.devices, device_id);
301 if(! device){
302 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
303 return ENOENT;
304 }
305 // send packet queue
306 if(packet){
307 netif_send_msg(device->phone, device_id, packet, SERVICE_NILDUMMY);
308 }
309 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
310 return EOK;
311}
312
313int nil_message(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
314 ERROR_DECLARE;
315
316 measured_string_ref address;
317 packet_t packet;
318 size_t addrlen;
319 size_t prefix;
320 size_t suffix;
321 size_t content;
322
323// printf("message %d - %d\n", IPC_GET_METHOD(*call), NET_NIL_FIRST);
324 *answer_count = 0;
325 switch(IPC_GET_METHOD(*call)){
326 case IPC_M_PHONE_HUNGUP:
327 return EOK;
328 case NET_NIL_DEVICE:
329 return nildummy_device_message(IPC_GET_DEVICE(call), IPC_GET_SERVICE(call), IPC_GET_MTU(call));
330 case NET_NIL_SEND:
331 ERROR_PROPAGATE(packet_translate(nildummy_globals.net_phone, &packet, IPC_GET_PACKET(call)));
332 return nildummy_send_message(IPC_GET_DEVICE(call), packet, IPC_GET_SERVICE(call));
333 case NET_NIL_PACKET_SPACE:
334 ERROR_PROPAGATE(nildummy_packet_space_message(IPC_GET_DEVICE(call), &addrlen, &prefix, &content, &suffix));
335 IPC_SET_ADDR(answer, addrlen);
336 IPC_SET_PREFIX(answer, prefix);
337 IPC_SET_CONTENT(answer, content);
338 IPC_SET_SUFFIX(answer, suffix);
339 *answer_count = 4;
340 return EOK;
341 case NET_NIL_ADDR:
342 ERROR_PROPAGATE(nildummy_addr_message(IPC_GET_DEVICE(call), &address));
343 return measured_strings_reply(address, 1);
344 case IPC_M_CONNECT_TO_ME:
345 return nildummy_register_message(NIL_GET_PROTO(call), IPC_GET_PHONE(call));
346 }
347 return ENOTSUP;
348}
349
350void nildummy_receiver(ipc_callid_t iid, ipc_call_t * icall){
351 ERROR_DECLARE;
352
353 packet_t packet;
354
355 while(true){
356// printf("message %d - %d\n", IPC_GET_METHOD(*icall), NET_NIL_FIRST);
357 switch(IPC_GET_METHOD(*icall)){
358 case NET_NIL_DEVICE_STATE:
359 ERROR_CODE = nil_device_state_msg(0, IPC_GET_DEVICE(icall), IPC_GET_STATE(icall));
360 ipc_answer_0(iid, (ipcarg_t) ERROR_CODE);
361 break;
362 case NET_NIL_RECEIVED:
363 if(! ERROR_OCCURRED(packet_translate(nildummy_globals.net_phone, &packet, IPC_GET_PACKET(icall)))){
364 ERROR_CODE = nil_received_msg(0, IPC_GET_DEVICE(icall), packet, 0);
365 }
366 ipc_answer_0(iid, (ipcarg_t) ERROR_CODE);
367 break;
368 default:
369 ipc_answer_0(iid, (ipcarg_t) ENOTSUP);
370 }
371 iid = async_get_call(icall);
372 }
373}
374
375/** @}
376 */
Note: See TracBrowser for help on using the repository browser.