source: mainline/uspace/lib/net/netif/netif_local.c@ 228e490

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

initial modifications for supporting declarative IPC interfaces

  • Property mode set to 100644
File size: 12.2 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 libnet
30 * @{
31 */
32
33/** @file
34 * Network interface module skeleton implementation.
35 * @see netif.h
36 */
37
38#include <async.h>
39#include <mem.h>
40#include <fibril_synch.h>
41#include <stdio.h>
42#include <ipc/ipc.h>
43#include <ipc/services.h>
44#include <ipc/netif.h>
45#include <errno.h>
46
47#include <generic.h>
48#include <net/modules.h>
49#include <net/packet.h>
50#include <packet_client.h>
51#include <packet_remote.h>
52#include <adt/measured_strings.h>
53#include <net/device.h>
54#include <nil_interface.h>
55#include <netif_local.h>
56#include <netif_interface.h>
57
58DEVICE_MAP_IMPLEMENT(netif_device_map, netif_device_t);
59
60/** Network interface global data. */
61netif_globals_t netif_globals;
62
63/** Probe the existence of the device.
64 *
65 * @param[in] netif_phone The network interface phone.
66 * @param[in] device_id The device identifier.
67 * @param[in] irq The device interrupt number.
68 * @param[in] io The device input/output address.
69 * @return EOK on success.
70 * @return Other error codes as defined for the
71 * netif_probe_message().
72 */
73int
74netif_probe_req_local(int netif_phone, device_id_t device_id, int irq, int io)
75{
76 fibril_rwlock_write_lock(&netif_globals.lock);
77 int result = netif_probe_message(device_id, irq, io);
78 fibril_rwlock_write_unlock(&netif_globals.lock);
79
80 return result;
81}
82
83/** Send the packet queue.
84 *
85 * @param[in] netif_phone The network interface phone.
86 * @param[in] device_id The device identifier.
87 * @param[in] packet The packet queue.
88 * @param[in] sender The sending module service.
89 * @return EOK on success.
90 * @return Other error codes as defined for the generic_send_msg()
91 * function.
92 */
93int netif_send_msg_local(int netif_phone, device_id_t device_id,
94 packet_t *packet, services_t sender)
95{
96 fibril_rwlock_write_lock(&netif_globals.lock);
97 int result = netif_send_message(device_id, packet, sender);
98 fibril_rwlock_write_unlock(&netif_globals.lock);
99
100 return result;
101}
102
103/** Start the device.
104 *
105 * @param[in] netif_phone The network interface phone.
106 * @param[in] device_id The device identifier.
107 * @return EOK on success.
108 * @return Other error codes as defined for the find_device()
109 * function.
110 * @return Other error codes as defined for the
111 * netif_start_message() function.
112 */
113int netif_start_req_local(int netif_phone, device_id_t device_id)
114{
115 int rc;
116
117 fibril_rwlock_write_lock(&netif_globals.lock);
118
119 netif_device_t *device;
120 rc = find_device(device_id, &device);
121 if (rc != EOK) {
122 fibril_rwlock_write_unlock(&netif_globals.lock);
123 return rc;
124 }
125
126 int result = netif_start_message(device);
127 if (result > NETIF_NULL) {
128 int phone = device->nil_phone;
129 fibril_rwlock_write_unlock(&netif_globals.lock);
130 nil_device_state_msg(phone, device_id, result);
131 return EOK;
132 }
133
134 fibril_rwlock_write_unlock(&netif_globals.lock);
135
136 return result;
137}
138
139/** Stop the device.
140 *
141 * @param[in] netif_phone The network interface phone.
142 * @param[in] device_id The device identifier.
143 * @return EOK on success.
144 * @return Other error codes as defined for the find_device()
145 * function.
146 * @return Other error codes as defined for the
147 * netif_stop_message() function.
148 */
149int netif_stop_req_local(int netif_phone, device_id_t device_id)
150{
151 int rc;
152
153 fibril_rwlock_write_lock(&netif_globals.lock);
154
155 netif_device_t *device;
156 rc = find_device(device_id, &device);
157 if (rc != EOK) {
158 fibril_rwlock_write_unlock(&netif_globals.lock);
159 return rc;
160 }
161
162 int result = netif_stop_message(device);
163 if (result > NETIF_NULL) {
164 int phone = device->nil_phone;
165 fibril_rwlock_write_unlock(&netif_globals.lock);
166 nil_device_state_msg(phone, device_id, result);
167 return EOK;
168 }
169
170 fibril_rwlock_write_unlock(&netif_globals.lock);
171
172 return result;
173}
174
175/** Return the device usage statistics.
176 *
177 * @param[in] netif_phone The network interface phone.
178 * @param[in] device_id The device identifier.
179 * @param[out] stats The device usage statistics.
180 * @return EOK on success.
181 */
182int netif_stats_req_local(int netif_phone, device_id_t device_id,
183 device_stats_t *stats)
184{
185 fibril_rwlock_read_lock(&netif_globals.lock);
186 int res = netif_get_device_stats(device_id, stats);
187 fibril_rwlock_read_unlock(&netif_globals.lock);
188
189 return res;
190}
191
192/** Return the device local hardware address.
193 *
194 * @param[in] netif_phone The network interface phone.
195 * @param[in] device_id The device identifier.
196 * @param[out] address The device local hardware address.
197 * @param[out] data The address data.
198 * @return EOK on success.
199 * @return EBADMEM if the address parameter is NULL.
200 * @return ENOENT if there no such device.
201 * @return Other error codes as defined for the
202 * netif_get_addr_message() function.
203 */
204int netif_get_addr_req_local(int netif_phone, device_id_t device_id,
205 measured_string_t **address, char **data)
206{
207 int rc;
208
209 if (!address || !data)
210 return EBADMEM;
211
212 fibril_rwlock_read_lock(&netif_globals.lock);
213
214 measured_string_t translation;
215 rc = netif_get_addr_message(device_id, &translation);
216 if (rc == EOK) {
217 *address = measured_string_copy(&translation);
218 rc = (*address) ? EOK : ENOMEM;
219 }
220
221 fibril_rwlock_read_unlock(&netif_globals.lock);
222
223 *data = (**address).value;
224
225 return rc;
226}
227
228/** Find the device specific data.
229 *
230 * @param[in] device_id The device identifier.
231 * @param[out] device The device specific data.
232 * @return EOK on success.
233 * @return ENOENT if device is not found.
234 * @return EPERM if the device is not initialized.
235 */
236int find_device(device_id_t device_id, netif_device_t **device)
237{
238 if (!device)
239 return EBADMEM;
240
241 *device = netif_device_map_find(&netif_globals.device_map, device_id);
242 if (*device == NULL)
243 return ENOENT;
244
245 if ((*device)->state == NETIF_NULL)
246 return EPERM;
247
248 return EOK;
249}
250
251/** Clear the usage statistics.
252 *
253 * @param[in] stats The usage statistics.
254 */
255void null_device_stats(device_stats_t *stats)
256{
257 bzero(stats, sizeof(device_stats_t));
258}
259
260/** Initialize the netif module.
261 *
262 * @param[in] client_connection The client connection functio to be registered.
263 * @return EOK on success.
264 * @return Other error codes as defined for each specific module
265 * message function.
266 */
267int netif_init_module(async_client_conn_t client_connection)
268{
269 int rc;
270
271 async_set_client_connection(client_connection);
272
273 netif_globals.net_phone = connect_to_service(SERVICE_NETWORKING);
274 netif_device_map_initialize(&netif_globals.device_map);
275
276 rc = pm_init();
277 if (rc != EOK)
278 return rc;
279
280 fibril_rwlock_initialize(&netif_globals.lock);
281
282 rc = netif_initialize();
283 if (rc != EOK) {
284 pm_destroy();
285 return rc;
286 }
287
288 return EOK;
289}
290
291/** Release the given packet.
292 *
293 * Prepared for future optimization.
294 *
295 * @param[in] packet_id The packet identifier.
296 */
297void netif_pq_release(packet_id_t packet_id)
298{
299 pq_release_remote(netif_globals.net_phone, packet_id);
300}
301
302/** Allocate new packet to handle the given content size.
303 *
304 * @param[in] content The minimum content size.
305 * @return The allocated packet.
306 * @return NULL if there is an error.
307 *
308 */
309packet_t *netif_packet_get_1(size_t content)
310{
311 return packet_get_1_remote(netif_globals.net_phone, content);
312}
313
314/** Register the device notification receiver, the network interface layer
315 * module.
316 *
317 * @param[in] name Module name.
318 * @param[in] device_id The device identifier.
319 * @param[in] phone The network interface layer module phone.
320 * @return EOK on success.
321 * @return ENOENT if there is no such device.
322 * @return ELIMIT if there is another module registered.
323 */
324static int register_message(const char *name, device_id_t device_id, int phone)
325{
326 netif_device_t *device;
327 int rc;
328
329 rc = find_device(device_id, &device);
330 if (rc != EOK)
331 return rc;
332
333 if (device->nil_phone > 0)
334 return ELIMIT;
335
336 device->nil_phone = phone;
337 printf("%s: Receiver of device %d registered (phone: %d)\n",
338 name, device->device_id, device->nil_phone);
339 return EOK;
340}
341
342/** Process the netif module messages.
343 *
344 * @param[in] name Module name.
345 * @param[in] callid The message identifier.
346 * @param[in] call The message parameters.
347 * @param[out] answer The message answer parameters.
348 * @param[out] answer_count The last parameter for the actual answer in the
349 * answer parameter.
350 * @return EOK on success.
351 * @return ENOTSUP if the message is not known.
352 * @return Other error codes as defined for each specific module
353 * message function.
354 *
355 * @see IS_NET_NETIF_MESSAGE()
356 *
357 */
358int netif_module_message_standalone(const char *name, ipc_callid_t callid,
359 ipc_call_t *call, ipc_call_t *answer, int *answer_count)
360{
361 size_t length;
362 device_stats_t stats;
363 packet_t *packet;
364 measured_string_t address;
365 int rc;
366
367 *answer_count = 0;
368 switch (IPC_GET_IMETHOD(*call)) {
369 case IPC_M_PHONE_HUNGUP:
370 return EOK;
371
372 case NET_NETIF_PROBE:
373 return netif_probe_req_local(0, IPC_GET_DEVICE(call),
374 NETIF_GET_IRQ(call), NETIF_GET_IO(call));
375
376 case IPC_M_CONNECT_TO_ME:
377 fibril_rwlock_write_lock(&netif_globals.lock);
378 rc = register_message(name, IPC_GET_DEVICE(call),
379 IPC_GET_PHONE(call));
380 fibril_rwlock_write_unlock(&netif_globals.lock);
381 return rc;
382
383 case NET_NETIF_SEND:
384 rc = packet_translate_remote(netif_globals.net_phone, &packet,
385 IPC_GET_PACKET(call));
386 if (rc != EOK)
387 return rc;
388 return netif_send_msg_local(0, IPC_GET_DEVICE(call), packet,
389 IPC_GET_SENDER(call));
390
391 case NET_NETIF_START:
392 return netif_start_req_local(0, IPC_GET_DEVICE(call));
393
394 case NET_NETIF_STATS:
395 fibril_rwlock_read_lock(&netif_globals.lock);
396
397 rc = async_data_read_receive(&callid, &length);
398 if (rc != EOK) {
399 fibril_rwlock_read_unlock(&netif_globals.lock);
400 return rc;
401 }
402 if (length < sizeof(device_stats_t)) {
403 fibril_rwlock_read_unlock(&netif_globals.lock);
404 return EOVERFLOW;
405 }
406
407 rc = netif_get_device_stats(IPC_GET_DEVICE(call), &stats);
408 if (rc == EOK) {
409 rc = async_data_read_finalize(callid, &stats,
410 sizeof(device_stats_t));
411 }
412
413 fibril_rwlock_read_unlock(&netif_globals.lock);
414 return rc;
415
416 case NET_NETIF_STOP:
417 return netif_stop_req_local(0, IPC_GET_DEVICE(call));
418
419 case NET_NETIF_GET_ADDR:
420 fibril_rwlock_read_lock(&netif_globals.lock);
421 rc = netif_get_addr_message(IPC_GET_DEVICE(call), &address);
422 if (rc == EOK)
423 rc = measured_strings_reply(&address, 1);
424 fibril_rwlock_read_unlock(&netif_globals.lock);
425 return rc;
426 }
427
428 return netif_specific_message(callid, call, answer, answer_count);
429}
430
431/** Start the network interface module.
432 *
433 * Initialize the client connection serving function, initialize the module,
434 * registers the module service and start the async manager, processing IPC
435 * messages in an infinite loop.
436 *
437 * @param[in] client_connection The client connection processing function.
438 * The module skeleton propagates its own one.
439 * @return EOK on success.
440 * @return Other error codes as defined for each specific module
441 * message function.
442 */
443int netif_module_start_standalone(async_client_conn_t client_connection)
444{
445 int rc;
446
447 rc = netif_init_module(client_connection);
448 if (rc != EOK)
449 return rc;
450
451 async_manager();
452
453 pm_destroy();
454 return EOK;
455}
456
457/** @}
458 */
Note: See TracBrowser for help on using the repository browser.