source: mainline/uspace/lib/drv/generic/remote_nic.c@ 8d7ec69d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8d7ec69d was 8d7ec69d, checked in by Jiri Svoboda <jiri@…>, 13 years ago

NIC should talk to its client via a callback connection with NIC-defined
protocol (was using nil, was connecting via NS).

  • Property mode set to 100644
File size: 31.9 KB
Line 
1/*
2 * Copyright (c) 2011 Radim Vansa
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 libdrv
30 * @{
31 */
32/**
33 * @file
34 * @brief Driver-side RPC skeletons for DDF NIC interface
35 */
36
37#include <assert.h>
38#include <async.h>
39#include <errno.h>
40#include <ipc/services.h>
41#include <sys/time.h>
42#include "ops/nic.h"
43
44static void remote_nic_send_frame(ddf_fun_t *dev, void *iface,
45 ipc_callid_t callid, ipc_call_t *call)
46{
47 nic_iface_t *nic_iface = (nic_iface_t *) iface;
48 assert(nic_iface->send_frame);
49
50 void *data;
51 size_t size;
52 int rc;
53
54 rc = async_data_write_accept(&data, false, 0, 0, 0, &size);
55 if (rc != EOK) {
56 async_answer_0(callid, EINVAL);
57 return;
58 }
59
60 rc = nic_iface->send_frame(dev, data, size);
61 async_answer_0(callid, rc);
62 free(data);
63}
64
65static void remote_nic_callback_create(ddf_fun_t *dev, void *iface,
66 ipc_callid_t callid, ipc_call_t *call)
67{
68 nic_iface_t *nic_iface = (nic_iface_t *) iface;
69 assert(nic_iface->callback_create);
70
71 nic_device_id_t device_id = (nic_device_id_t) IPC_GET_ARG2(*call);
72
73 int rc = nic_iface->callback_create(dev, device_id);
74 async_answer_0(callid, rc);
75}
76
77static void remote_nic_get_state(ddf_fun_t *dev, void *iface,
78 ipc_callid_t callid, ipc_call_t *call)
79{
80 nic_iface_t *nic_iface = (nic_iface_t *) iface;
81 assert(nic_iface->get_state);
82
83 nic_device_state_t state = NIC_STATE_MAX;
84
85 int rc = nic_iface->get_state(dev, &state);
86 async_answer_1(callid, rc, state);
87}
88
89static void remote_nic_set_state(ddf_fun_t *dev, void *iface,
90 ipc_callid_t callid, ipc_call_t *call)
91{
92 nic_iface_t *nic_iface = (nic_iface_t *) iface;
93 assert(nic_iface->set_state);
94
95 nic_device_state_t state = (nic_device_state_t) IPC_GET_ARG2(*call);
96
97 int rc = nic_iface->set_state(dev, state);
98 async_answer_0(callid, rc);
99}
100
101static void remote_nic_get_address(ddf_fun_t *dev, void *iface,
102 ipc_callid_t callid, ipc_call_t *call)
103{
104 nic_iface_t *nic_iface = (nic_iface_t *) iface;
105 assert(nic_iface->get_address);
106
107 nic_address_t address;
108 bzero(&address, sizeof(nic_address_t));
109
110 int rc = nic_iface->get_address(dev, &address);
111 if (rc == EOK) {
112 size_t max_len;
113 ipc_callid_t data_callid;
114
115 /* All errors will be translated into EPARTY anyway */
116 if (!async_data_read_receive(&data_callid, &max_len)) {
117 async_answer_0(data_callid, EINVAL);
118 async_answer_0(callid, EINVAL);
119 return;
120 }
121
122 if (max_len != sizeof(nic_address_t)) {
123 async_answer_0(data_callid, ELIMIT);
124 async_answer_0(callid, ELIMIT);
125 return;
126 }
127
128 async_data_read_finalize(data_callid, &address,
129 sizeof(nic_address_t));
130 }
131
132 async_answer_0(callid, rc);
133}
134
135static void remote_nic_set_address(ddf_fun_t *dev, void *iface,
136 ipc_callid_t callid, ipc_call_t *call)
137{
138 nic_iface_t *nic_iface = (nic_iface_t *) iface;
139
140 size_t length;
141 ipc_callid_t data_callid;
142 if (!async_data_write_receive(&data_callid, &length)) {
143 async_answer_0(data_callid, EINVAL);
144 async_answer_0(callid, EINVAL);
145 return;
146 }
147
148 if (length > sizeof(nic_address_t)) {
149 async_answer_0(data_callid, ELIMIT);
150 async_answer_0(callid, ELIMIT);
151 return;
152 }
153
154 nic_address_t address;
155 if (async_data_write_finalize(data_callid, &address, length) != EOK) {
156 async_answer_0(callid, EINVAL);
157 return;
158 }
159
160 if (nic_iface->set_address != NULL) {
161 int rc = nic_iface->set_address(dev, &address);
162 async_answer_0(callid, rc);
163 } else
164 async_answer_0(callid, ENOTSUP);
165}
166
167static void remote_nic_get_stats(ddf_fun_t *dev, void *iface,
168 ipc_callid_t callid, ipc_call_t *call)
169{
170 nic_iface_t *nic_iface = (nic_iface_t *) iface;
171 if (nic_iface->get_stats == NULL) {
172 async_answer_0(callid, ENOTSUP);
173 return;
174 }
175
176 nic_device_stats_t stats;
177 bzero(&stats, sizeof(nic_device_stats_t));
178
179 int rc = nic_iface->get_stats(dev, &stats);
180 if (rc == EOK) {
181 ipc_callid_t data_callid;
182 size_t max_len;
183 if (!async_data_read_receive(&data_callid, &max_len)) {
184 async_answer_0(data_callid, EINVAL);
185 async_answer_0(callid, EINVAL);
186 return;
187 }
188
189 if (max_len < sizeof(nic_device_stats_t)) {
190 async_answer_0(data_callid, ELIMIT);
191 async_answer_0(callid, ELIMIT);
192 return;
193 }
194
195 async_data_read_finalize(data_callid, &stats,
196 sizeof(nic_device_stats_t));
197 }
198
199 async_answer_0(callid, rc);
200}
201
202static void remote_nic_get_device_info(ddf_fun_t *dev, void *iface,
203 ipc_callid_t callid, ipc_call_t *call)
204{
205 nic_iface_t *nic_iface = (nic_iface_t *) iface;
206 if (nic_iface->get_device_info == NULL) {
207 async_answer_0(callid, ENOTSUP);
208 return;
209 }
210
211 nic_device_info_t info;
212 bzero(&info, sizeof(nic_device_info_t));
213
214 int rc = nic_iface->get_device_info(dev, &info);
215 if (rc == EOK) {
216 ipc_callid_t data_callid;
217 size_t max_len;
218 if (!async_data_read_receive(&data_callid, &max_len)) {
219 async_answer_0(data_callid, EINVAL);
220 async_answer_0(callid, EINVAL);
221 return;
222 }
223
224 if (max_len < sizeof (nic_device_info_t)) {
225 async_answer_0(data_callid, ELIMIT);
226 async_answer_0(callid, ELIMIT);
227 return;
228 }
229
230 async_data_read_finalize(data_callid, &info,
231 sizeof(nic_device_info_t));
232 }
233
234 async_answer_0(callid, rc);
235}
236
237static void remote_nic_get_cable_state(ddf_fun_t *dev, void *iface,
238 ipc_callid_t callid, ipc_call_t *call)
239{
240 nic_iface_t *nic_iface = (nic_iface_t *) iface;
241 if (nic_iface->get_cable_state == NULL) {
242 async_answer_0(callid, ENOTSUP);
243 return;
244 }
245
246 nic_cable_state_t cs = NIC_CS_UNKNOWN;
247
248 int rc = nic_iface->get_cable_state(dev, &cs);
249 async_answer_1(callid, rc, (sysarg_t) cs);
250}
251
252static void remote_nic_get_operation_mode(ddf_fun_t *dev, void *iface,
253 ipc_callid_t callid, ipc_call_t *call)
254{
255 nic_iface_t *nic_iface = (nic_iface_t *) iface;
256 if (nic_iface->get_operation_mode == NULL) {
257 async_answer_0(callid, ENOTSUP);
258 return;
259 }
260
261 int speed = 0;
262 nic_channel_mode_t duplex = NIC_CM_UNKNOWN;
263 nic_role_t role = NIC_ROLE_UNKNOWN;
264
265 int rc = nic_iface->get_operation_mode(dev, &speed, &duplex, &role);
266 async_answer_3(callid, rc, (sysarg_t) speed, (sysarg_t) duplex,
267 (sysarg_t) role);
268}
269
270static void remote_nic_set_operation_mode(ddf_fun_t *dev, void *iface,
271 ipc_callid_t callid, ipc_call_t *call)
272{
273 nic_iface_t *nic_iface = (nic_iface_t *) iface;
274 if (nic_iface->set_operation_mode == NULL) {
275 async_answer_0(callid, ENOTSUP);
276 return;
277 }
278
279 int speed = (int) IPC_GET_ARG2(*call);
280 nic_channel_mode_t duplex = (nic_channel_mode_t) IPC_GET_ARG3(*call);
281 nic_role_t role = (nic_role_t) IPC_GET_ARG4(*call);
282
283 int rc = nic_iface->set_operation_mode(dev, speed, duplex, role);
284 async_answer_0(callid, rc);
285}
286
287static void remote_nic_autoneg_enable(ddf_fun_t *dev, void *iface,
288 ipc_callid_t callid, ipc_call_t *call)
289{
290 nic_iface_t *nic_iface = (nic_iface_t *) iface;
291 if (nic_iface->autoneg_enable == NULL) {
292 async_answer_0(callid, ENOTSUP);
293 return;
294 }
295
296 uint32_t advertisement = (uint32_t) IPC_GET_ARG2(*call);
297
298 int rc = nic_iface->autoneg_enable(dev, advertisement);
299 async_answer_0(callid, rc);
300}
301
302static void remote_nic_autoneg_disable(ddf_fun_t *dev, void *iface,
303 ipc_callid_t callid, ipc_call_t *call)
304{
305 nic_iface_t *nic_iface = (nic_iface_t *) iface;
306 if (nic_iface->autoneg_disable == NULL) {
307 async_answer_0(callid, ENOTSUP);
308 return;
309 }
310
311 int rc = nic_iface->autoneg_disable(dev);
312 async_answer_0(callid, rc);
313}
314
315static void remote_nic_autoneg_probe(ddf_fun_t *dev, void *iface,
316 ipc_callid_t callid, ipc_call_t *call)
317{
318 nic_iface_t *nic_iface = (nic_iface_t *) iface;
319 if (nic_iface->autoneg_probe == NULL) {
320 async_answer_0(callid, ENOTSUP);
321 return;
322 }
323
324 uint32_t our_adv = 0;
325 uint32_t their_adv = 0;
326 nic_result_t result = NIC_RESULT_NOT_AVAILABLE;
327 nic_result_t their_result = NIC_RESULT_NOT_AVAILABLE;
328
329 int rc = nic_iface->autoneg_probe(dev, &our_adv, &their_adv, &result,
330 &their_result);
331 async_answer_4(callid, rc, our_adv, their_adv, (sysarg_t) result,
332 (sysarg_t) their_result);
333}
334
335static void remote_nic_autoneg_restart(ddf_fun_t *dev, void *iface,
336 ipc_callid_t callid, ipc_call_t *call)
337{
338 nic_iface_t *nic_iface = (nic_iface_t *) iface;
339 if (nic_iface->autoneg_restart == NULL) {
340 async_answer_0(callid, ENOTSUP);
341 return;
342 }
343
344 int rc = nic_iface->autoneg_restart(dev);
345 async_answer_0(callid, rc);
346}
347
348static void remote_nic_get_pause(ddf_fun_t *dev, void *iface,
349 ipc_callid_t callid, ipc_call_t *call)
350{
351 nic_iface_t *nic_iface = (nic_iface_t *) iface;
352 if (nic_iface->get_pause == NULL) {
353 async_answer_0(callid, ENOTSUP);
354 return;
355 }
356
357 nic_result_t we_send;
358 nic_result_t we_receive;
359 uint16_t pause;
360
361 int rc = nic_iface->get_pause(dev, &we_send, &we_receive, &pause);
362 async_answer_3(callid, rc, we_send, we_receive, pause);
363}
364
365static void remote_nic_set_pause(ddf_fun_t *dev, void *iface,
366 ipc_callid_t callid, ipc_call_t *call)
367{
368 nic_iface_t *nic_iface = (nic_iface_t *) iface;
369 if (nic_iface->set_pause == NULL) {
370 async_answer_0(callid, ENOTSUP);
371 return;
372 }
373
374 int allow_send = (int) IPC_GET_ARG2(*call);
375 int allow_receive = (int) IPC_GET_ARG3(*call);
376 uint16_t pause = (uint16_t) IPC_GET_ARG4(*call);
377
378 int rc = nic_iface->set_pause(dev, allow_send, allow_receive,
379 pause);
380 async_answer_0(callid, rc);
381}
382
383static void remote_nic_unicast_get_mode(ddf_fun_t *dev, void *iface,
384 ipc_callid_t callid, ipc_call_t *call)
385{
386 nic_iface_t *nic_iface = (nic_iface_t *) iface;
387 if (nic_iface->unicast_get_mode == NULL) {
388 async_answer_0(callid, ENOTSUP);
389 return;
390 }
391
392 size_t max_count = IPC_GET_ARG2(*call);
393 nic_address_t *address_list = NULL;
394
395 if (max_count != 0) {
396 address_list = malloc(max_count * sizeof (nic_address_t));
397 if (!address_list) {
398 async_answer_0(callid, ENOMEM);
399 return;
400 }
401 }
402
403 bzero(address_list, max_count * sizeof(nic_address_t));
404 nic_unicast_mode_t mode = NIC_UNICAST_DEFAULT;
405 size_t address_count = 0;
406
407 int rc = nic_iface->unicast_get_mode(dev, &mode, max_count, address_list,
408 &address_count);
409
410 if ((rc != EOK) || (max_count == 0) || (address_count == 0)) {
411 free(address_list);
412 async_answer_2(callid, rc, mode, address_count);
413 return;
414 }
415
416 ipc_callid_t data_callid;
417 size_t max_len;
418 if (!async_data_read_receive(&data_callid, &max_len)) {
419 async_answer_0(data_callid, EINVAL);
420 async_answer_2(callid, rc, mode, address_count);
421 free(address_list);
422 return;
423 }
424
425 if (max_len > address_count * sizeof(nic_address_t))
426 max_len = address_count * sizeof(nic_address_t);
427
428 if (max_len > max_count * sizeof(nic_address_t))
429 max_len = max_count * sizeof(nic_address_t);
430
431 async_data_read_finalize(data_callid, address_list, max_len);
432 async_answer_0(data_callid, EINVAL);
433
434 free(address_list);
435 async_answer_2(callid, rc, mode, address_count);
436}
437
438static void remote_nic_unicast_set_mode(ddf_fun_t *dev, void *iface,
439 ipc_callid_t callid, ipc_call_t *call)
440{
441 nic_iface_t *nic_iface = (nic_iface_t *) iface;
442
443 size_t length;
444 nic_unicast_mode_t mode = IPC_GET_ARG2(*call);
445 size_t address_count = IPC_GET_ARG3(*call);
446 nic_address_t *address_list = NULL;
447
448 if (address_count) {
449 ipc_callid_t data_callid;
450 if (!async_data_write_receive(&data_callid, &length)) {
451 async_answer_0(data_callid, EINVAL);
452 async_answer_0(callid, EINVAL);
453 return;
454 }
455
456 if (length != address_count * sizeof(nic_address_t)) {
457 async_answer_0(data_callid, ELIMIT);
458 async_answer_0(callid, ELIMIT);
459 return;
460 }
461
462 address_list = malloc(length);
463 if (address_list == NULL) {
464 async_answer_0(data_callid, ENOMEM);
465 async_answer_0(callid, ENOMEM);
466 return;
467 }
468
469 if (async_data_write_finalize(data_callid, address_list,
470 length) != EOK) {
471 async_answer_0(callid, EINVAL);
472 free(address_list);
473 return;
474 }
475 }
476
477 if (nic_iface->unicast_set_mode != NULL) {
478 int rc = nic_iface->unicast_set_mode(dev, mode, address_list,
479 address_count);
480 async_answer_0(callid, rc);
481 } else
482 async_answer_0(callid, ENOTSUP);
483
484 free(address_list);
485}
486
487static void remote_nic_multicast_get_mode(ddf_fun_t *dev, void *iface,
488 ipc_callid_t callid, ipc_call_t *call)
489{
490 nic_iface_t *nic_iface = (nic_iface_t *) iface;
491 if (nic_iface->multicast_get_mode == NULL) {
492 async_answer_0(callid, ENOTSUP);
493 return;
494 }
495
496 size_t max_count = IPC_GET_ARG2(*call);
497 nic_address_t *address_list = NULL;
498
499 if (max_count != 0) {
500 address_list = malloc(max_count * sizeof(nic_address_t));
501 if (!address_list) {
502 async_answer_0(callid, ENOMEM);
503 return;
504 }
505 }
506
507 bzero(address_list, max_count * sizeof(nic_address_t));
508 nic_multicast_mode_t mode = NIC_MULTICAST_BLOCKED;
509 size_t address_count = 0;
510
511 int rc = nic_iface->multicast_get_mode(dev, &mode, max_count, address_list,
512 &address_count);
513
514
515 if ((rc != EOK) || (max_count == 0) || (address_count == 0)) {
516 free(address_list);
517 async_answer_2(callid, rc, mode, address_count);
518 return;
519 }
520
521 ipc_callid_t data_callid;
522 size_t max_len;
523 if (!async_data_read_receive(&data_callid, &max_len)) {
524 async_answer_0(data_callid, EINVAL);
525 async_answer_2(callid, rc, mode, address_count);
526 free(address_list);
527 return;
528 }
529
530 if (max_len > address_count * sizeof(nic_address_t))
531 max_len = address_count * sizeof(nic_address_t);
532
533 if (max_len > max_count * sizeof(nic_address_t))
534 max_len = max_count * sizeof(nic_address_t);
535
536 async_data_read_finalize(data_callid, address_list, max_len);
537
538 free(address_list);
539 async_answer_2(callid, rc, mode, address_count);
540}
541
542static void remote_nic_multicast_set_mode(ddf_fun_t *dev, void *iface,
543 ipc_callid_t callid, ipc_call_t *call)
544{
545 nic_iface_t *nic_iface = (nic_iface_t *) iface;
546
547 nic_multicast_mode_t mode = IPC_GET_ARG2(*call);
548 size_t address_count = IPC_GET_ARG3(*call);
549 nic_address_t *address_list = NULL;
550
551 if (address_count) {
552 ipc_callid_t data_callid;
553 size_t length;
554 if (!async_data_write_receive(&data_callid, &length)) {
555 async_answer_0(data_callid, EINVAL);
556 async_answer_0(callid, EINVAL);
557 return;
558 }
559
560 if (length != address_count * sizeof (nic_address_t)) {
561 async_answer_0(data_callid, ELIMIT);
562 async_answer_0(callid, ELIMIT);
563 return;
564 }
565
566 address_list = malloc(length);
567 if (address_list == NULL) {
568 async_answer_0(data_callid, ENOMEM);
569 async_answer_0(callid, ENOMEM);
570 return;
571 }
572
573 if (async_data_write_finalize(data_callid, address_list,
574 length) != EOK) {
575 async_answer_0(callid, EINVAL);
576 free(address_list);
577 return;
578 }
579 }
580
581 if (nic_iface->multicast_set_mode != NULL) {
582 int rc = nic_iface->multicast_set_mode(dev, mode, address_list,
583 address_count);
584 async_answer_0(callid, rc);
585 } else
586 async_answer_0(callid, ENOTSUP);
587
588 free(address_list);
589}
590
591static void remote_nic_broadcast_get_mode(ddf_fun_t *dev, void *iface,
592 ipc_callid_t callid, ipc_call_t *call)
593{
594 nic_iface_t *nic_iface = (nic_iface_t *) iface;
595 if (nic_iface->broadcast_get_mode == NULL) {
596 async_answer_0(callid, ENOTSUP);
597 return;
598 }
599
600 nic_broadcast_mode_t mode = NIC_BROADCAST_ACCEPTED;
601
602 int rc = nic_iface->broadcast_get_mode(dev, &mode);
603 async_answer_1(callid, rc, mode);
604}
605
606static void remote_nic_broadcast_set_mode(ddf_fun_t *dev, void *iface,
607 ipc_callid_t callid, ipc_call_t *call)
608{
609 nic_iface_t *nic_iface = (nic_iface_t *) iface;
610 if (nic_iface->broadcast_set_mode == NULL) {
611 async_answer_0(callid, ENOTSUP);
612 return;
613 }
614
615 nic_broadcast_mode_t mode = IPC_GET_ARG2(*call);
616
617 int rc = nic_iface->broadcast_set_mode(dev, mode);
618 async_answer_0(callid, rc);
619}
620
621static void remote_nic_defective_get_mode(ddf_fun_t *dev, void *iface,
622 ipc_callid_t callid, ipc_call_t *call)
623{
624 nic_iface_t *nic_iface = (nic_iface_t *) iface;
625 if (nic_iface->defective_get_mode == NULL) {
626 async_answer_0(callid, ENOTSUP);
627 return;
628 }
629
630 uint32_t mode = 0;
631
632 int rc = nic_iface->defective_get_mode(dev, &mode);
633 async_answer_1(callid, rc, mode);
634}
635
636static void remote_nic_defective_set_mode(ddf_fun_t *dev, void *iface,
637 ipc_callid_t callid, ipc_call_t *call)
638{
639 nic_iface_t *nic_iface = (nic_iface_t *) iface;
640 if (nic_iface->defective_set_mode == NULL) {
641 async_answer_0(callid, ENOTSUP);
642 return;
643 }
644
645 uint32_t mode = IPC_GET_ARG2(*call);
646
647 int rc = nic_iface->defective_set_mode(dev, mode);
648 async_answer_0(callid, rc);
649}
650
651static void remote_nic_blocked_sources_get(ddf_fun_t *dev, void *iface,
652 ipc_callid_t callid, ipc_call_t *call)
653{
654 nic_iface_t *nic_iface = (nic_iface_t *) iface;
655 if (nic_iface->blocked_sources_get == NULL) {
656 async_answer_0(callid, ENOTSUP);
657 return;
658 }
659
660 size_t max_count = IPC_GET_ARG2(*call);
661 nic_address_t *address_list = NULL;
662
663 if (max_count != 0) {
664 address_list = malloc(max_count * sizeof(nic_address_t));
665 if (!address_list) {
666 async_answer_0(callid, ENOMEM);
667 return;
668 }
669 }
670
671 bzero(address_list, max_count * sizeof(nic_address_t));
672 size_t address_count = 0;
673
674 int rc = nic_iface->blocked_sources_get(dev, max_count, address_list,
675 &address_count);
676
677 if ((rc != EOK) || (max_count == 0) || (address_count == 0)) {
678 async_answer_1(callid, rc, address_count);
679 free(address_list);
680 return;
681 }
682
683 ipc_callid_t data_callid;
684 size_t max_len;
685 if (!async_data_read_receive(&data_callid, &max_len)) {
686 async_answer_0(data_callid, EINVAL);
687 async_answer_1(callid, rc, address_count);
688 free(address_list);
689 return;
690 }
691
692 if (max_len > address_count * sizeof(nic_address_t))
693 max_len = address_count * sizeof(nic_address_t);
694
695 if (max_len > max_count * sizeof(nic_address_t))
696 max_len = max_count * sizeof(nic_address_t);
697
698 async_data_read_finalize(data_callid, address_list, max_len);
699 async_answer_0(data_callid, EINVAL);
700
701 free(address_list);
702 async_answer_1(callid, rc, address_count);
703}
704
705static void remote_nic_blocked_sources_set(ddf_fun_t *dev, void *iface,
706 ipc_callid_t callid, ipc_call_t *call)
707{
708 nic_iface_t *nic_iface = (nic_iface_t *) iface;
709
710 size_t length;
711 size_t address_count = IPC_GET_ARG2(*call);
712 nic_address_t *address_list = NULL;
713
714 if (address_count) {
715 ipc_callid_t data_callid;
716 if (!async_data_write_receive(&data_callid, &length)) {
717 async_answer_0(data_callid, EINVAL);
718 async_answer_0(callid, EINVAL);
719 return;
720 }
721
722 if (length != address_count * sizeof(nic_address_t)) {
723 async_answer_0(data_callid, ELIMIT);
724 async_answer_0(callid, ELIMIT);
725 return;
726 }
727
728 address_list = malloc(length);
729 if (address_list == NULL) {
730 async_answer_0(data_callid, ENOMEM);
731 async_answer_0(callid, ENOMEM);
732 return;
733 }
734
735 if (async_data_write_finalize(data_callid, address_list,
736 length) != EOK) {
737 async_answer_0(callid, EINVAL);
738 free(address_list);
739 return;
740 }
741 }
742
743 if (nic_iface->blocked_sources_set != NULL) {
744 int rc = nic_iface->blocked_sources_set(dev, address_list,
745 address_count);
746 async_answer_0(callid, rc);
747 } else
748 async_answer_0(callid, ENOTSUP);
749
750 free(address_list);
751}
752
753static void remote_nic_vlan_get_mask(ddf_fun_t *dev, void *iface,
754 ipc_callid_t callid, ipc_call_t *call)
755{
756 nic_iface_t *nic_iface = (nic_iface_t *) iface;
757 if (nic_iface->vlan_get_mask == NULL) {
758 async_answer_0(callid, ENOTSUP);
759 return;
760 }
761
762 nic_vlan_mask_t vlan_mask;
763 bzero(&vlan_mask, sizeof(nic_vlan_mask_t));
764
765 int rc = nic_iface->vlan_get_mask(dev, &vlan_mask);
766 if (rc == EOK) {
767 ipc_callid_t data_callid;
768 size_t max_len;
769 if (!async_data_read_receive(&data_callid, &max_len)) {
770 async_answer_0(data_callid, EINVAL);
771 async_answer_0(callid, EINVAL);
772 return;
773 }
774
775 if (max_len != sizeof(nic_vlan_mask_t)) {
776 async_answer_0(data_callid, EINVAL);
777 async_answer_0(callid, EINVAL);
778 return;
779 }
780
781 async_data_read_finalize(data_callid, &vlan_mask, max_len);
782 }
783
784 async_answer_0(callid, rc);
785}
786
787static void remote_nic_vlan_set_mask(ddf_fun_t *dev, void *iface,
788 ipc_callid_t callid, ipc_call_t *call)
789{
790 nic_iface_t *nic_iface = (nic_iface_t *) iface;
791
792 nic_vlan_mask_t vlan_mask;
793 nic_vlan_mask_t *vlan_mask_pointer = NULL;
794 bool vlan_mask_set = (bool) IPC_GET_ARG2(*call);
795
796 if (vlan_mask_set) {
797 ipc_callid_t data_callid;
798 size_t length;
799 if (!async_data_write_receive(&data_callid, &length)) {
800 async_answer_0(data_callid, EINVAL);
801 async_answer_0(callid, EINVAL);
802 return;
803 }
804
805 if (length != sizeof(nic_vlan_mask_t)) {
806 async_answer_0(data_callid, ELIMIT);
807 async_answer_0(callid, ELIMIT);
808 return;
809 }
810
811 if (async_data_write_finalize(data_callid, &vlan_mask,
812 length) != EOK) {
813 async_answer_0(callid, EINVAL);
814 return;
815 }
816
817 vlan_mask_pointer = &vlan_mask;
818 }
819
820 if (nic_iface->vlan_set_mask != NULL) {
821 int rc = nic_iface->vlan_set_mask(dev, vlan_mask_pointer);
822 async_answer_0(callid, rc);
823 } else
824 async_answer_0(callid, ENOTSUP);
825}
826
827static void remote_nic_vlan_set_tag(ddf_fun_t *dev, void *iface,
828 ipc_callid_t callid, ipc_call_t *call)
829{
830 nic_iface_t *nic_iface = (nic_iface_t *) iface;
831
832 if (nic_iface->vlan_set_tag == NULL) {
833 async_answer_0(callid, ENOTSUP);
834 return;
835 }
836
837 uint16_t tag = (uint16_t) IPC_GET_ARG2(*call);
838 bool add = (int) IPC_GET_ARG3(*call);
839 bool strip = (int) IPC_GET_ARG4(*call);
840
841 int rc = nic_iface->vlan_set_tag(dev, tag, add, strip);
842 async_answer_0(callid, rc);
843}
844
845static void remote_nic_wol_virtue_add(ddf_fun_t *dev, void *iface,
846 ipc_callid_t callid, ipc_call_t *call)
847{
848 nic_iface_t *nic_iface = (nic_iface_t *) iface;
849
850 int send_data = (int) IPC_GET_ARG3(*call);
851 ipc_callid_t data_callid;
852
853 if (nic_iface->wol_virtue_add == NULL) {
854 if (send_data) {
855 async_data_write_receive(&data_callid, NULL);
856 async_answer_0(data_callid, ENOTSUP);
857 }
858
859 async_answer_0(callid, ENOTSUP);
860 }
861
862 size_t length = 0;
863 void *data = NULL;
864
865 if (send_data) {
866 if (!async_data_write_receive(&data_callid, &length)) {
867 async_answer_0(data_callid, EINVAL);
868 async_answer_0(callid, EINVAL);
869 return;
870 }
871
872 data = malloc(length);
873 if (data == NULL) {
874 async_answer_0(data_callid, ENOMEM);
875 async_answer_0(callid, ENOMEM);
876 return;
877 }
878
879 if (async_data_write_finalize(data_callid, data,
880 length) != EOK) {
881 async_answer_0(callid, EINVAL);
882 free(data);
883 return;
884 }
885 }
886
887 nic_wv_id_t id = 0;
888 nic_wv_type_t type = (nic_wv_type_t) IPC_GET_ARG2(*call);
889
890 int rc = nic_iface->wol_virtue_add(dev, type, data, length, &id);
891 async_answer_1(callid, rc, (sysarg_t) id);
892 free(data);
893}
894
895static void remote_nic_wol_virtue_remove(ddf_fun_t *dev, void *iface,
896 ipc_callid_t callid, ipc_call_t *call)
897{
898 nic_iface_t *nic_iface = (nic_iface_t *) iface;
899
900 if (nic_iface->wol_virtue_remove == NULL) {
901 async_answer_0(callid, ENOTSUP);
902 return;
903 }
904
905 nic_wv_id_t id = (nic_wv_id_t) IPC_GET_ARG2(*call);
906
907 int rc = nic_iface->wol_virtue_remove(dev, id);
908 async_answer_0(callid, rc);
909}
910
911static void remote_nic_wol_virtue_probe(ddf_fun_t *dev, void *iface,
912 ipc_callid_t callid, ipc_call_t *call)
913{
914 nic_iface_t *nic_iface = (nic_iface_t *) iface;
915
916 if (nic_iface->wol_virtue_probe == NULL) {
917 async_answer_0(callid, ENOTSUP);
918 return;
919 }
920
921 nic_wv_id_t id = (nic_wv_id_t) IPC_GET_ARG2(*call);
922 size_t max_length = IPC_GET_ARG3(*call);
923 nic_wv_type_t type = NIC_WV_NONE;
924 size_t length = 0;
925 ipc_callid_t data_callid;
926 void *data = NULL;
927
928 if (max_length != 0) {
929 data = malloc(max_length);
930 if (data == NULL) {
931 async_answer_0(callid, ENOMEM);
932 return;
933 }
934 }
935
936 bzero(data, max_length);
937
938 int rc = nic_iface->wol_virtue_probe(dev, id, &type, max_length,
939 data, &length);
940
941 if ((max_length != 0) && (length != 0)) {
942 size_t req_length;
943 if (!async_data_read_receive(&data_callid, &req_length)) {
944 async_answer_0(data_callid, EINVAL);
945 async_answer_0(callid, EINVAL);
946 free(data);
947 return;
948 }
949
950 if (req_length > length)
951 req_length = length;
952
953 if (req_length > max_length)
954 req_length = max_length;
955
956 async_data_read_finalize(data_callid, data, req_length);
957 }
958
959 async_answer_2(callid, rc, (sysarg_t) type, (sysarg_t) length);
960 free(data);
961}
962
963static void remote_nic_wol_virtue_list(ddf_fun_t *dev, void *iface,
964 ipc_callid_t callid, ipc_call_t *call)
965{
966 nic_iface_t *nic_iface = (nic_iface_t *) iface;
967 if (nic_iface->wol_virtue_list == NULL) {
968 async_answer_0(callid, ENOTSUP);
969 return;
970 }
971
972 nic_wv_type_t type = (nic_wv_type_t) IPC_GET_ARG2(*call);
973 size_t max_count = IPC_GET_ARG3(*call);
974 size_t count = 0;
975 nic_wv_id_t *id_list = NULL;
976 ipc_callid_t data_callid;
977
978 if (max_count != 0) {
979 id_list = malloc(max_count * sizeof(nic_wv_id_t));
980 if (id_list == NULL) {
981 async_answer_0(callid, ENOMEM);
982 return;
983 }
984 }
985
986 bzero(id_list, max_count * sizeof (nic_wv_id_t));
987
988 int rc = nic_iface->wol_virtue_list(dev, type, max_count, id_list,
989 &count);
990
991 if ((max_count != 0) && (count != 0)) {
992 size_t req_length;
993 if (!async_data_read_receive(&data_callid, &req_length)) {
994 async_answer_0(data_callid, EINVAL);
995 async_answer_0(callid, EINVAL);
996 free(id_list);
997 return;
998 }
999
1000 if (req_length > count * sizeof(nic_wv_id_t))
1001 req_length = count * sizeof(nic_wv_id_t);
1002
1003 if (req_length > max_count * sizeof(nic_wv_id_t))
1004 req_length = max_count * sizeof(nic_wv_id_t);
1005
1006 rc = async_data_read_finalize(data_callid, id_list, req_length);
1007 }
1008
1009 async_answer_1(callid, rc, (sysarg_t) count);
1010 free(id_list);
1011}
1012
1013static void remote_nic_wol_virtue_get_caps(ddf_fun_t *dev, void *iface,
1014 ipc_callid_t callid, ipc_call_t *call)
1015{
1016 nic_iface_t *nic_iface = (nic_iface_t *) iface;
1017 if (nic_iface->wol_virtue_get_caps == NULL) {
1018 async_answer_0(callid, ENOTSUP);
1019 return;
1020 }
1021
1022 int count = -1;
1023 nic_wv_type_t type = (nic_wv_type_t) IPC_GET_ARG2(*call);
1024
1025 int rc = nic_iface->wol_virtue_get_caps(dev, type, &count);
1026 async_answer_1(callid, rc, (sysarg_t) count);
1027}
1028
1029static void remote_nic_wol_load_info(ddf_fun_t *dev, void *iface,
1030 ipc_callid_t callid, ipc_call_t *call)
1031{
1032 nic_iface_t *nic_iface = (nic_iface_t *) iface;
1033 if (nic_iface->wol_load_info == NULL) {
1034 async_answer_0(callid, ENOTSUP);
1035 return;
1036 }
1037
1038 size_t max_length = (size_t) IPC_GET_ARG2(*call);
1039 size_t frame_length = 0;
1040 nic_wv_type_t type = NIC_WV_NONE;
1041 uint8_t *data = NULL;
1042
1043 if (max_length != 0) {
1044 data = malloc(max_length);
1045 if (data == NULL) {
1046 async_answer_0(callid, ENOMEM);
1047 return;
1048 }
1049 }
1050
1051 bzero(data, max_length);
1052
1053 int rc = nic_iface->wol_load_info(dev, &type, max_length, data,
1054 &frame_length);
1055 if (rc == EOK) {
1056 ipc_callid_t data_callid;
1057 size_t req_length;
1058 if (!async_data_read_receive(&data_callid, &req_length)) {
1059 async_answer_0(data_callid, EINVAL);
1060 async_answer_0(callid, EINVAL);
1061 free(data);
1062 return;
1063 }
1064
1065 req_length = req_length > max_length ? max_length : req_length;
1066 req_length = req_length > frame_length ? frame_length : req_length;
1067 async_data_read_finalize(data_callid, data, req_length);
1068 }
1069
1070 async_answer_2(callid, rc, (sysarg_t) type, (sysarg_t) frame_length);
1071 free(data);
1072}
1073
1074static void remote_nic_offload_probe(ddf_fun_t *dev, void *iface,
1075 ipc_callid_t callid, ipc_call_t *call)
1076{
1077 nic_iface_t *nic_iface = (nic_iface_t *) iface;
1078 if (nic_iface->offload_probe == NULL) {
1079 async_answer_0(callid, ENOTSUP);
1080 return;
1081 }
1082
1083 uint32_t supported = 0;
1084 uint32_t active = 0;
1085
1086 int rc = nic_iface->offload_probe(dev, &supported, &active);
1087 async_answer_2(callid, rc, supported, active);
1088}
1089
1090static void remote_nic_offload_set(ddf_fun_t *dev, void *iface,
1091 ipc_callid_t callid, ipc_call_t *call)
1092{
1093 nic_iface_t *nic_iface = (nic_iface_t *) iface;
1094 if (nic_iface->offload_set == NULL) {
1095 async_answer_0(callid, ENOTSUP);
1096 return;
1097 }
1098
1099 uint32_t mask = (uint32_t) IPC_GET_ARG2(*call);
1100 uint32_t active = (uint32_t) IPC_GET_ARG3(*call);
1101
1102 int rc = nic_iface->offload_set(dev, mask, active);
1103 async_answer_0(callid, rc);
1104}
1105
1106static void remote_nic_poll_get_mode(ddf_fun_t *dev, void *iface,
1107 ipc_callid_t callid, ipc_call_t *call)
1108{
1109 nic_iface_t *nic_iface = (nic_iface_t *) iface;
1110 if (nic_iface->poll_get_mode == NULL) {
1111 async_answer_0(callid, ENOTSUP);
1112 return;
1113 }
1114
1115 nic_poll_mode_t mode = NIC_POLL_IMMEDIATE;
1116 int request_data = IPC_GET_ARG2(*call);
1117 struct timeval period = {
1118 .tv_sec = 0,
1119 .tv_usec = 0
1120 };
1121
1122 int rc = nic_iface->poll_get_mode(dev, &mode, &period);
1123 if ((rc == EOK) && (request_data)) {
1124 size_t max_len;
1125 ipc_callid_t data_callid;
1126
1127 if (!async_data_read_receive(&data_callid, &max_len)) {
1128 async_answer_0(data_callid, EINVAL);
1129 async_answer_0(callid, EINVAL);
1130 return;
1131 }
1132
1133 if (max_len != sizeof(struct timeval)) {
1134 async_answer_0(data_callid, ELIMIT);
1135 async_answer_0(callid, ELIMIT);
1136 return;
1137 }
1138
1139 async_data_read_finalize(data_callid, &period,
1140 sizeof(struct timeval));
1141 }
1142
1143 async_answer_1(callid, rc, (sysarg_t) mode);
1144}
1145
1146static void remote_nic_poll_set_mode(ddf_fun_t *dev, void *iface,
1147 ipc_callid_t callid, ipc_call_t *call)
1148{
1149 nic_iface_t *nic_iface = (nic_iface_t *) iface;
1150
1151 nic_poll_mode_t mode = IPC_GET_ARG2(*call);
1152 int has_period = IPC_GET_ARG3(*call);
1153 struct timeval period_buf;
1154 struct timeval *period = NULL;
1155 size_t length;
1156
1157 if (has_period) {
1158 ipc_callid_t data_callid;
1159 if (!async_data_write_receive(&data_callid, &length)) {
1160 async_answer_0(data_callid, EINVAL);
1161 async_answer_0(callid, EINVAL);
1162 return;
1163 }
1164
1165 if (length != sizeof(struct timeval)) {
1166 async_answer_0(data_callid, ELIMIT);
1167 async_answer_0(callid, ELIMIT);
1168 return;
1169 }
1170
1171 period = &period_buf;
1172 if (async_data_write_finalize(data_callid, period,
1173 length) != EOK) {
1174 async_answer_0(callid, EINVAL);
1175 return;
1176 }
1177 }
1178
1179 if (nic_iface->poll_set_mode != NULL) {
1180 int rc = nic_iface->poll_set_mode(dev, mode, period);
1181 async_answer_0(callid, rc);
1182 } else
1183 async_answer_0(callid, ENOTSUP);
1184}
1185
1186static void remote_nic_poll_now(ddf_fun_t *dev, void *iface,
1187 ipc_callid_t callid, ipc_call_t *call)
1188{
1189 nic_iface_t *nic_iface = (nic_iface_t *) iface;
1190 if (nic_iface->poll_now == NULL) {
1191 async_answer_0(callid, ENOTSUP);
1192 return;
1193 }
1194
1195 int rc = nic_iface->poll_now(dev);
1196 async_answer_0(callid, rc);
1197}
1198
1199/** Remote NIC interface operations.
1200 *
1201 */
1202static remote_iface_func_ptr_t remote_nic_iface_ops[] = {
1203 &remote_nic_send_frame,
1204 &remote_nic_callback_create,
1205 &remote_nic_get_state,
1206 &remote_nic_set_state,
1207 &remote_nic_get_address,
1208 &remote_nic_set_address,
1209 &remote_nic_get_stats,
1210 &remote_nic_get_device_info,
1211 &remote_nic_get_cable_state,
1212 &remote_nic_get_operation_mode,
1213 &remote_nic_set_operation_mode,
1214 &remote_nic_autoneg_enable,
1215 &remote_nic_autoneg_disable,
1216 &remote_nic_autoneg_probe,
1217 &remote_nic_autoneg_restart,
1218 &remote_nic_get_pause,
1219 &remote_nic_set_pause,
1220 &remote_nic_unicast_get_mode,
1221 &remote_nic_unicast_set_mode,
1222 &remote_nic_multicast_get_mode,
1223 &remote_nic_multicast_set_mode,
1224 &remote_nic_broadcast_get_mode,
1225 &remote_nic_broadcast_set_mode,
1226 &remote_nic_defective_get_mode,
1227 &remote_nic_defective_set_mode,
1228 &remote_nic_blocked_sources_get,
1229 &remote_nic_blocked_sources_set,
1230 &remote_nic_vlan_get_mask,
1231 &remote_nic_vlan_set_mask,
1232 &remote_nic_vlan_set_tag,
1233 &remote_nic_wol_virtue_add,
1234 &remote_nic_wol_virtue_remove,
1235 &remote_nic_wol_virtue_probe,
1236 &remote_nic_wol_virtue_list,
1237 &remote_nic_wol_virtue_get_caps,
1238 &remote_nic_wol_load_info,
1239 &remote_nic_offload_probe,
1240 &remote_nic_offload_set,
1241 &remote_nic_poll_get_mode,
1242 &remote_nic_poll_set_mode,
1243 &remote_nic_poll_now
1244};
1245
1246/** Remote NIC interface structure.
1247 *
1248 * Interface for processing request from remote
1249 * clients addressed to the NIC interface.
1250 *
1251 */
1252remote_iface_t remote_nic_iface = {
1253 .method_count = sizeof(remote_nic_iface_ops) /
1254 sizeof(remote_iface_func_ptr_t),
1255 .methods = remote_nic_iface_ops
1256};
1257
1258/**
1259 * @}
1260 */
Note: See TracBrowser for help on using the repository browser.