source: mainline/uspace/srv/net/il/arp/arp.c@ aadf01e

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

Coding style (no functional change)

  • Property mode set to 100644
File size: 20.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 arp
30 * @{
31 */
32
33/** @file
34 * ARP module implementation.
35 * @see arp.h
36 */
37
38#include <async.h>
39#include <malloc.h>
40#include <mem.h>
41#include <fibril_synch.h>
42#include <stdio.h>
43#include <string.h>
44#include <task.h>
45
46#include <ipc/ipc.h>
47#include <ipc/services.h>
48
49#include "../../err.h"
50#include "../../messages.h"
51#include "../../modules.h"
52
53#include "../../include/byteorder.h"
54#include "../../include/device.h"
55#include "../../include/arp_interface.h"
56#include "../../include/nil_interface.h"
57#include "../../include/protocol_map.h"
58
59#include "../../structures/measured_strings.h"
60#include "../../structures/packet/packet.h"
61#include "../../structures/packet/packet_client.h"
62
63#include "../il_messages.h"
64
65#include "arp.h"
66#include "arp_header.h"
67#include "arp_oc.h"
68#include "arp_module.h"
69#include "arp_messages.h"
70
71/** ARP global data.
72 */
73arp_globals_t arp_globals;
74
75/** Creates new protocol specific data.
76 * Allocates and returns the needed memory block as the proto parameter.
77 * @param[out] proto The allocated protocol specific data.
78 * @param[in] service The protocol module service.
79 * @param[in] address The actual protocol device address.
80 * @returns EOK on success.
81 * @returns ENOMEM if there is not enough memory left.
82 */
83int arp_proto_create(arp_proto_ref * proto, services_t service, measured_string_ref address);
84
85/** Clears the device specific data.
86 * @param[in] device The device specific data.
87 */
88void arp_clear_device(arp_device_ref device);
89
90/** @name Message processing functions
91 */
92/*@{*/
93
94/** Registers the device.
95 * Creates new device entry in the cache or updates the protocol address if the device with the device identifier and the driver service exists.
96 * @param[in] device_id The device identifier.
97 * @param[in] service The device driver service.
98 * @param[in] protocol The protocol service.
99 * @param[in] address The actual device protocol address.
100 * @returns EOK on success.
101 * @returns EEXIST if another device with the same device identifier and different driver service exists.
102 * @returns ENOMEM if there is not enough memory left.
103 * @returns Other error codes as defined for the measured_strings_return() function.
104 */
105int arp_device_message(device_id_t device_id, services_t service, services_t protocol, measured_string_ref address);
106
107/** Returns the hardware address for the given protocol address.
108 * Sends the ARP request packet if the hardware address is not found in the cache.
109 * @param[in] device_id The device identifier.
110 * @param[in] protocol The protocol service.
111 * @param[in] target The target protocol address.
112 * @returns The hardware address of the target.
113 * @returns NULL if the target parameter is NULL.
114 * @returns NULL if the device is not found.
115 * @returns NULL if the device packet is too small to send a&nbsp;request.
116 * @returns NULL if the hardware address is not found in the cache.
117 */
118measured_string_ref arp_translate_message(device_id_t device_id, services_t protocol, measured_string_ref target);
119
120/** Processes the received ARP packet.
121 * Updates the source hardware address if the source entry exists or the packet is targeted to my protocol address.
122 * Responses to the ARP request if the packet is the ARP request and is targeted to my address.
123 * @param[in] device_id The source device identifier.
124 * @param[in,out] packet The received packet.
125 * @returns EOK on success and the packet is no longer needed.
126 * @returns 1 on success and the packet has been reused.
127 * @returns EINVAL if the packet is too small to carry an ARP packet.
128 * @returns EINVAL if the received address lengths differs from the registered values.
129 * @returns ENOENT if the device is not found in the cache.
130 * @returns ENOENT if the protocol for the device is not found in the cache.
131 * @returns ENOMEM if there is not enough memory left.
132 */
133int arp_receive_message(device_id_t device_id, packet_t packet);
134
135/** Updates the device content length according to the new MTU value.
136 * @param[in] device_id The device identifier.
137 * @param[in] mtu The new mtu value.
138 * @returns ENOENT if device is not found.
139 * @returns EOK on success.
140 */
141int arp_mtu_changed_message(device_id_t device_id, size_t mtu);
142
143/*@}*/
144
145DEVICE_MAP_IMPLEMENT(arp_cache, arp_device_t)
146
147INT_MAP_IMPLEMENT(arp_protos, arp_proto_t)
148
149GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, measured_string_t)
150
151task_id_t arp_task_get_id(void){
152 return task_get_id();
153}
154
155int arp_clear_device_req(int arp_phone, device_id_t device_id){
156 arp_device_ref device;
157
158 fibril_rwlock_write_lock(&arp_globals.lock);
159 device = arp_cache_find(&arp_globals.cache, device_id);
160 if(! device){
161 fibril_rwlock_write_unlock(&arp_globals.lock);
162 return ENOENT;
163 }
164 arp_clear_device(device);
165 printf("Device %d cleared\n", device_id);
166 fibril_rwlock_write_unlock(&arp_globals.lock);
167 return EOK;
168}
169
170int arp_clear_address_req(int arp_phone, device_id_t device_id, services_t protocol, measured_string_ref address){
171 arp_device_ref device;
172 arp_proto_ref proto;
173
174 fibril_rwlock_write_lock(&arp_globals.lock);
175 device = arp_cache_find(&arp_globals.cache, device_id);
176 if(! device){
177 fibril_rwlock_write_unlock(&arp_globals.lock);
178 return ENOENT;
179 }
180 proto = arp_protos_find(&device->protos, protocol);
181 if(! proto){
182 fibril_rwlock_write_unlock(&arp_globals.lock);
183 return ENOENT;
184 }
185 arp_addr_exclude(&proto->addresses, address->value, address->length);
186 fibril_rwlock_write_unlock(&arp_globals.lock);
187 return EOK;
188}
189
190int arp_clean_cache_req(int arp_phone){
191 int count;
192 arp_device_ref device;
193
194 fibril_rwlock_write_lock(&arp_globals.lock);
195 for(count = arp_cache_count(&arp_globals.cache) - 1; count >= 0; -- count){
196 device = arp_cache_get_index(&arp_globals.cache, count);
197 if(device){
198 arp_clear_device(device);
199 if(device->addr_data){
200 free(device->addr_data);
201 }
202 if(device->broadcast_data){
203 free(device->broadcast_data);
204 }
205 }
206 }
207 arp_cache_clear(&arp_globals.cache);
208 fibril_rwlock_write_unlock(&arp_globals.lock);
209 printf("Cache cleaned\n");
210 return EOK;
211}
212
213int arp_device_req(int arp_phone, device_id_t device_id, services_t protocol, services_t netif, measured_string_ref address){
214 ERROR_DECLARE;
215
216 measured_string_ref tmp;
217
218 // copy the given address for exclusive use
219 tmp = measured_string_copy(address);
220 if(ERROR_OCCURRED(arp_device_message(device_id, netif, protocol, tmp))){
221 free(tmp->value);
222 free(tmp);
223 }
224 return ERROR_CODE;
225}
226
227int arp_translate_req(int arp_phone, device_id_t device_id, services_t protocol, measured_string_ref address, measured_string_ref * translation, char ** data){
228 measured_string_ref tmp;
229
230 fibril_rwlock_read_lock(&arp_globals.lock);
231 tmp = arp_translate_message(device_id, protocol, address);
232 if(tmp){
233 *translation = measured_string_copy(tmp);
234 fibril_rwlock_read_unlock(&arp_globals.lock);
235 if(*translation){
236 *data = (** translation).value;
237 return EOK;
238 }else{
239 return ENOMEM;
240 }
241 }else{
242 fibril_rwlock_read_unlock(&arp_globals.lock);
243 return ENOENT;
244 }
245}
246
247int arp_initialize(async_client_conn_t client_connection){
248 ERROR_DECLARE;
249
250 fibril_rwlock_initialize(&arp_globals.lock);
251 fibril_rwlock_write_lock(&arp_globals.lock);
252 arp_globals.client_connection = client_connection;
253 ERROR_PROPAGATE(arp_cache_initialize(&arp_globals.cache));
254 fibril_rwlock_write_unlock(&arp_globals.lock);
255 return EOK;
256}
257
258int arp_proto_create(arp_proto_ref * proto, services_t service, measured_string_ref address){
259 ERROR_DECLARE;
260
261 *proto = (arp_proto_ref) malloc(sizeof(arp_proto_t));
262 if(!(*proto)){
263 return ENOMEM;
264 }
265 (** proto).service = service;
266 (** proto).addr = address;
267 (** proto).addr_data = address->value;
268 if(ERROR_OCCURRED(arp_addr_initialize(&(** proto).addresses))){
269 free(*proto);
270 return ERROR_CODE;
271 }
272 return EOK;
273}
274
275int arp_device_message(device_id_t device_id, services_t service, services_t protocol, measured_string_ref address){
276 ERROR_DECLARE;
277
278 arp_device_ref device;
279 arp_proto_ref proto;
280 int index;
281 hw_type_t hardware;
282
283 fibril_rwlock_write_lock(&arp_globals.lock);
284 // an existing device?
285 device = arp_cache_find(&arp_globals.cache, device_id);
286 if(device){
287 if(device->service != service){
288 printf("Device %d already exists\n", device->device_id);
289 fibril_rwlock_write_unlock(&arp_globals.lock);
290 return EEXIST;
291 }
292 proto = arp_protos_find(&device->protos, protocol);
293 if(proto){
294 free(proto->addr);
295 free(proto->addr_data);
296 proto->addr = address;
297 proto->addr_data = address->value;
298 }else{
299 if(ERROR_OCCURRED(arp_proto_create(&proto, protocol, address))){
300 fibril_rwlock_write_unlock(&arp_globals.lock);
301 return ERROR_CODE;
302 }
303 index = arp_protos_add(&device->protos, proto->service, proto);
304 if(index < 0){
305 fibril_rwlock_write_unlock(&arp_globals.lock);
306 free(proto);
307 return index;
308 }
309 printf("New protocol added:\n\tdevice id\t= %d\n\tproto\t= %d", device_id, protocol);
310 }
311 }else{
312 hardware = hardware_map(service);
313 if(! hardware){
314 return ENOENT;
315 }
316 // create a new device
317 device = (arp_device_ref) malloc(sizeof(arp_device_t));
318 if(! device){
319 fibril_rwlock_write_unlock(&arp_globals.lock);
320 return ENOMEM;
321 }
322 device->hardware = hardware;
323 device->device_id = device_id;
324 if(ERROR_OCCURRED(arp_protos_initialize(&device->protos))
325 || ERROR_OCCURRED(arp_proto_create(&proto, protocol, address))){
326 fibril_rwlock_write_unlock(&arp_globals.lock);
327 free(device);
328 return ERROR_CODE;
329 }
330 index = arp_protos_add(&device->protos, proto->service, proto);
331 if(index < 0){
332 fibril_rwlock_write_unlock(&arp_globals.lock);
333 arp_protos_destroy(&device->protos);
334 free(device);
335 return index;
336 }
337 device->service = service;
338 // bind the new one
339 device->phone = nil_bind_service(device->service, (ipcarg_t) device->device_id, SERVICE_ARP, arp_globals.client_connection);
340 if(device->phone < 0){
341 fibril_rwlock_write_unlock(&arp_globals.lock);
342 arp_protos_destroy(&device->protos);
343 free(device);
344 return EREFUSED;
345 }
346 // get packet dimensions
347 if(ERROR_OCCURRED(nil_packet_size_req(device->phone, device_id, &device->packet_dimension))){
348 fibril_rwlock_write_unlock(&arp_globals.lock);
349 arp_protos_destroy(&device->protos);
350 free(device);
351 return ERROR_CODE;
352 }
353 // get hardware address
354 if(ERROR_OCCURRED(nil_get_addr_req(device->phone, device_id, &device->addr, &device->addr_data))){
355 fibril_rwlock_write_unlock(&arp_globals.lock);
356 arp_protos_destroy(&device->protos);
357 free(device);
358 return ERROR_CODE;
359 }
360 // get broadcast address
361 if(ERROR_OCCURRED(nil_get_broadcast_addr_req(device->phone, device_id, &device->broadcast_addr, &device->broadcast_data))){
362 fibril_rwlock_write_unlock(&arp_globals.lock);
363 free(device->addr);
364 free(device->addr_data);
365 arp_protos_destroy(&device->protos);
366 free(device);
367 return ERROR_CODE;
368 }
369 if(ERROR_OCCURRED(arp_cache_add(&arp_globals.cache, device->device_id, device))){
370 fibril_rwlock_write_unlock(&arp_globals.lock);
371 free(device->addr);
372 free(device->addr_data);
373 free(device->broadcast_addr);
374 free(device->broadcast_data);
375 arp_protos_destroy(&device->protos);
376 free(device);
377 return ERROR_CODE;
378 }
379 printf("New device registered:\n\tid\t= %d\n\ttype\t= 0x%x\n\tservice\t= %d\n\tproto\t= %d\n", device->device_id, device->hardware, device->service, protocol);
380 }
381 fibril_rwlock_write_unlock(&arp_globals.lock);
382 return EOK;
383}
384
385measured_string_ref arp_translate_message(device_id_t device_id, services_t protocol, measured_string_ref target){
386 arp_device_ref device;
387 arp_proto_ref proto;
388 measured_string_ref addr;
389 size_t length;
390 packet_t packet;
391 arp_header_ref header;
392
393 if(! target){
394 return NULL;
395 }
396 device = arp_cache_find(&arp_globals.cache, device_id);
397 if(! device){
398 return NULL;
399 }
400 proto = arp_protos_find(&device->protos, protocol);
401 if((! proto) || (proto->addr->length != target->length)){
402 return NULL;
403 }
404 addr = arp_addr_find(&proto->addresses, target->value, target->length);
405 if(addr){
406 return addr;
407 }
408 // ARP packet content size = header + (address + translation) * 2
409 length = 8 + (CONVERT_SIZE(char, uint8_t, proto->addr->length) + CONVERT_SIZE(char, uint8_t, device->addr->length)) * 2;
410 if(length > device->packet_dimension.content){
411 return NULL;
412 }
413 packet = packet_get_4(arp_globals.net_phone, device->packet_dimension.addr_len, device->packet_dimension.prefix, length, device->packet_dimension.suffix);
414 if(! packet){
415 return NULL;
416 }
417 header = (arp_header_ref) packet_suffix(packet, length);
418 if(! header){
419 pq_release(arp_globals.net_phone, packet_get_id(packet));
420 return NULL;
421 }
422 header->hardware = htons(device->hardware);
423 header->hardware_length = (uint8_t) device->addr->length;
424 header->protocol = htons(protocol_map(device->service, protocol));
425 header->protocol_length = (uint8_t) proto->addr->length;
426 header->operation = htons(ARPOP_REQUEST);
427 length = sizeof(arp_header_t);
428 memcpy(((uint8_t *) header) + length, device->addr->value, device->addr->length);
429 length += device->addr->length;
430 memcpy(((uint8_t *) header) + length, proto->addr->value, proto->addr->length);
431 length += proto->addr->length;
432 bzero(((uint8_t *) header) + length, device->addr->length);
433 length += device->addr->length;
434 memcpy(((uint8_t *) header) + length, target->value, target->length);
435 if(packet_set_addr(packet, (uint8_t *) device->addr->value, (uint8_t *) device->broadcast_addr->value, CONVERT_SIZE(char, uint8_t, device->addr->length)) != EOK){
436 pq_release(arp_globals.net_phone, packet_get_id(packet));
437 return NULL;
438 }
439 nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
440 return NULL;
441}
442
443int arp_receive_message(device_id_t device_id, packet_t packet){
444 ERROR_DECLARE;
445
446 size_t length;
447 arp_header_ref header;
448 arp_device_ref device;
449 arp_proto_ref proto;
450 measured_string_ref hw_source;
451 uint8_t * src_hw;
452 uint8_t * src_proto;
453 uint8_t * des_hw;
454 uint8_t * des_proto;
455
456 length = packet_get_data_length(packet);
457 if(length <= sizeof(arp_header_t)){
458 return EINVAL;
459 }
460 device = arp_cache_find(&arp_globals.cache, device_id);
461 if(! device){
462 return ENOENT;
463 }
464 header = (arp_header_ref) packet_get_data(packet);
465 if((ntohs(header->hardware) != device->hardware)
466 || (length < sizeof(arp_header_t) + header->hardware_length * 2u + header->protocol_length * 2u)){
467 return EINVAL;
468 }
469 proto = arp_protos_find(&device->protos, protocol_unmap(device->service, ntohs(header->protocol)));
470 if(! proto){
471 return ENOENT;
472 }
473 src_hw = ((uint8_t *) header) + sizeof(arp_header_t);
474 src_proto = src_hw + header->hardware_length;
475 des_hw = src_proto + header->protocol_length;
476 des_proto = des_hw + header->hardware_length;
477 hw_source = arp_addr_find(&proto->addresses, (char *) src_proto, CONVERT_SIZE(uint8_t, char, header->protocol_length));
478 // exists?
479 if(hw_source){
480 if(hw_source->length != CONVERT_SIZE(uint8_t, char, header->hardware_length)){
481 return EINVAL;
482 }
483 memcpy(hw_source->value, src_hw, hw_source->length);
484 }
485 // is my protocol address?
486 if(proto->addr->length != CONVERT_SIZE(uint8_t, char, header->protocol_length)){
487 return EINVAL;
488 }
489 if(! str_lcmp(proto->addr->value, (char *) des_proto, proto->addr->length)){
490 // not already upadted?
491 if(! hw_source){
492 hw_source = measured_string_create_bulk((char *) src_hw, CONVERT_SIZE(uint8_t, char, header->hardware_length));
493 if(! hw_source){
494 return ENOMEM;
495 }
496 ERROR_PROPAGATE(arp_addr_add(&proto->addresses, (char *) src_proto, CONVERT_SIZE(uint8_t, char, header->protocol_length), hw_source));
497 }
498 if(ntohs(header->operation) == ARPOP_REQUEST){
499 header->operation = htons(ARPOP_REPLY);
500 memcpy(des_proto, src_proto, header->protocol_length);
501 memcpy(src_proto, proto->addr->value, header->protocol_length);
502 memcpy(src_hw, device->addr->value, device->packet_dimension.addr_len);
503 memcpy(des_hw, hw_source->value, header->hardware_length);
504 ERROR_PROPAGATE(packet_set_addr(packet, src_hw, des_hw, header->hardware_length));
505 nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
506 return 1;
507 }
508 }
509 return EOK;
510}
511
512void arp_clear_device(arp_device_ref device){
513 int count;
514 arp_proto_ref proto;
515
516 for(count = arp_protos_count(&device->protos) - 1; count >= 0; -- count){
517 proto = arp_protos_get_index(&device->protos, count);
518 if(proto){
519 if(proto->addr){
520 free(proto->addr);
521 }
522 if(proto->addr_data){
523 free(proto->addr_data);
524 }
525 arp_addr_destroy(&proto->addresses);
526 }
527 }
528 arp_protos_clear(&device->protos);
529}
530
531int arp_connect_module(services_t service){
532 if(service != SERVICE_ARP){
533 return EINVAL;
534 }
535 return EOK;
536}
537
538int arp_mtu_changed_message(device_id_t device_id, size_t mtu){
539 arp_device_ref device;
540
541 fibril_rwlock_write_lock(&arp_globals.lock);
542 device = arp_cache_find(&arp_globals.cache, device_id);
543 if(! device){
544 fibril_rwlock_write_unlock(&arp_globals.lock);
545 return ENOENT;
546 }
547 device->packet_dimension.content = mtu;
548 printf("arp - device %d changed mtu to %d\n\n", device_id, mtu);
549 fibril_rwlock_write_unlock(&arp_globals.lock);
550 return EOK;
551}
552
553int arp_message(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
554 ERROR_DECLARE;
555
556 measured_string_ref address;
557 measured_string_ref translation;
558 char * data;
559 packet_t packet;
560 packet_t next;
561
562// printf("message %d - %d\n", IPC_GET_METHOD(*call), NET_ARP_FIRST);
563 *answer_count = 0;
564 switch(IPC_GET_METHOD(*call)){
565 case IPC_M_PHONE_HUNGUP:
566 return EOK;
567 case NET_ARP_DEVICE:
568 ERROR_PROPAGATE(measured_strings_receive(&address, &data, 1));
569 if(ERROR_OCCURRED(arp_device_message(IPC_GET_DEVICE(call), IPC_GET_SERVICE(call), ARP_GET_NETIF(call), address))){
570 free(address);
571 free(data);
572 }
573 return ERROR_CODE;
574 case NET_ARP_TRANSLATE:
575 ERROR_PROPAGATE(measured_strings_receive(&address, &data, 1));
576 fibril_rwlock_read_lock(&arp_globals.lock);
577 translation = arp_translate_message(IPC_GET_DEVICE(call), IPC_GET_SERVICE(call), address);
578 free(address);
579 free(data);
580 if(! translation){
581 fibril_rwlock_read_unlock(&arp_globals.lock);
582 return ENOENT;
583 }
584 ERROR_CODE = measured_strings_reply(translation, 1);
585 fibril_rwlock_read_unlock(&arp_globals.lock);
586 return ERROR_CODE;
587 case NET_ARP_CLEAR_DEVICE:
588 return arp_clear_device_req(0, IPC_GET_DEVICE(call));
589 case NET_ARP_CLEAR_ADDRESS:
590 ERROR_PROPAGATE(measured_strings_receive(&address, &data, 1));
591 arp_clear_address_req(0, IPC_GET_DEVICE(call), IPC_GET_SERVICE(call), address);
592 free(address);
593 free(data);
594 return EOK;
595 case NET_ARP_CLEAN_CACHE:
596 return arp_clean_cache_req(0);
597 case NET_IL_DEVICE_STATE:
598 // do nothing - keep the cache
599 return EOK;
600 case NET_IL_RECEIVED:
601 if(! ERROR_OCCURRED(packet_translate(arp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){
602 fibril_rwlock_read_lock(&arp_globals.lock);
603 do{
604 next = pq_detach(packet);
605 ERROR_CODE = arp_receive_message(IPC_GET_DEVICE(call), packet);
606 if(ERROR_CODE != 1){
607 pq_release(arp_globals.net_phone, packet_get_id(packet));
608 }
609 packet = next;
610 }while(packet);
611 fibril_rwlock_read_unlock(&arp_globals.lock);
612 }
613 return ERROR_CODE;
614 case NET_IL_MTU_CHANGED:
615 return arp_mtu_changed_message(IPC_GET_DEVICE(call), IPC_GET_MTU(call));
616 }
617 return ENOTSUP;
618}
619
620/** @}
621 */
Note: See TracBrowser for help on using the repository browser.