source: mainline/uspace/lib/net/netif/netif_skel.c@ 79ae36dd

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

new async framework with integrated exchange tracking

  • strict isolation between low-level IPC and high-level async framework with integrated exchange tracking
    • each IPC connection is represented by an async_sess_t structure
    • each IPC exchange is represented by an async_exch_t structure
    • exchange management is either based on atomic messages (EXCHANGE_ATOMIC), locking (EXCHANGE_SERIALIZE) or connection cloning (EXCHANGE_CLONE)
  • async_obsolete: temporary compatibility layer to keep old async clients working (several pieces of code are currently broken, but only non-essential functionality)
  • IPC_M_PHONE_HANGUP is now method no. 0 (for elegant boolean evaluation)
  • IPC_M_DEBUG_ALL has been renamed to IPC_M_DEBUG
  • IPC_M_PING has been removed (VFS protocol now has VFS_IN_PING)
  • console routines in libc have been rewritten for better abstraction
  • additional use for libc-private header files (FILE structure opaque to the client)
  • various cstyle changes (typos, indentation, missing externs in header files, improved comments, etc.)
  • Property mode set to 100644
File size: 11.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 libnet
30 * @{
31 */
32
33/** @file
34 * Network interface module skeleton implementation.
35 * @see netif_skel.h
36 */
37
38#include <async.h>
39#include <mem.h>
40#include <fibril_synch.h>
41#include <stdio.h>
42#include <ipc/services.h>
43#include <ipc/netif.h>
44#include <errno.h>
45
46#include <generic.h>
47#include <net/modules.h>
48#include <net/packet.h>
49#include <packet_client.h>
50#include <packet_remote.h>
51#include <adt/measured_strings.h>
52#include <net/device.h>
53#include <netif_skel.h>
54#include <nil_remote.h>
55
56// FIXME: remove this header
57#include <kernel/ipc/ipc_methods.h>
58
59DEVICE_MAP_IMPLEMENT(netif_device_map, netif_device_t);
60
61/** Network interface global data. */
62netif_globals_t netif_globals;
63
64/** Probe the existence of the device.
65 *
66 * @param[in] netif_phone Network interface phone.
67 * @param[in] device_id Device identifier.
68 * @param[in] irq Device interrupt number.
69 * @param[in] io Device input/output address.
70 *
71 * @return EOK on success.
72 * @return Other error codes as defined for the
73 * netif_probe_message().
74 *
75 */
76static int netif_probe_req_local(int netif_phone, device_id_t device_id,
77 int irq, void *io)
78{
79 fibril_rwlock_write_lock(&netif_globals.lock);
80 int result = netif_probe_message(device_id, irq, io);
81 fibril_rwlock_write_unlock(&netif_globals.lock);
82
83 return result;
84}
85
86/** Send the packet queue.
87 *
88 * @param[in] netif_phone Network interface phone.
89 * @param[in] device_id Device identifier.
90 * @param[in] packet Packet queue.
91 * @param[in] sender Sending module service.
92 *
93 * @return EOK on success.
94 * @return Other error codes as defined for the generic_send_msg()
95 * function.
96 *
97 */
98static int netif_send_msg_local(int netif_phone, device_id_t device_id,
99 packet_t *packet, services_t sender)
100{
101 fibril_rwlock_write_lock(&netif_globals.lock);
102 int result = netif_send_message(device_id, packet, sender);
103 fibril_rwlock_write_unlock(&netif_globals.lock);
104
105 return result;
106}
107
108/** Start the device.
109 *
110 * @param[in] netif_phone Network interface phone.
111 * @param[in] device_id Device identifier.
112 *
113 * @return EOK on success.
114 * @return Other error codes as defined for the find_device()
115 * function.
116 * @return Other error codes as defined for the
117 * netif_start_message() function.
118 *
119 */
120static int netif_start_req_local(int netif_phone, device_id_t device_id)
121{
122 fibril_rwlock_write_lock(&netif_globals.lock);
123
124 netif_device_t *device;
125 int rc = find_device(device_id, &device);
126 if (rc != EOK) {
127 fibril_rwlock_write_unlock(&netif_globals.lock);
128 return rc;
129 }
130
131 int result = netif_start_message(device);
132 if (result > NETIF_NULL) {
133 int phone = device->nil_phone;
134 nil_device_state_msg(phone, device_id, result);
135 fibril_rwlock_write_unlock(&netif_globals.lock);
136 return EOK;
137 }
138
139 fibril_rwlock_write_unlock(&netif_globals.lock);
140
141 return result;
142}
143
144/** Stop the device.
145 *
146 * @param[in] netif_phone Network interface phone.
147 * @param[in] device_id Device identifier.
148 *
149 * @return EOK on success.
150 * @return Other error codes as defined for the find_device()
151 * function.
152 * @return Other error codes as defined for the
153 * netif_stop_message() function.
154 *
155 */
156static int netif_stop_req_local(int netif_phone, device_id_t device_id)
157{
158 fibril_rwlock_write_lock(&netif_globals.lock);
159
160 netif_device_t *device;
161 int rc = find_device(device_id, &device);
162 if (rc != EOK) {
163 fibril_rwlock_write_unlock(&netif_globals.lock);
164 return rc;
165 }
166
167 int result = netif_stop_message(device);
168 if (result > NETIF_NULL) {
169 int phone = device->nil_phone;
170 nil_device_state_msg(phone, device_id, result);
171 fibril_rwlock_write_unlock(&netif_globals.lock);
172 return EOK;
173 }
174
175 fibril_rwlock_write_unlock(&netif_globals.lock);
176
177 return result;
178}
179
180/** Find the device specific data.
181 *
182 * @param[in] device_id Device identifier.
183 * @param[out] device Device specific data.
184 *
185 * @return EOK on success.
186 * @return ENOENT if device is not found.
187 * @return EPERM if the device is not initialized.
188 *
189 */
190int find_device(device_id_t device_id, netif_device_t **device)
191{
192 if (!device)
193 return EBADMEM;
194
195 *device = netif_device_map_find(&netif_globals.device_map, device_id);
196 if (*device == NULL)
197 return ENOENT;
198
199 if ((*device)->state == NETIF_NULL)
200 return EPERM;
201
202 return EOK;
203}
204
205/** Clear the usage statistics.
206 *
207 * @param[in] stats The usage statistics.
208 *
209 */
210void null_device_stats(device_stats_t *stats)
211{
212 bzero(stats, sizeof(device_stats_t));
213}
214
215/** Release the given packet.
216 *
217 * Prepared for future optimization.
218 *
219 * @param[in] packet_id The packet identifier.
220 *
221 */
222void netif_pq_release(packet_id_t packet_id)
223{
224 pq_release_remote(netif_globals.net_phone, packet_id);
225}
226
227/** Allocate new packet to handle the given content size.
228 *
229 * @param[in] content Minimum content size.
230 *
231 * @return The allocated packet.
232 * @return NULL on error.
233 *
234 */
235packet_t *netif_packet_get_1(size_t content)
236{
237 return packet_get_1_remote(netif_globals.net_phone, content);
238}
239
240/** Register the device notification receiver,
241 *
242 * Register a network interface layer module as the device
243 * notification receiver.
244 *
245 * @param[in] device_id Device identifier.
246 * @param[in] phone Network interface layer module phone.
247 *
248 * @return EOK on success.
249 * @return ENOENT if there is no such device.
250 * @return ELIMIT if there is another module registered.
251 *
252 */
253static int register_message(device_id_t device_id, int phone)
254{
255 netif_device_t *device;
256 int rc = find_device(device_id, &device);
257 if (rc != EOK)
258 return rc;
259
260 if (device->nil_phone >= 0)
261 return ELIMIT;
262
263 device->nil_phone = phone;
264 return EOK;
265}
266
267/** Process the netif module messages.
268 *
269 * @param[in] callid Mmessage identifier.
270 * @param[in] call Message.
271 * @param[out] answer Answer.
272 * @param[out] count Number of arguments of the answer.
273 *
274 * @return EOK on success.
275 * @return ENOTSUP if the message is unknown.
276 * @return Other error codes as defined for each specific module
277 * message function.
278 *
279 * @see IS_NET_NETIF_MESSAGE()
280 *
281 */
282static int netif_module_message(ipc_callid_t callid, ipc_call_t *call,
283 ipc_call_t *answer, size_t *count)
284{
285 size_t length;
286 device_stats_t stats;
287 packet_t *packet;
288 measured_string_t address;
289 int rc;
290
291 *count = 0;
292
293 if (!IPC_GET_IMETHOD(*call))
294 return EOK;
295
296 switch (IPC_GET_IMETHOD(*call)) {
297 case NET_NETIF_PROBE:
298 return netif_probe_req_local(0, IPC_GET_DEVICE(*call),
299 NETIF_GET_IRQ(*call), NETIF_GET_IO(*call));
300
301 case IPC_M_CONNECT_TO_ME:
302 fibril_rwlock_write_lock(&netif_globals.lock);
303
304 rc = register_message(IPC_GET_DEVICE(*call), IPC_GET_PHONE(*call));
305
306 fibril_rwlock_write_unlock(&netif_globals.lock);
307 return rc;
308
309 case NET_NETIF_SEND:
310 rc = packet_translate_remote(netif_globals.net_phone, &packet,
311 IPC_GET_PACKET(*call));
312 if (rc != EOK)
313 return rc;
314
315 return netif_send_msg_local(0, IPC_GET_DEVICE(*call), packet,
316 IPC_GET_SENDER(*call));
317
318 case NET_NETIF_START:
319 return netif_start_req_local(0, IPC_GET_DEVICE(*call));
320
321 case NET_NETIF_STATS:
322 fibril_rwlock_read_lock(&netif_globals.lock);
323
324 rc = async_data_read_receive(&callid, &length);
325 if (rc != EOK) {
326 fibril_rwlock_read_unlock(&netif_globals.lock);
327 return rc;
328 }
329
330 if (length < sizeof(device_stats_t)) {
331 fibril_rwlock_read_unlock(&netif_globals.lock);
332 return EOVERFLOW;
333 }
334
335 rc = netif_get_device_stats(IPC_GET_DEVICE(*call), &stats);
336 if (rc == EOK) {
337 rc = async_data_read_finalize(callid, &stats,
338 sizeof(device_stats_t));
339 }
340
341 fibril_rwlock_read_unlock(&netif_globals.lock);
342 return rc;
343
344 case NET_NETIF_STOP:
345 return netif_stop_req_local(0, IPC_GET_DEVICE(*call));
346
347 case NET_NETIF_GET_ADDR:
348 fibril_rwlock_read_lock(&netif_globals.lock);
349
350 rc = netif_get_addr_message(IPC_GET_DEVICE(*call), &address);
351 if (rc == EOK)
352 rc = measured_strings_reply(&address, 1);
353
354 fibril_rwlock_read_unlock(&netif_globals.lock);
355 return rc;
356 }
357
358 return netif_specific_message(callid, call, answer, count);
359}
360
361/** Default fibril for new module connections.
362 *
363 * @param[in] iid Initial message identifier.
364 * @param[in] icall Initial message call structure.
365 *
366 */
367static void netif_client_connection(ipc_callid_t iid, ipc_call_t *icall)
368{
369 /*
370 * Accept the connection by answering
371 * the initial IPC_M_CONNECT_ME_TO call.
372 */
373 async_answer_0(iid, EOK);
374
375 while (true) {
376 ipc_call_t answer;
377 size_t count;
378
379 /* Clear the answer structure */
380 refresh_answer(&answer, &count);
381
382 /* Fetch the next message */
383 ipc_call_t call;
384 ipc_callid_t callid = async_get_call(&call);
385
386 /* Process the message */
387 int res = netif_module_message(callid, &call, &answer, &count);
388
389 /* End if said to either by the message or the processing result */
390 if ((!IPC_GET_IMETHOD(call)) || (res == EHANGUP))
391 return;
392
393 /* Answer the message */
394 answer_call(callid, res, &answer, count);
395 }
396}
397
398/** Start the network interface module.
399 *
400 * Initialize the client connection serving function, initialize the module,
401 * registers the module service and start the async manager, processing IPC
402 * messages in an infinite loop.
403 *
404 * @return EOK on success.
405 * @return Other error codes as defined for each specific module
406 * message function.
407 *
408 */
409int netif_module_start(void)
410{
411 async_set_client_connection(netif_client_connection);
412
413 netif_globals.net_phone = connect_to_service(SERVICE_NETWORKING);
414 netif_device_map_initialize(&netif_globals.device_map);
415
416 int rc = pm_init();
417 if (rc != EOK)
418 return rc;
419
420 fibril_rwlock_initialize(&netif_globals.lock);
421
422 rc = netif_initialize();
423 if (rc != EOK) {
424 pm_destroy();
425 return rc;
426 }
427
428 async_manager();
429
430 pm_destroy();
431 return EOK;
432}
433
434/** @}
435 */
Note: See TracBrowser for help on using the repository browser.