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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 91478aa was 91478aa, checked in by Lukas Mejdrech <lukasmejdrech@…>, 15 years ago
  • unify packet dimension interfaces
  • Property mode set to 100644
File size: 20.8 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 ) free( device->addr_data );
200 if( device->broadcast_data ) free( device->broadcast_data );
201 }
202 }
203 arp_cache_clear( & arp_globals.cache );
204 fibril_rwlock_write_unlock( & arp_globals.lock );
205 printf( "Cache cleaned\n" );
206 return EOK;
207}
208
209int arp_device_req( int arp_phone, device_id_t device_id, services_t protocol, services_t netif, measured_string_ref address ){
210 ERROR_DECLARE;
211
212 measured_string_ref tmp;
213
214 // copy the given address for exclusive use
215 tmp = measured_string_copy( address );
216 if( ERROR_OCCURRED( arp_device_message( device_id, netif, protocol, tmp ))){
217 free( tmp->value );
218 free( tmp );
219 }
220 return ERROR_CODE;
221}
222
223int arp_translate_req( int arp_phone, device_id_t device_id, services_t protocol, measured_string_ref address, measured_string_ref * translation, char ** data ){
224 measured_string_ref tmp;
225
226 fibril_rwlock_read_lock( & arp_globals.lock );
227 tmp = arp_translate_message( device_id, protocol, address );
228 if( tmp ){
229 * translation = measured_string_copy( tmp );
230 fibril_rwlock_read_unlock( & arp_globals.lock );
231 if( * translation ){
232 * data = ( ** translation ).value;
233 return EOK;
234 }else{
235 return ENOMEM;
236 }
237 }else{
238 fibril_rwlock_read_unlock( & arp_globals.lock );
239 return ENOENT;
240 }
241}
242
243int arp_initialize( async_client_conn_t client_connection ){
244 ERROR_DECLARE;
245
246 fibril_rwlock_initialize( & arp_globals.lock );
247 fibril_rwlock_write_lock( & arp_globals.lock );
248 arp_globals.client_connection = client_connection;
249 ERROR_PROPAGATE( arp_cache_initialize( & arp_globals.cache ));
250 fibril_rwlock_write_unlock( & arp_globals.lock );
251 return EOK;
252}
253
254int arp_proto_create( arp_proto_ref * proto, services_t service, measured_string_ref address ){
255 ERROR_DECLARE;
256
257 * proto = ( arp_proto_ref ) malloc( sizeof( arp_proto_t ));
258 if( !( * proto )) return ENOMEM;
259 ( ** proto ).service = service;
260 ( ** proto ).addr = address;
261 ( ** proto ).addr_data = address->value;
262 if( ERROR_OCCURRED( arp_addr_initialize( &( ** proto).addresses ))){
263 free( * proto );
264 return ERROR_CODE;
265 }
266 return EOK;
267}
268
269int arp_device_message( device_id_t device_id, services_t service, services_t protocol, measured_string_ref address ){
270 ERROR_DECLARE;
271
272 arp_device_ref device;
273 arp_proto_ref proto;
274 int index;
275 hw_type_t hardware;
276
277 fibril_rwlock_write_lock( & arp_globals.lock );
278 // an existing device?
279 device = arp_cache_find( & arp_globals.cache, device_id );
280 if( device ){
281 if( device->service != service ){
282 printf( "Device %d already exists\n", device->device_id );
283 fibril_rwlock_write_unlock( & arp_globals.lock );
284 return EEXIST;
285 }
286 proto = arp_protos_find( & device->protos, protocol );
287 if( proto ){
288 free( proto->addr );
289 free( proto->addr_data );
290 proto->addr = address;
291 proto->addr_data = address->value;
292 }else{
293 if( ERROR_OCCURRED( arp_proto_create( & proto, protocol, address ))){
294 fibril_rwlock_write_unlock( & arp_globals.lock );
295 return ERROR_CODE;
296 }
297 index = arp_protos_add( & device->protos, proto->service, proto );
298 if( index < 0 ){
299 fibril_rwlock_write_unlock( & arp_globals.lock );
300 free( proto );
301 return index;
302 }
303 printf( "New protocol added:\n\tdevice id\t= %d\n\tproto\t= %d", device_id, protocol );
304 }
305 }else{
306 hardware = hardware_map( service );
307 if( ! hardware ) return ENOENT;
308 // create a new device
309 device = ( arp_device_ref ) malloc( sizeof( arp_device_t ));
310 if( ! device ){
311 fibril_rwlock_write_unlock( & arp_globals.lock );
312 return ENOMEM;
313 }
314 device->hardware = hardware;
315 device->device_id = device_id;
316 if( ERROR_OCCURRED( arp_protos_initialize( & device->protos ))
317 || ERROR_OCCURRED( arp_proto_create( & proto, protocol, address ))){
318 fibril_rwlock_write_unlock( & arp_globals.lock );
319 free( device );
320 return ERROR_CODE;
321 }
322 index = arp_protos_add( & device->protos, proto->service, proto );
323 if( index < 0 ){
324 fibril_rwlock_write_unlock( & arp_globals.lock );
325 arp_protos_destroy( & device->protos );
326 free( device );
327 return index;
328 }
329 device->service = service;
330 // bind the new one
331 device->phone = nil_bind_service( device->service, ( ipcarg_t ) device->device_id, SERVICE_ARP, arp_globals.client_connection );
332 if( device->phone < 0 ){
333 fibril_rwlock_write_unlock( & arp_globals.lock );
334 arp_protos_destroy( & device->protos );
335 free( device );
336 return EREFUSED;
337 }
338 // get packet dimensions
339 if( ERROR_OCCURRED( nil_packet_size_req( device->phone, device_id, & device->packet_dimension ))){
340 fibril_rwlock_write_unlock( & arp_globals.lock );
341 arp_protos_destroy( & device->protos );
342 free( device );
343 return ERROR_CODE;
344 }
345 // get hardware address
346 if( ERROR_OCCURRED( nil_get_addr_req( device->phone, device_id, & device->addr, & device->addr_data ))){
347 fibril_rwlock_write_unlock( & arp_globals.lock );
348 arp_protos_destroy( & device->protos );
349 free( device );
350 return ERROR_CODE;
351 }
352 // get broadcast address
353 if( ERROR_OCCURRED( nil_get_broadcast_addr_req( device->phone, device_id, & device->broadcast_addr, & device->broadcast_data ))){
354 fibril_rwlock_write_unlock( & arp_globals.lock );
355 free( device->addr );
356 free( device->addr_data );
357 arp_protos_destroy( & device->protos );
358 free( device );
359 return ERROR_CODE;
360 }
361 if( ERROR_OCCURRED( arp_cache_add( & arp_globals.cache, device->device_id, device ))){
362 fibril_rwlock_write_unlock( & arp_globals.lock );
363 free( device->addr );
364 free( device->addr_data );
365 free( device->broadcast_addr );
366 free( device->broadcast_data );
367 arp_protos_destroy( & device->protos );
368 free( device );
369 return ERROR_CODE;
370 }
371 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 );
372 }
373 fibril_rwlock_write_unlock( & arp_globals.lock );
374 return EOK;
375}
376
377measured_string_ref arp_translate_message( device_id_t device_id, services_t protocol, measured_string_ref target ){
378 arp_device_ref device;
379 arp_proto_ref proto;
380 measured_string_ref addr;
381 size_t length;
382 packet_t packet;
383 arp_header_ref header;
384
385 if( ! target ) return NULL;
386 device = arp_cache_find( & arp_globals.cache, device_id );
387 if( ! device ) return NULL;
388 proto = arp_protos_find( & device->protos, protocol );
389 if(( ! proto ) || ( proto->addr->length != target->length )) return NULL;
390 addr = arp_addr_find( & proto->addresses, target->value, target->length );
391 if( addr ) return addr;
392 // ARP packet content size = header + ( address + translation ) * 2
393 length = 8 + ( CONVERT_SIZE( char, uint8_t, proto->addr->length ) + CONVERT_SIZE( char, uint8_t, device->addr->length )) * 2;
394 if( length > device->packet_dimension.content ) return NULL;
395 packet = packet_get_4( arp_globals.net_phone, device->packet_dimension.addr_len, device->packet_dimension.prefix, length, device->packet_dimension.suffix );
396 if( ! packet ) return NULL;
397 header = ( arp_header_ref ) packet_suffix( packet, length );
398 if( ! header ){
399 pq_release( arp_globals.net_phone, packet_get_id( packet ));
400 return NULL;
401 }
402 header->hardware = htons( device->hardware );
403 header->hardware_length = ( uint8_t ) device->addr->length;
404 header->protocol = htons( protocol_map( device->service, protocol ));
405 header->protocol_length = ( uint8_t ) proto->addr->length;
406 header->operation = htons( ARPOP_REQUEST );
407 length = sizeof( arp_header_t );
408 memcpy((( uint8_t * ) header ) + length, device->addr->value, device->addr->length );
409 length += device->addr->length;
410 memcpy((( uint8_t * ) header ) + length, proto->addr->value, proto->addr->length );
411 length += proto->addr->length;
412 bzero((( uint8_t * ) header ) + length, device->addr->length );
413 length += device->addr->length;
414 memcpy((( uint8_t * ) header ) + length, target->value, target->length );
415 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 ){
416 pq_release( arp_globals.net_phone, packet_get_id( packet ));
417 return NULL;
418 }
419 nil_send_msg( device->phone, device_id, packet, SERVICE_ARP );
420 return NULL;
421}
422
423int arp_receive_message( device_id_t device_id, packet_t packet ){
424 ERROR_DECLARE;
425
426 size_t length;
427 arp_header_ref header;
428 arp_device_ref device;
429 arp_proto_ref proto;
430 measured_string_ref hw_source;
431 uint8_t * src_hw;
432 uint8_t * src_proto;
433 uint8_t * des_hw;
434 uint8_t * des_proto;
435
436 length = packet_get_data_length( packet );
437 if( length <= sizeof( arp_header_t )) return EINVAL;
438 device = arp_cache_find( & arp_globals.cache, device_id );
439 if( ! device ) return ENOENT;
440 header = ( arp_header_ref ) packet_get_data( packet );
441 if(( ntohs( header->hardware ) != device->hardware )
442 || ( length < sizeof( arp_header_t ) + header->hardware_length * 2u + header->protocol_length * 2u )){
443 return EINVAL;
444 }
445 proto = arp_protos_find( & device->protos, protocol_unmap( device->service, ntohs( header->protocol )));
446 if( ! proto ) return ENOENT;
447 src_hw = (( uint8_t * ) header ) + sizeof( arp_header_t );
448 src_proto = src_hw + header->hardware_length;
449 des_hw = src_proto + header->protocol_length;
450 des_proto = des_hw + header->hardware_length;
451 hw_source = arp_addr_find( & proto->addresses, ( char * ) src_proto, CONVERT_SIZE( uint8_t, char, header->protocol_length ));
452 // exists?
453 if( hw_source ){
454 if( hw_source->length != CONVERT_SIZE( uint8_t, char, header->hardware_length )){
455 return EINVAL;
456 }
457 memcpy( hw_source->value, src_hw, hw_source->length );
458 }
459 // is my protocol address?
460 if( proto->addr->length != CONVERT_SIZE( uint8_t, char, header->protocol_length )){
461 return EINVAL;
462 }
463 if( ! str_lcmp( proto->addr->value, ( char * ) des_proto, proto->addr->length )){
464 // not already upadted?
465 if( ! hw_source ){
466 hw_source = measured_string_create_bulk(( char * ) src_hw, CONVERT_SIZE( uint8_t, char, header->hardware_length ));
467 if( ! hw_source ) return ENOMEM;
468 ERROR_PROPAGATE( arp_addr_add( & proto->addresses, ( char * ) src_proto, CONVERT_SIZE( uint8_t, char, header->protocol_length ), hw_source ));
469 }
470 if( ntohs( header->operation ) == ARPOP_REQUEST ){
471 header->operation = htons( ARPOP_REPLY );
472 memcpy( des_proto, src_proto, header->protocol_length );
473 memcpy( src_proto, proto->addr->value, header->protocol_length );
474 memcpy( src_hw, device->addr->value, device->packet_dimension.addr_len );
475 memcpy( des_hw, hw_source->value, header->hardware_length );
476 ERROR_PROPAGATE( packet_set_addr( packet, src_hw, des_hw, header->hardware_length ));
477 nil_send_msg( device->phone, device_id, packet, SERVICE_ARP );
478 return 1;
479 }
480 }
481 return EOK;
482}
483
484void arp_clear_device( arp_device_ref device ){
485 int count;
486 arp_proto_ref proto;
487
488 for( count = arp_protos_count( & device->protos ) - 1; count >= 0; -- count ){
489 proto = arp_protos_get_index( & device->protos, count );
490 if( proto ){
491 if( proto->addr ) free( proto->addr );
492 if( proto->addr_data ) free( proto->addr_data );
493 arp_addr_destroy( & proto->addresses );
494 }
495 }
496 arp_protos_clear( & device->protos );
497}
498
499int arp_connect_module( services_t service ){
500 if( service != SERVICE_ARP ) return EINVAL;
501 return EOK;
502}
503
504int arp_mtu_changed_message( device_id_t device_id, size_t mtu ){
505 arp_device_ref device;
506
507 fibril_rwlock_write_lock( & arp_globals.lock );
508 device = arp_cache_find( & arp_globals.cache, device_id );
509 if( ! device ){
510 fibril_rwlock_write_unlock( & arp_globals.lock );
511 return ENOENT;
512 }
513 device->packet_dimension.content = mtu;
514 printf( "arp - device %d changed mtu to %d\n\n", device_id, mtu );
515 fibril_rwlock_write_unlock( & arp_globals.lock );
516 return EOK;
517}
518
519int arp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
520 ERROR_DECLARE;
521
522 measured_string_ref address;
523 measured_string_ref translation;
524 char * data;
525 packet_t packet;
526 packet_t next;
527
528// printf( "message %d - %d\n", IPC_GET_METHOD( * call ), NET_ARP_FIRST );
529 * answer_count = 0;
530 switch( IPC_GET_METHOD( * call )){
531 case IPC_M_PHONE_HUNGUP:
532 return EOK;
533 case NET_ARP_DEVICE:
534 ERROR_PROPAGATE( measured_strings_receive( & address, & data, 1 ));
535 if( ERROR_OCCURRED( arp_device_message( IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ), ARP_GET_NETIF( call ), address ))){
536 free( address );
537 free( data );
538 }
539 return ERROR_CODE;
540 case NET_ARP_TRANSLATE:
541 ERROR_PROPAGATE( measured_strings_receive( & address, & data, 1 ));
542 fibril_rwlock_read_lock( & arp_globals.lock );
543 translation = arp_translate_message( IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ), address );
544 free( address );
545 free( data );
546 if( ! translation ){
547 fibril_rwlock_read_unlock( & arp_globals.lock );
548 return ENOENT;
549 }
550 ERROR_CODE = measured_strings_reply( translation, 1 );
551 fibril_rwlock_read_unlock( & arp_globals.lock );
552 return ERROR_CODE;
553 case NET_ARP_CLEAR_DEVICE:
554 return arp_clear_device_req( 0, IPC_GET_DEVICE( call ));
555 case NET_ARP_CLEAR_ADDRESS:
556 ERROR_PROPAGATE( measured_strings_receive( & address, & data, 1 ));
557 arp_clear_address_req( 0, IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ), address );
558 free( address );
559 free( data );
560 return EOK;
561 case NET_ARP_CLEAN_CACHE:
562 return arp_clean_cache_req( 0 );
563 case NET_IL_DEVICE_STATE:
564 // do nothing - keep the cache
565 return EOK;
566 case NET_IL_RECEIVED:
567 if( ! ERROR_OCCURRED( packet_translate( arp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
568 fibril_rwlock_read_lock( & arp_globals.lock );
569 do{
570 next = pq_detach( packet );
571 ERROR_CODE = arp_receive_message( IPC_GET_DEVICE( call ), packet );
572 if( ERROR_CODE != 1 ) pq_release( arp_globals.net_phone, packet_get_id( packet ));
573 packet = next;
574 }while( packet );
575 fibril_rwlock_read_unlock( & arp_globals.lock );
576 }
577 return ERROR_CODE;
578 case NET_IL_MTU_CHANGED:
579 return arp_mtu_changed_message( IPC_GET_DEVICE( call ), IPC_GET_MTU( call ));
580 }
581 return ENOTSUP;
582}
583
584/** @}
585 */
Note: See TracBrowser for help on using the repository browser.