source: mainline/uspace/lib/nic/src/nic_impl.c@ 1d14090

Last change on this file since 1d14090 was 1d14090, checked in by Nataliia Korop <n.corop08@…>, 10 months ago

dumper ops can be set by user

  • Property mode set to 100644
File size: 24.7 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/**
30 * @addtogroup libnic
31 * @{
32 */
33/**
34 * @file
35 * @brief Default DDF NIC interface methods implementations
36 */
37
38#include <errno.h>
39#include <str_error.h>
40#include <ipc/services.h>
41#include <ns.h>
42#include <pcapdump_iface.h>
43#include "nic_driver.h"
44#include "nic_ev.h"
45#include "nic_impl.h"
46
47/**
48 * Default implementation of the set_state method. Trivial.
49 *
50 * @param fun
51 * @param[out] state
52 *
53 * @return EOK always.
54 */
55errno_t nic_get_state_impl(ddf_fun_t *fun, nic_device_state_t *state)
56{
57 nic_t *nic_data = nic_get_from_ddf_fun(fun);
58 fibril_rwlock_read_lock(&nic_data->main_lock);
59 *state = nic_data->state;
60 fibril_rwlock_read_unlock(&nic_data->main_lock);
61 return EOK;
62}
63
64/**
65 * Default implementation of the set_state method. Changes the internal
66 * driver's state, calls the appropriate callback and notifies the NIL service
67 * about this change.
68 *
69 * @param fun
70 * @param state The new device's state
71 *
72 * @return EOK If the state was changed
73 * @return EINVAL If the state cannot be changed
74 */
75errno_t nic_set_state_impl(ddf_fun_t *fun, nic_device_state_t state)
76{
77 if (state >= NIC_STATE_MAX) {
78 return EINVAL;
79 }
80
81 nic_t *nic_data = nic_get_from_ddf_fun(fun);
82
83 fibril_rwlock_write_lock(&nic_data->main_lock);
84 if (nic_data->state == state) {
85 /* No change, nothing to do */
86 fibril_rwlock_write_unlock(&nic_data->main_lock);
87 return EOK;
88 }
89 if (state == NIC_STATE_ACTIVE) {
90 if (nic_data->client_session == NULL) {
91 fibril_rwlock_write_unlock(&nic_data->main_lock);
92 return EINVAL;
93 }
94 }
95
96 state_change_handler event_handler = NULL;
97 switch (state) {
98 case NIC_STATE_STOPPED:
99 event_handler = nic_data->on_stopping;
100 break;
101 case NIC_STATE_DOWN:
102 event_handler = nic_data->on_going_down;
103 break;
104 case NIC_STATE_ACTIVE:
105 event_handler = nic_data->on_activating;
106 break;
107 default:
108 break;
109 }
110 if (event_handler != NULL) {
111 errno_t rc = event_handler(nic_data);
112 if (rc != EOK) {
113 fibril_rwlock_write_unlock(&nic_data->main_lock);
114 return EINVAL;
115 }
116 }
117
118 if (state == NIC_STATE_STOPPED) {
119 /* Notify upper layers that we are reseting the MAC */
120 errno_t rc = nic_ev_addr_changed(nic_data->client_session,
121 &nic_data->default_mac);
122 nic_data->poll_mode = nic_data->default_poll_mode;
123 memcpy(&nic_data->poll_period, &nic_data->default_poll_period,
124 sizeof(struct timespec));
125 if (rc != EOK) {
126 /*
127 * We have already ran the on stopped handler, even if we
128 * terminated the state change we would end up in undefined state.
129 * Therefore we just log the problem.
130 */
131 }
132
133 fibril_rwlock_write_lock(&nic_data->stats_lock);
134 memset(&nic_data->stats, 0, sizeof(nic_device_stats_t));
135 fibril_rwlock_write_unlock(&nic_data->stats_lock);
136
137 fibril_rwlock_write_lock(&nic_data->rxc_lock);
138 nic_rxc_clear(&nic_data->rx_control);
139 /* Reinsert device's default MAC */
140 nic_rxc_set_addr(&nic_data->rx_control, NULL,
141 &nic_data->default_mac);
142 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
143 memcpy(&nic_data->mac, &nic_data->default_mac, sizeof (nic_address_t));
144
145 fibril_rwlock_write_lock(&nic_data->wv_lock);
146 nic_wol_virtues_clear(&nic_data->wol_virtues);
147 fibril_rwlock_write_unlock(&nic_data->wv_lock);
148
149 /* Ensure stopping period of NIC_POLL_SOFTWARE_PERIODIC */
150 nic_sw_period_stop(nic_data);
151 }
152
153 nic_data->state = state;
154
155 nic_ev_device_state(nic_data->client_session, state);
156
157 fibril_rwlock_write_unlock(&nic_data->main_lock);
158
159 return EOK;
160}
161
162/**
163 * Default implementation of the send_frame method.
164 * Send messages to the network.
165 *
166 * @param fun
167 * @param data Frame data
168 * @param size Frame size in bytes
169 *
170 * @return EOK If the message was sent
171 * @return EBUSY If the device is not in state when the frame can be sent.
172 */
173errno_t nic_send_frame_impl(ddf_fun_t *fun, void *data, size_t size)
174{
175 nic_t *nic_data = nic_get_from_ddf_fun(fun);
176
177 fibril_rwlock_read_lock(&nic_data->main_lock);
178 if (nic_data->state != NIC_STATE_ACTIVE || nic_data->tx_busy) {
179 fibril_rwlock_read_unlock(&nic_data->main_lock);
180 return EBUSY;
181 }
182 pcapdump_packet(nic_get_pcap_iface(nic_data), data, size);
183 nic_data->send_frame(nic_data, data, size);
184 fibril_rwlock_read_unlock(&nic_data->main_lock);
185 return EOK;
186}
187
188/**
189 * Default implementation of the connect_client method.
190 * Creates callback connection to the client.
191 *
192 * @param fun
193 *
194 * @return EOK On success, or an error code.
195 */
196errno_t nic_callback_create_impl(ddf_fun_t *fun)
197{
198 nic_t *nic = nic_get_from_ddf_fun(fun);
199 fibril_rwlock_write_lock(&nic->main_lock);
200
201 nic->client_session = async_callback_receive(EXCHANGE_SERIALIZE);
202 if (nic->client_session == NULL) {
203 fibril_rwlock_write_unlock(&nic->main_lock);
204 return ENOMEM;
205 }
206
207 fibril_rwlock_write_unlock(&nic->main_lock);
208 return EOK;
209}
210
211/**
212 * Default implementation of the get_address method.
213 * Retrieves the NIC's physical address.
214 *
215 * @param fun
216 * @param address Pointer to the structure where the address will be stored.
217 *
218 * @return EOK If the services were bound
219 * @return ELIMIT If the buffer is too short
220 */
221errno_t nic_get_address_impl(ddf_fun_t *fun, nic_address_t *address)
222{
223 assert(address);
224 nic_t *nic_data = nic_get_from_ddf_fun(fun);
225 fibril_rwlock_read_lock(&nic_data->main_lock);
226 memcpy(address, &nic_data->mac, sizeof (nic_address_t));
227 fibril_rwlock_read_unlock(&nic_data->main_lock);
228 return EOK;
229}
230
231/**
232 * Default implementation of the get_stats method. Copies the statistics from
233 * the drivers data to supplied buffer.
234 *
235 * @param fun
236 * @param[out] stats The buffer for statistics
237 *
238 * @return EOK (cannot fail)
239 */
240errno_t nic_get_stats_impl(ddf_fun_t *fun, nic_device_stats_t *stats)
241{
242 nic_t *nic_data = nic_get_from_ddf_fun(fun);
243 assert (stats != NULL);
244 fibril_rwlock_read_lock(&nic_data->stats_lock);
245 memcpy(stats, &nic_data->stats, sizeof (nic_device_stats_t));
246 fibril_rwlock_read_unlock(&nic_data->stats_lock);
247 return EOK;
248}
249
250/**
251 * Default implementation of unicast_get_mode method.
252 *
253 * @param fun
254 * @param[out] mode Current operation mode
255 * @param[in] max_count Max number of addresses that can be written into the
256 * buffer (addr_list).
257 * @param[out] addr_list Buffer for addresses
258 * @param[out] addr_count Number of addresses written into the list
259 *
260 * @return EOK
261 */
262errno_t nic_unicast_get_mode_impl(ddf_fun_t *fun, nic_unicast_mode_t *mode,
263 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
264{
265 nic_t *nic_data = nic_get_from_ddf_fun(fun);
266 fibril_rwlock_read_lock(&nic_data->rxc_lock);
267 nic_rxc_unicast_get_mode(&nic_data->rx_control, mode, max_count,
268 addr_list, addr_count);
269 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
270 return EOK;
271}
272
273/**
274 * Default implementation of unicast_set_mode method.
275 *
276 * @param fun
277 * @param[in] mode New operation mode
278 * @param[in] addr_list List of unicast addresses
279 * @param[in] addr_count Number of addresses in the list
280 *
281 * @return EOK
282 * @return EINVAL
283 * @return ENOTSUP
284 * @return ENOMEM
285 */
286errno_t nic_unicast_set_mode_impl(ddf_fun_t *fun,
287 nic_unicast_mode_t mode, const nic_address_t *addr_list, size_t addr_count)
288{
289 assert((addr_count == 0 && addr_list == NULL) ||
290 (addr_count != 0 && addr_list != NULL));
291 size_t i;
292 for (i = 0; i < addr_count; ++i) {
293 if (addr_list[i].address[0] & 1)
294 return EINVAL;
295 }
296
297 nic_t *nic_data = nic_get_from_ddf_fun(fun);
298 fibril_rwlock_write_lock(&nic_data->rxc_lock);
299 errno_t rc = ENOTSUP;
300 if (nic_data->on_unicast_mode_change) {
301 rc = nic_data->on_unicast_mode_change(nic_data,
302 mode, addr_list, addr_count);
303 }
304 if (rc == EOK) {
305 rc = nic_rxc_unicast_set_mode(&nic_data->rx_control, mode,
306 addr_list, addr_count);
307 /*
308 * After changing the mode the addr db gets cleared, therefore we have
309 * to reinsert also the physical address of NIC.
310 */
311 nic_rxc_set_addr(&nic_data->rx_control, NULL, &nic_data->mac);
312 }
313 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
314 return rc;
315}
316
317/**
318 * Default implementation of multicast_get_mode method.
319 *
320 * @param fun
321 * @param[out] mode Current operation mode
322 * @param[in] max_count Max number of addresses that can be written into the
323 * buffer (addr_list).
324 * @param[out] addr_list Buffer for addresses
325 * @param[out] addr_count Number of addresses written into the list
326 *
327 * @return EOK
328 */
329errno_t nic_multicast_get_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t *mode,
330 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
331{
332 nic_t *nic_data = nic_get_from_ddf_fun(fun);
333 fibril_rwlock_read_lock(&nic_data->rxc_lock);
334 nic_rxc_multicast_get_mode(&nic_data->rx_control, mode, max_count,
335 addr_list, addr_count);
336 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
337 return EOK;
338}
339
340/**
341 * Default implementation of multicast_set_mode method.
342 *
343 * @param fun
344 * @param[in] mode New operation mode
345 * @param[in] addr_list List of multicast addresses
346 * @param[in] addr_count Number of addresses in the list
347 *
348 * @return EOK
349 * @return EINVAL
350 * @return ENOTSUP
351 * @return ENOMEM
352 */
353errno_t nic_multicast_set_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t mode,
354 const nic_address_t *addr_list, size_t addr_count)
355{
356 assert((addr_count == 0 && addr_list == NULL) ||
357 (addr_count != 0 && addr_list != NULL));
358 size_t i;
359 for (i = 0; i < addr_count; ++i) {
360 if (!(addr_list[i].address[0] & 1))
361 return EINVAL;
362 }
363
364 nic_t *nic_data = nic_get_from_ddf_fun(fun);
365 fibril_rwlock_write_lock(&nic_data->rxc_lock);
366 errno_t rc = ENOTSUP;
367 if (nic_data->on_multicast_mode_change) {
368 rc = nic_data->on_multicast_mode_change(nic_data, mode, addr_list, addr_count);
369 }
370 if (rc == EOK) {
371 rc = nic_rxc_multicast_set_mode(&nic_data->rx_control, mode,
372 addr_list, addr_count);
373 }
374 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
375 return rc;
376}
377
378/**
379 * Default implementation of broadcast_get_mode method.
380 *
381 * @param fun
382 * @param[out] mode Current operation mode
383 *
384 * @return EOK
385 */
386errno_t nic_broadcast_get_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t *mode)
387{
388 nic_t *nic_data = nic_get_from_ddf_fun(fun);
389 fibril_rwlock_read_lock(&nic_data->rxc_lock);
390 nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
391 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
392 return EOK;
393}
394
395/**
396 * Default implementation of broadcast_set_mode method.
397 *
398 * @param fun
399 * @param[in] mode New operation mode
400 *
401 * @return EOK
402 * @return EINVAL
403 * @return ENOTSUP
404 * @return ENOMEM
405 */
406errno_t nic_broadcast_set_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t mode)
407{
408 nic_t *nic_data = nic_get_from_ddf_fun(fun);
409 fibril_rwlock_write_lock(&nic_data->rxc_lock);
410 errno_t rc = ENOTSUP;
411 if (nic_data->on_broadcast_mode_change) {
412 rc = nic_data->on_broadcast_mode_change(nic_data, mode);
413 }
414 if (rc == EOK) {
415 rc = nic_rxc_broadcast_set_mode(&nic_data->rx_control, mode);
416 }
417 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
418 return rc;
419}
420
421/**
422 * Default implementation of blocked_sources_get method.
423 *
424 * @param fun
425 * @param[in] max_count Max number of addresses that can be written into the
426 * buffer (addr_list).
427 * @param[out] addr_list Buffer for addresses
428 * @param[out] addr_count Number of addresses written into the list
429 *
430 * @return EOK
431 */
432errno_t nic_blocked_sources_get_impl(ddf_fun_t *fun,
433 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
434{
435 nic_t *nic_data = nic_get_from_ddf_fun(fun);
436 fibril_rwlock_read_lock(&nic_data->rxc_lock);
437 nic_rxc_blocked_sources_get(&nic_data->rx_control,
438 max_count, addr_list, addr_count);
439 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
440 return EOK;
441}
442
443/**
444 * Default implementation of blocked_sources_set method.
445 *
446 * @param fun
447 * @param[in] addr_list List of blocked addresses
448 * @param[in] addr_count Number of addresses in the list
449 *
450 * @return EOK
451 * @return EINVAL
452 * @return ENOTSUP
453 * @return ENOMEM
454 */
455errno_t nic_blocked_sources_set_impl(ddf_fun_t *fun,
456 const nic_address_t *addr_list, size_t addr_count)
457{
458 nic_t *nic_data = nic_get_from_ddf_fun(fun);
459 fibril_rwlock_write_lock(&nic_data->rxc_lock);
460 if (nic_data->on_blocked_sources_change) {
461 nic_data->on_blocked_sources_change(nic_data, addr_list, addr_count);
462 }
463 errno_t rc = nic_rxc_blocked_sources_set(&nic_data->rx_control,
464 addr_list, addr_count);
465 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
466 return rc;
467}
468
469/**
470 * Default implementation of vlan_get_mask method.
471 *
472 * @param fun
473 * @param[out] mask Current VLAN mask
474 *
475 * @return EOK
476 * @return ENOENT If the mask is not set
477 */
478errno_t nic_vlan_get_mask_impl(ddf_fun_t *fun, nic_vlan_mask_t *mask)
479{
480 nic_t *nic_data = nic_get_from_ddf_fun(fun);
481 fibril_rwlock_read_lock(&nic_data->rxc_lock);
482 errno_t rc = nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
483 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
484 return rc;
485}
486
487/**
488 * Default implementation of vlan_set_mask method.
489 *
490 * @param fun
491 * @param[in] mask The new VLAN mask
492 *
493 * @return EOK
494 * @return ENOMEM
495 */
496errno_t nic_vlan_set_mask_impl(ddf_fun_t *fun, const nic_vlan_mask_t *mask)
497{
498 nic_t *nic_data = nic_get_from_ddf_fun(fun);
499 fibril_rwlock_write_lock(&nic_data->rxc_lock);
500 errno_t rc = nic_rxc_vlan_set_mask(&nic_data->rx_control, mask);
501 if (rc == EOK && nic_data->on_vlan_mask_change) {
502 nic_data->on_vlan_mask_change(nic_data, mask);
503 }
504 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
505 return rc;
506}
507
508/**
509 * Default implementation of the wol_virtue_add method.
510 * Create a new WOL virtue.
511 *
512 * @param[in] fun
513 * @param[in] type Type of the virtue
514 * @param[in] data Data required for this virtue (depends on type)
515 * @param[in] length Length of the data
516 * @param[out] filter Identifier of the new virtue
517 *
518 * @return EOK If the operation was successfully completed
519 * @return EINVAL If virtue type is not supported or the data are invalid
520 * @return ELIMIT If the driver does not allow to create more virtues
521 * @return ENOMEM If there was not enough memory to complete the operation
522 */
523errno_t nic_wol_virtue_add_impl(ddf_fun_t *fun, nic_wv_type_t type,
524 const void *data, size_t length, nic_wv_id_t *new_id)
525{
526 nic_t *nic_data = nic_get_from_ddf_fun(fun);
527 if (nic_data->on_wol_virtue_add == NULL ||
528 nic_data->on_wol_virtue_remove == NULL) {
529 return ENOTSUP;
530 }
531 if (type == NIC_WV_NONE || type >= NIC_WV_MAX) {
532 return EINVAL;
533 }
534 if (nic_wol_virtues_verify(type, data, length) != EOK) {
535 return EINVAL;
536 }
537 nic_wol_virtue_t *virtue = malloc(sizeof (nic_wol_virtue_t));
538 if (virtue == NULL) {
539 return ENOMEM;
540 }
541 memset(virtue, 0, sizeof(nic_wol_virtue_t));
542 if (length != 0) {
543 virtue->data = malloc(length);
544 if (virtue->data == NULL) {
545 free(virtue);
546 return ENOMEM;
547 }
548 memcpy((void *) virtue->data, data, length);
549 }
550 virtue->type = type;
551 virtue->length = length;
552
553 fibril_rwlock_write_lock(&nic_data->wv_lock);
554 /* Check if we haven't reached the maximum */
555 if (nic_data->wol_virtues.caps_max[type] < 0) {
556 fibril_rwlock_write_unlock(&nic_data->wv_lock);
557 free(virtue->data);
558 free(virtue);
559 return EINVAL;
560 }
561 if ((int) nic_data->wol_virtues.lists_sizes[type] >=
562 nic_data->wol_virtues.caps_max[type]) {
563 fibril_rwlock_write_unlock(&nic_data->wv_lock);
564 free(virtue->data);
565 free(virtue);
566 return ELIMIT;
567 }
568 /* Call the user-defined add callback */
569 errno_t rc = nic_data->on_wol_virtue_add(nic_data, virtue);
570 if (rc != EOK) {
571 free(virtue->data);
572 free(virtue);
573 fibril_rwlock_write_unlock(&nic_data->wv_lock);
574 return rc;
575 }
576 rc = nic_wol_virtues_add(&nic_data->wol_virtues, virtue);
577 if (rc != EOK) {
578 /* If the adding fails, call user-defined remove callback */
579 nic_data->on_wol_virtue_remove(nic_data, virtue);
580 fibril_rwlock_write_unlock(&nic_data->wv_lock);
581 free(virtue->data);
582 free(virtue);
583 return rc;
584 } else {
585 *new_id = virtue->id;
586 fibril_rwlock_write_unlock(&nic_data->wv_lock);
587 }
588 return EOK;
589}
590
591/**
592 * Default implementation of the wol_virtue_remove method.
593 * Destroys the WOL virtue.
594 *
595 * @param[in] fun
596 * @param[in] id WOL virtue identification
597 *
598 * @return EOK If the operation was successfully completed
599 * @return ENOTSUP If the function is not supported by the driver or device
600 * @return ENOENT If the virtue identifier is not valid.
601 */
602errno_t nic_wol_virtue_remove_impl(ddf_fun_t *fun, nic_wv_id_t id)
603{
604 nic_t *nic_data = nic_get_from_ddf_fun(fun);
605 if (nic_data->on_wol_virtue_add == NULL ||
606 nic_data->on_wol_virtue_remove == NULL) {
607 return ENOTSUP;
608 }
609 fibril_rwlock_write_lock(&nic_data->wv_lock);
610 nic_wol_virtue_t *virtue =
611 nic_wol_virtues_remove(&nic_data->wol_virtues, id);
612 if (virtue == NULL) {
613 fibril_rwlock_write_unlock(&nic_data->wv_lock);
614 return ENOENT;
615 }
616 /* The event handler is called after the filter was removed */
617 nic_data->on_wol_virtue_remove(nic_data, virtue);
618 fibril_rwlock_write_unlock(&nic_data->wv_lock);
619 free(virtue->data);
620 free(virtue);
621 return EOK;
622}
623
624/**
625 * Default implementation of the wol_virtue_probe method.
626 * Queries the type and data of the virtue.
627 *
628 * @param[in] fun
629 * @param[in] id Virtue identifier
630 * @param[out] type Type of the virtue. Can be NULL.
631 * @param[out] data Data used when the virtue was created. Can be NULL.
632 * @param[out] length Length of the data. Can be NULL.
633 *
634 * @return EOK If the operation was successfully completed
635 * @return ENOENT If the virtue identifier is not valid.
636 * @return ENOMEM If there was not enough memory to complete the operation
637 */
638errno_t nic_wol_virtue_probe_impl(ddf_fun_t *fun, nic_wv_id_t id,
639 nic_wv_type_t *type, size_t max_length, void *data, size_t *length)
640{
641 nic_t *nic_data = nic_get_from_ddf_fun(fun);
642 fibril_rwlock_read_lock(&nic_data->wv_lock);
643 const nic_wol_virtue_t *virtue =
644 nic_wol_virtues_find(&nic_data->wol_virtues, id);
645 if (virtue == NULL) {
646 *type = NIC_WV_NONE;
647 *length = 0;
648 fibril_rwlock_read_unlock(&nic_data->wv_lock);
649 return ENOENT;
650 } else {
651 *type = virtue->type;
652 if (max_length > virtue->length) {
653 max_length = virtue->length;
654 }
655 memcpy(data, virtue->data, max_length);
656 *length = virtue->length;
657 fibril_rwlock_read_unlock(&nic_data->wv_lock);
658 return EOK;
659 }
660}
661
662/**
663 * Default implementation of the wol_virtue_list method.
664 * List filters of the specified type. If NIC_WV_NONE is the type, it lists all
665 * filters.
666 *
667 * @param[in] fun
668 * @param[in] type Type of the virtues
669 * @param[out] virtues Vector of virtue ID's.
670 * @param[out] count Length of the data. Can be NULL.
671 *
672 * @return EOK If the operation was successfully completed
673 * @return ENOENT If the filter identification is not valid.
674 * @return ENOMEM If there was not enough memory to complete the operation
675 */
676errno_t nic_wol_virtue_list_impl(ddf_fun_t *fun, nic_wv_type_t type,
677 size_t max_count, nic_wv_id_t *id_list, size_t *id_count)
678{
679 nic_t *nic_data = nic_get_from_ddf_fun(fun);
680 fibril_rwlock_read_lock(&nic_data->wv_lock);
681 errno_t rc = nic_wol_virtues_list(&nic_data->wol_virtues, type,
682 max_count, id_list, id_count);
683 fibril_rwlock_read_unlock(&nic_data->wv_lock);
684 return rc;
685}
686
687/**
688 * Default implementation of the wol_virtue_get_caps method.
689 * Queries for the current capabilities for some type of filter.
690 *
691 * @param[in] fun
692 * @param[in] type Type of the virtues
693 * @param[out] count Number of virtues of this type that can be currently set
694 *
695 * @return EOK If the operation was successfully completed
696 */
697errno_t nic_wol_virtue_get_caps_impl(ddf_fun_t *fun, nic_wv_type_t type, int *count)
698{
699 nic_t *nic_data = nic_get_from_ddf_fun(fun);
700 fibril_rwlock_read_lock(&nic_data->wv_lock);
701 *count = nic_data->wol_virtues.caps_max[type] -
702 (int) nic_data->wol_virtues.lists_sizes[type];
703 fibril_rwlock_read_unlock(&nic_data->wv_lock);
704 return EOK;
705}
706
707/**
708 * Default implementation of the poll_get_mode method.
709 * Queries the current interrupt/poll mode of the NIC
710 *
711 * @param[in] fun
712 * @param[out] mode Current poll mode
713 * @param[out] period Period used in periodic polling. Can be NULL.
714 *
715 * @return EOK If the operation was successfully completed
716 * @return ENOTSUP This function is not supported.
717 * @return EPARTY Error in communication protocol
718 */
719errno_t nic_poll_get_mode_impl(ddf_fun_t *fun,
720 nic_poll_mode_t *mode, struct timespec *period)
721{
722 nic_t *nic_data = nic_get_from_ddf_fun(fun);
723 fibril_rwlock_read_lock(&nic_data->main_lock);
724 *mode = nic_data->poll_mode;
725 memcpy(period, &nic_data->poll_period, sizeof(struct timespec));
726 fibril_rwlock_read_unlock(&nic_data->main_lock);
727 return EOK;
728}
729
730/**
731 * Default implementation of the poll_set_mode_impl method.
732 * Sets the interrupt/poll mode of the NIC.
733 *
734 * @param[in] fun
735 * @param[in] mode The new poll mode
736 * @param[in] period Period used in periodic polling. Can be NULL.
737 *
738 * @return EOK If the operation was successfully completed
739 * @return ENOTSUP This operation is not supported.
740 * @return EPARTY Error in communication protocol
741 */
742errno_t nic_poll_set_mode_impl(ddf_fun_t *fun,
743 nic_poll_mode_t mode, const struct timespec *period)
744{
745 nic_t *nic_data = nic_get_from_ddf_fun(fun);
746 /*
747 * If the driver does not implement the poll mode change handler it cannot
748 * switch off interrupts and this is not supported.
749 */
750 if (nic_data->on_poll_mode_change == NULL)
751 return ENOTSUP;
752
753 if ((mode == NIC_POLL_ON_DEMAND) && nic_data->on_poll_request == NULL)
754 return ENOTSUP;
755
756 if (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) {
757 if (period == NULL)
758 return EINVAL;
759 if (period->tv_sec == 0 && period->tv_nsec == 0)
760 return EINVAL;
761 if (period->tv_sec < 0 || period->tv_nsec < 0)
762 return EINVAL;
763 }
764 fibril_rwlock_write_lock(&nic_data->main_lock);
765 errno_t rc = nic_data->on_poll_mode_change(nic_data, mode, period);
766 assert(rc == EOK || rc == ENOTSUP || rc == EINVAL);
767 if (rc == ENOTSUP && (nic_data->on_poll_request != NULL) &&
768 (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC)) {
769
770 rc = nic_data->on_poll_mode_change(nic_data, NIC_POLL_ON_DEMAND, NULL);
771 assert(rc == EOK || rc == ENOTSUP);
772 if (rc == EOK)
773 nic_sw_period_start(nic_data);
774 }
775 if (rc == EOK) {
776 nic_data->poll_mode = mode;
777 if (period)
778 nic_data->poll_period = *period;
779 }
780 fibril_rwlock_write_unlock(&nic_data->main_lock);
781 return rc;
782}
783
784/**
785 * Default implementation of the poll_now method.
786 * Wrapper for the actual poll implementation.
787 *
788 * @param[in] fun
789 *
790 * @return EOK If the NIC was polled
791 * @return ENOTSUP If the function is not supported
792 * @return EINVAL If the NIC is not in state where it allows on demand polling
793 */
794errno_t nic_poll_now_impl(ddf_fun_t *fun)
795{
796 nic_t *nic_data = nic_get_from_ddf_fun(fun);
797 fibril_rwlock_read_lock(&nic_data->main_lock);
798 if (nic_data->poll_mode != NIC_POLL_ON_DEMAND) {
799 fibril_rwlock_read_unlock(&nic_data->main_lock);
800 return EINVAL;
801 }
802 if (nic_data->on_poll_request != NULL) {
803 nic_data->on_poll_request(nic_data);
804 fibril_rwlock_read_unlock(&nic_data->main_lock);
805 return EOK;
806 } else {
807 fibril_rwlock_read_unlock(&nic_data->main_lock);
808 return ENOTSUP;
809 }
810}
811
812/**
813 * Default handler for unknown methods (outside of the NIC interface).
814 * Logs a warning message and returns ENOTSUP to the caller.
815 *
816 * @param fun The DDF function where the method should be called.
817 * @param call IPC call data
818 *
819 */
820void nic_default_handler_impl(ddf_fun_t *fun, ipc_call_t *call)
821{
822 async_answer_0(call, ENOTSUP);
823}
824
825/**
826 * Default (empty) OPEN function implementation.
827 *
828 * @param fun The DDF function
829 *
830 * @return EOK always.
831 */
832errno_t nic_open_impl(ddf_fun_t *fun)
833{
834 return EOK;
835}
836
837/**
838 * Default (empty) OPEN function implementation.
839 *
840 * @param fun The DDF function
841 */
842void nic_close_impl(ddf_fun_t *fun)
843{
844}
845
846errno_t nic_fun_add_to_cats(ddf_fun_t *fun)
847{
848 errno_t rc;
849 rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
850 if (rc != EOK)
851 return rc;
852
853 rc = ddf_fun_add_to_category(fun, "pcap");
854 if (rc != EOK) {
855 return rc;
856 }
857 return EOK;
858}
859
860/** @}
861 */
Note: See TracBrowser for help on using the repository browser.