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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0a9ea4a was 87e373b, checked in by Jakub Jermar <jakub@…>, 15 years ago

Do not prevent new ARP requests to be made when the first one times out.
Add explanatory comments where useful.

  • Property mode set to 100644
File size: 23.7 KB
RevLine 
[21580dd]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
[e9caf47]30 * @{
[21580dd]31 */
32
33/** @file
[e9caf47]34 * ARP module implementation.
35 * @see arp.h
[21580dd]36 */
37
38#include <async.h>
39#include <malloc.h>
40#include <mem.h>
41#include <fibril_synch.h>
[87e373b]42#include <assert.h>
[21580dd]43#include <stdio.h>
[19f857a]44#include <str.h>
[21580dd]45#include <task.h>
[e9caf47]46#include <adt/measured_strings.h>
[21580dd]47#include <ipc/ipc.h>
48#include <ipc/services.h>
[514ee46]49#include <ipc/net.h>
[f87ec535]50#include <ipc/arp.h>
[522253c1]51#include <ipc/il.h>
[fe8dfa6]52#include <ipc/nil.h>
[2687bdb]53#include <byteorder.h>
[a852181]54#include <errno.h>
[c7a8442]55#include <net/modules.h>
[e526f08]56#include <net/device.h>
[e9caf47]57#include <net/packet.h>
[fe8dfa6]58#include <nil_remote.h>
[849ed54]59#include <protocol_map.h>
[0a866eeb]60#include <packet_client.h>
[14f1db0]61#include <packet_remote.h>
[797b704]62#include <il_remote.h>
63#include <il_skel.h>
64#include "arp.h"
[849ed54]65
[e9caf47]66/** ARP module name. */
[24ab58b3]67#define NAME "arp"
[21580dd]68
[fc3dba14]69/** Number of microseconds to wait for an ARP reply. */
[fe5a9fc]70#define ARP_TRANS_WAIT 1000000
[fc3dba14]71
[797b704]72/** @name ARP operation codes definitions */
73/*@{*/
74
75/** REQUEST operation code. */
76#define ARPOP_REQUEST 1
77
78/** REPLY operation code. */
79#define ARPOP_REPLY 2
80
81/*@}*/
82
83/** Type definition of an ARP protocol header.
84 * @see arp_header
85 */
86typedef struct arp_header arp_header_t;
87
88/** ARP protocol header. */
89struct arp_header {
90 /**
91 * Hardware type identifier.
92 * @see hardware.h
93 */
94 uint16_t hardware;
95
96 /** Protocol identifier. */
97 uint16_t protocol;
98 /** Hardware address length in bytes. */
99 uint8_t hardware_length;
100 /** Protocol address length in bytes. */
101 uint8_t protocol_length;
102
103 /**
104 * ARP packet type.
105 * @see arp_oc.h
106 */
107 uint16_t operation;
108} __attribute__ ((packed));
109
[e9caf47]110/** ARP global data. */
111arp_globals_t arp_globals;
[21580dd]112
[e9caf47]113DEVICE_MAP_IMPLEMENT(arp_cache, arp_device_t);
114INT_MAP_IMPLEMENT(arp_protos, arp_proto_t);
[fc3dba14]115GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, arp_trans_t);
116
117static void arp_clear_trans(arp_trans_t *trans)
118{
119 if (trans->hw_addr) {
120 free(trans->hw_addr);
121 trans->hw_addr = NULL;
122 }
[fe5a9fc]123
[fc3dba14]124 fibril_condvar_broadcast(&trans->cv);
125}
126
127static void arp_clear_addr(arp_addr_t *addresses)
128{
129 int count;
[fe5a9fc]130
[fc3dba14]131 for (count = arp_addr_count(addresses) - 1; count >= 0; count--) {
[fe5a9fc]132 arp_trans_t *trans = arp_addr_items_get_index(&addresses->values,
133 count);
[fc3dba14]134 if (trans)
135 arp_clear_trans(trans);
136 }
137}
138
[fe5a9fc]139/** Clear the device specific data.
[e9caf47]140 *
[fe5a9fc]141 * @param[in] device Device specific data.
[21580dd]142 */
[4e5c7ba]143static void arp_clear_device(arp_device_t *device)
[e9caf47]144{
145 int count;
[fe5a9fc]146
[e9caf47]147 for (count = arp_protos_count(&device->protos) - 1; count >= 0;
148 count--) {
[fe5a9fc]149 arp_proto_t *proto = arp_protos_get_index(&device->protos,
150 count);
151
[e9caf47]152 if (proto) {
153 if (proto->addr)
154 free(proto->addr);
[fe5a9fc]155
[e9caf47]156 if (proto->addr_data)
157 free(proto->addr_data);
[fe5a9fc]158
[fc3dba14]159 arp_clear_addr(&proto->addresses);
[e9caf47]160 arp_addr_destroy(&proto->addresses);
161 }
162 }
[fe5a9fc]163
[e9caf47]164 arp_protos_clear(&device->protos);
165}
[21580dd]166
[e9caf47]167static int arp_clean_cache_req(int arp_phone)
168{
[a64c64d]169 int count;
[fe5a9fc]170
[fc3dba14]171 fibril_mutex_lock(&arp_globals.lock);
[e9caf47]172 for (count = arp_cache_count(&arp_globals.cache) - 1; count >= 0;
173 count--) {
[fe5a9fc]174 arp_device_t *device = arp_cache_get_index(&arp_globals.cache,
175 count);
176
[e9caf47]177 if (device) {
[a64c64d]178 arp_clear_device(device);
[e9caf47]179 if (device->addr_data)
[a64c64d]180 free(device->addr_data);
[fe5a9fc]181
[e9caf47]182 if (device->broadcast_data)
[a64c64d]183 free(device->broadcast_data);
184 }
[21580dd]185 }
[fe5a9fc]186
[a64c64d]187 arp_cache_clear(&arp_globals.cache);
[fc3dba14]188 fibril_mutex_unlock(&arp_globals.lock);
[fe5a9fc]189
[21580dd]190 return EOK;
191}
192
[fb04cba8]193static int arp_clear_address_req(int arp_phone, device_id_t device_id,
[4eca056]194 services_t protocol, measured_string_t *address)
[e9caf47]195{
[fc3dba14]196 fibril_mutex_lock(&arp_globals.lock);
[fe5a9fc]197
198 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
[e9caf47]199 if (!device) {
[fc3dba14]200 fibril_mutex_unlock(&arp_globals.lock);
[21580dd]201 return ENOENT;
202 }
[fe5a9fc]203
204 arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
[e9caf47]205 if (!proto) {
[fc3dba14]206 fibril_mutex_unlock(&arp_globals.lock);
[21580dd]207 return ENOENT;
208 }
[fe5a9fc]209
210 arp_trans_t *trans = arp_addr_find(&proto->addresses, address->value,
211 address->length);
[fc3dba14]212 if (trans)
213 arp_clear_trans(trans);
[fe5a9fc]214
[aadf01e]215 arp_addr_exclude(&proto->addresses, address->value, address->length);
[fe5a9fc]216
[fc3dba14]217 fibril_mutex_unlock(&arp_globals.lock);
[21580dd]218 return EOK;
219}
220
[e9caf47]221static int arp_clear_device_req(int arp_phone, device_id_t device_id)
222{
[fc3dba14]223 fibril_mutex_lock(&arp_globals.lock);
[fe5a9fc]224
225 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
[e9caf47]226 if (!device) {
[fc3dba14]227 fibril_mutex_unlock(&arp_globals.lock);
[21580dd]228 return ENOENT;
229 }
[fe5a9fc]230
[a64c64d]231 arp_clear_device(device);
[fe5a9fc]232
[fc3dba14]233 fibril_mutex_unlock(&arp_globals.lock);
[21580dd]234 return EOK;
235}
236
[fe5a9fc]237/** Create new protocol specific data.
238 *
239 * Allocate and return the needed memory block as the proto parameter.
[e9caf47]240 *
[fe5a9fc]241 * @param[out] proto Allocated protocol specific data.
242 * @param[in] service Protocol module service.
243 * @param[in] address Actual protocol device address.
244 *
245 * @return EOK on success.
246 * @return ENOMEM if there is not enough memory left.
[e9caf47]247 *
248 */
[4e5c7ba]249static int arp_proto_create(arp_proto_t **proto, services_t service,
[4eca056]250 measured_string_t *address)
[e9caf47]251{
[4e5c7ba]252 *proto = (arp_proto_t *) malloc(sizeof(arp_proto_t));
[e9caf47]253 if (!*proto)
254 return ENOMEM;
[a852181]255
[e9caf47]256 (*proto)->service = service;
257 (*proto)->addr = address;
[61bfc370]258 (*proto)->addr_data = address->value;
[a852181]259
[fe5a9fc]260 int rc = arp_addr_initialize(&(*proto)->addresses);
[a852181]261 if (rc != EOK) {
[e9caf47]262 free(*proto);
[a852181]263 return rc;
[e9caf47]264 }
[a852181]265
[e9caf47]266 return EOK;
267}
268
[797b704]269/** Process the received ARP packet.
270 *
271 * Update the source hardware address if the source entry exists or the packet
272 * is targeted to my protocol address.
273 *
274 * Respond to the ARP request if the packet is the ARP request and is
275 * targeted to my address.
276 *
277 * @param[in] device_id Source device identifier.
278 * @param[in,out] packet Received packet.
279 *
280 * @return EOK on success and the packet is no longer needed.
281 * @return One on success and the packet has been reused.
282 * @return EINVAL if the packet is too small to carry an ARP
283 * packet.
284 * @return EINVAL if the received address lengths differs from
285 * the registered values.
286 * @return ENOENT if the device is not found in the cache.
287 * @return ENOENT if the protocol for the device is not found in
288 * the cache.
289 * @return ENOMEM if there is not enough memory left.
290 *
291 */
292static int arp_receive_message(device_id_t device_id, packet_t *packet)
293{
294 int rc;
295
296 size_t length = packet_get_data_length(packet);
297 if (length <= sizeof(arp_header_t))
298 return EINVAL;
299
300 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
301 if (!device)
302 return ENOENT;
303
304 arp_header_t *header = (arp_header_t *) packet_get_data(packet);
305 if ((ntohs(header->hardware) != device->hardware) ||
306 (length < sizeof(arp_header_t) + header->hardware_length * 2U +
307 header->protocol_length * 2U)) {
308 return EINVAL;
309 }
310
311 arp_proto_t *proto = arp_protos_find(&device->protos,
312 protocol_unmap(device->service, ntohs(header->protocol)));
313 if (!proto)
314 return ENOENT;
315
316 uint8_t *src_hw = ((uint8_t *) header) + sizeof(arp_header_t);
317 uint8_t *src_proto = src_hw + header->hardware_length;
318 uint8_t *des_hw = src_proto + header->protocol_length;
319 uint8_t *des_proto = des_hw + header->hardware_length;
320
321 arp_trans_t *trans = arp_addr_find(&proto->addresses, src_proto,
322 header->protocol_length);
323
324 if ((trans) && (trans->hw_addr)) {
325 /* Translation exists */
326 if (trans->hw_addr->length != header->hardware_length)
327 return EINVAL;
328
329 memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
330 }
331
332 /* Is my protocol address? */
333 if (proto->addr->length != header->protocol_length)
334 return EINVAL;
335
336 if (!bcmp(proto->addr->value, des_proto, proto->addr->length)) {
337 if (!trans) {
338 /* Update the translation */
339 trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
340 if (!trans)
341 return ENOMEM;
342
343 trans->hw_addr = NULL;
344 fibril_condvar_initialize(&trans->cv);
345 rc = arp_addr_add(&proto->addresses, src_proto,
346 header->protocol_length, trans);
347 if (rc != EOK) {
348 /* The generic char map has already freed trans! */
349 return rc;
350 }
351 }
352
353 if (!trans->hw_addr) {
354 trans->hw_addr = measured_string_create_bulk(src_hw,
355 header->hardware_length);
356 if (!trans->hw_addr)
357 return ENOMEM;
358
359 /* Notify the fibrils that wait for the translation. */
360 fibril_condvar_broadcast(&trans->cv);
361 }
362
363 if (ntohs(header->operation) == ARPOP_REQUEST) {
364 header->operation = htons(ARPOP_REPLY);
365 memcpy(des_proto, src_proto, header->protocol_length);
366 memcpy(src_proto, proto->addr->value,
367 header->protocol_length);
368 memcpy(src_hw, device->addr->value,
369 device->packet_dimension.addr_len);
370 memcpy(des_hw, trans->hw_addr->value,
371 header->hardware_length);
372
373 rc = packet_set_addr(packet, src_hw, des_hw,
374 header->hardware_length);
375 if (rc != EOK)
376 return rc;
377
378 nil_send_msg(device->phone, device_id, packet,
379 SERVICE_ARP);
380 return 1;
381 }
382 }
383
384 return EOK;
385}
386
387/** Update the device content length according to the new MTU value.
388 *
389 * @param[in] device_id Device identifier.
390 * @param[in] mtu New MTU value.
391 *
392 * @return ENOENT if device is not found.
393 * @return EOK on success.
394 *
395 */
396static int arp_mtu_changed_message(device_id_t device_id, size_t mtu)
397{
398 fibril_mutex_lock(&arp_globals.lock);
399
400 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
401 if (!device) {
402 fibril_mutex_unlock(&arp_globals.lock);
403 return ENOENT;
404 }
405
406 device->packet_dimension.content = mtu;
407
408 fibril_mutex_unlock(&arp_globals.lock);
409
410 printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
411
412 return EOK;
413}
414
415/** Process IPC messages from the registered device driver modules
416 *
417 * @param[in] iid Message identifier.
418 * @param[in,out] icall Message parameters.
419 *
420 */
421static void arp_receiver(ipc_callid_t iid, ipc_call_t *icall)
422{
423 packet_t *packet;
424 int rc;
425
426 while (true) {
427 switch (IPC_GET_IMETHOD(*icall)) {
428 case NET_IL_DEVICE_STATE:
429 /* Do nothing - keep the cache */
430 ipc_answer_0(iid, (sysarg_t) EOK);
431 break;
432
433 case NET_IL_RECEIVED:
434 rc = packet_translate_remote(arp_globals.net_phone, &packet,
435 IPC_GET_PACKET(*icall));
436 if (rc == EOK) {
437 fibril_mutex_lock(&arp_globals.lock);
438 do {
439 packet_t *next = pq_detach(packet);
440 rc = arp_receive_message(IPC_GET_DEVICE(*icall), packet);
441 if (rc != 1) {
442 pq_release_remote(arp_globals.net_phone,
443 packet_get_id(packet));
444 }
445
446 packet = next;
447 } while (packet);
448 fibril_mutex_unlock(&arp_globals.lock);
449 }
450 ipc_answer_0(iid, (sysarg_t) rc);
451 break;
452
453 case NET_IL_MTU_CHANGED:
454 rc = arp_mtu_changed_message(IPC_GET_DEVICE(*icall),
455 IPC_GET_MTU(*icall));
456 ipc_answer_0(iid, (sysarg_t) rc);
457 break;
458
459 default:
460 ipc_answer_0(iid, (sysarg_t) ENOTSUP);
461 }
462
463 iid = async_get_call(icall);
464 }
465}
466
[fe5a9fc]467/** Register the device.
[e9caf47]468 *
[fe5a9fc]469 * Create new device entry in the cache or update the protocol address if the
[e9caf47]470 * device with the device identifier and the driver service exists.
471 *
[fe5a9fc]472 * @param[in] device_id Device identifier.
473 * @param[in] service Device driver service.
474 * @param[in] protocol Protocol service.
475 * @param[in] address Actual device protocol address.
476 *
477 * @return EOK on success.
478 * @return EEXIST if another device with the same device identifier
479 * and different driver service exists.
480 * @return ENOMEM if there is not enough memory left.
481 * @return Other error codes as defined for the
482 * measured_strings_return() function.
483 *
[e9caf47]484 */
[fb04cba8]485static int arp_device_message(device_id_t device_id, services_t service,
[4eca056]486 services_t protocol, measured_string_t *address)
[e9caf47]487{
[a852181]488 int index;
489 int rc;
[fe5a9fc]490
[fc3dba14]491 fibril_mutex_lock(&arp_globals.lock);
[fe5a9fc]492
[fb04cba8]493 /* An existing device? */
[fe5a9fc]494 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
[e9caf47]495 if (device) {
496 if (device->service != service) {
[fe5a9fc]497 printf("%s: Device %d already exists\n", NAME,
498 device->device_id);
[fc3dba14]499 fibril_mutex_unlock(&arp_globals.lock);
[21580dd]500 return EEXIST;
501 }
[fe5a9fc]502
503 arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
[e9caf47]504 if (proto) {
[aadf01e]505 free(proto->addr);
506 free(proto->addr_data);
[21580dd]507 proto->addr = address;
[61bfc370]508 proto->addr_data = address->value;
[e9caf47]509 } else {
[a852181]510 rc = arp_proto_create(&proto, protocol, address);
511 if (rc != EOK) {
[fc3dba14]512 fibril_mutex_unlock(&arp_globals.lock);
[a852181]513 return rc;
[21580dd]514 }
[fe5a9fc]515
[e9caf47]516 index = arp_protos_add(&device->protos, proto->service,
517 proto);
518 if (index < 0) {
[fc3dba14]519 fibril_mutex_unlock(&arp_globals.lock);
[aadf01e]520 free(proto);
[21580dd]521 return index;
522 }
[fe5a9fc]523
524 printf("%s: New protocol added (id: %d, proto: %d)\n", NAME,
525 device_id, protocol);
[21580dd]526 }
[e9caf47]527 } else {
[fe5a9fc]528 hw_type_t hardware = hardware_map(service);
[e9caf47]529 if (!hardware)
[aadf01e]530 return ENOENT;
[e9caf47]531
[fe5a9fc]532 /* Create new device */
[4e5c7ba]533 device = (arp_device_t *) malloc(sizeof(arp_device_t));
[e9caf47]534 if (!device) {
[fc3dba14]535 fibril_mutex_unlock(&arp_globals.lock);
[21580dd]536 return ENOMEM;
537 }
[fe5a9fc]538
[21580dd]539 device->hardware = hardware;
540 device->device_id = device_id;
[a852181]541 rc = arp_protos_initialize(&device->protos);
542 if (rc != EOK) {
[fc3dba14]543 fibril_mutex_unlock(&arp_globals.lock);
[a852181]544 free(device);
545 return rc;
546 }
[fe5a9fc]547
548 arp_proto_t *proto;
[a852181]549 rc = arp_proto_create(&proto, protocol, address);
550 if (rc != EOK) {
[fc3dba14]551 fibril_mutex_unlock(&arp_globals.lock);
[aadf01e]552 free(device);
[a852181]553 return rc;
[21580dd]554 }
[fe5a9fc]555
[aadf01e]556 index = arp_protos_add(&device->protos, proto->service, proto);
[e9caf47]557 if (index < 0) {
[fc3dba14]558 fibril_mutex_unlock(&arp_globals.lock);
[aadf01e]559 arp_protos_destroy(&device->protos);
560 free(device);
[21580dd]561 return index;
562 }
[fe5a9fc]563
[21580dd]564 device->service = service;
[e9caf47]565
[fe5a9fc]566 /* Bind */
[e9caf47]567 device->phone = nil_bind_service(device->service,
[96b02eb9]568 (sysarg_t) device->device_id, SERVICE_ARP,
[797b704]569 arp_receiver);
[e9caf47]570 if (device->phone < 0) {
[fc3dba14]571 fibril_mutex_unlock(&arp_globals.lock);
[aadf01e]572 arp_protos_destroy(&device->protos);
573 free(device);
[21580dd]574 return EREFUSED;
575 }
[e9caf47]576
[fb04cba8]577 /* Get packet dimensions */
[a852181]578 rc = nil_packet_size_req(device->phone, device_id,
579 &device->packet_dimension);
580 if (rc != EOK) {
[fc3dba14]581 fibril_mutex_unlock(&arp_globals.lock);
[aadf01e]582 arp_protos_destroy(&device->protos);
583 free(device);
[a852181]584 return rc;
[21580dd]585 }
[e9caf47]586
[fb04cba8]587 /* Get hardware address */
[a852181]588 rc = nil_get_addr_req(device->phone, device_id, &device->addr,
589 &device->addr_data);
590 if (rc != EOK) {
[fc3dba14]591 fibril_mutex_unlock(&arp_globals.lock);
[aadf01e]592 arp_protos_destroy(&device->protos);
593 free(device);
[a852181]594 return rc;
[21580dd]595 }
[e9caf47]596
[fb04cba8]597 /* Get broadcast address */
[a852181]598 rc = nil_get_broadcast_addr_req(device->phone, device_id,
599 &device->broadcast_addr, &device->broadcast_data);
600 if (rc != EOK) {
[fc3dba14]601 fibril_mutex_unlock(&arp_globals.lock);
[aadf01e]602 free(device->addr);
603 free(device->addr_data);
604 arp_protos_destroy(&device->protos);
605 free(device);
[a852181]606 return rc;
[21580dd]607 }
[e9caf47]608
[a852181]609 rc = arp_cache_add(&arp_globals.cache, device->device_id,
610 device);
611 if (rc != EOK) {
[fc3dba14]612 fibril_mutex_unlock(&arp_globals.lock);
[aadf01e]613 free(device->addr);
614 free(device->addr_data);
615 free(device->broadcast_addr);
616 free(device->broadcast_data);
617 arp_protos_destroy(&device->protos);
618 free(device);
[a852181]619 return rc;
[21580dd]620 }
[e9caf47]621 printf("%s: Device registered (id: %d, type: 0x%x, service: %d,"
622 " proto: %d)\n", NAME, device->device_id, device->hardware,
623 device->service, protocol);
[21580dd]624 }
[e9caf47]625
[fe5a9fc]626 fibril_mutex_unlock(&arp_globals.lock);
[21580dd]627 return EOK;
628}
629
[797b704]630int il_initialize(int net_phone)
[e9caf47]631{
[fc3dba14]632 fibril_mutex_initialize(&arp_globals.lock);
[fe5a9fc]633
[fc3dba14]634 fibril_mutex_lock(&arp_globals.lock);
[797b704]635 arp_globals.net_phone = net_phone;
[fe5a9fc]636 int rc = arp_cache_initialize(&arp_globals.cache);
[fc3dba14]637 fibril_mutex_unlock(&arp_globals.lock);
[a852181]638
639 return rc;
[a64c64d]640}
641
[597c948]642static int arp_send_request(device_id_t device_id, services_t protocol,
643 measured_string_t *target, arp_device_t *device, arp_proto_t *proto)
644{
645 /* ARP packet content size = header + (address + translation) * 2 */
646 size_t length = 8 + 2 * (proto->addr->length + device->addr->length);
647 if (length > device->packet_dimension.content)
648 return ELIMIT;
649
650 packet_t *packet = packet_get_4_remote(arp_globals.net_phone,
651 device->packet_dimension.addr_len, device->packet_dimension.prefix,
652 length, device->packet_dimension.suffix);
653 if (!packet)
654 return ENOMEM;
655
656 arp_header_t *header = (arp_header_t *) packet_suffix(packet, length);
657 if (!header) {
658 pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
659 return ENOMEM;
660 }
661
662 header->hardware = htons(device->hardware);
663 header->hardware_length = (uint8_t) device->addr->length;
664 header->protocol = htons(protocol_map(device->service, protocol));
665 header->protocol_length = (uint8_t) proto->addr->length;
666 header->operation = htons(ARPOP_REQUEST);
[fe5a9fc]667
[597c948]668 length = sizeof(arp_header_t);
[fe5a9fc]669
[597c948]670 memcpy(((uint8_t *) header) + length, device->addr->value,
671 device->addr->length);
672 length += device->addr->length;
673 memcpy(((uint8_t *) header) + length, proto->addr->value,
674 proto->addr->length);
675 length += proto->addr->length;
676 bzero(((uint8_t *) header) + length, device->addr->length);
677 length += device->addr->length;
678 memcpy(((uint8_t *) header) + length, target->value, target->length);
679
680 int rc = packet_set_addr(packet, (uint8_t *) device->addr->value,
681 (uint8_t *) device->broadcast_addr->value, device->addr->length);
682 if (rc != EOK) {
683 pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
684 return rc;
685 }
686
687 nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
688 return EOK;
689}
[e9caf47]690
[597c948]691/** Return the hardware address for the given protocol address.
[e9caf47]692 *
[597c948]693 * Send the ARP request packet if the hardware address is not found in the
[e9caf47]694 * cache.
695 *
[597c948]696 * @param[in] device_id Device identifier.
697 * @param[in] protocol Protocol service.
698 * @param[in] target Target protocol address.
[3bb5735]699 * @param[out] translation Where the hardware address of the target is stored.
[597c948]700 *
701 * @return EOK on success.
702 * @return EAGAIN if the caller should try again.
703 * @return Other error codes in case of error.
704 *
[e9caf47]705 */
[fe5a9fc]706static int arp_translate_message(device_id_t device_id, services_t protocol,
[3bb5735]707 measured_string_t *target, measured_string_t **translation)
[e9caf47]708{
[fc3dba14]709 bool retry = false;
[3bb5735]710 int rc;
[87e373b]711
712 assert(fibril_mutex_is_locked(&arp_globals.lock));
[597c948]713
[fc3dba14]714restart:
[597c948]715 if ((!target) || (!translation))
[3bb5735]716 return EBADMEM;
[597c948]717
[fe5a9fc]718 arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
[e9caf47]719 if (!device)
[3bb5735]720 return ENOENT;
[597c948]721
[fe5a9fc]722 arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
[597c948]723 if ((!proto) || (proto->addr->length != target->length))
[3bb5735]724 return ENOENT;
[597c948]725
[fe5a9fc]726 arp_trans_t *trans = arp_addr_find(&proto->addresses, target->value,
727 target->length);
[fc3dba14]728 if (trans) {
729 if (trans->hw_addr) {
[87e373b]730 /* The translation is in place. */
[fc3dba14]731 *translation = trans->hw_addr;
732 return EOK;
733 }
[597c948]734
[fe5a9fc]735 if (retry) {
[87e373b]736 /*
737 * We may get here as a result of being signalled for
738 * some reason while waiting for the translation (e.g.
739 * translation becoming available, record being removed
740 * from the table) and then losing the race for
741 * the arp_globals.lock with someone else who modified
742 * the table.
743 *
744 * Remove the incomplete record so that it is possible
745 * to make new ARP requests.
746 */
[fe5a9fc]747 arp_clear_trans(trans);
748 arp_addr_exclude(&proto->addresses, target->value,
749 target->length);
[fc3dba14]750 return EAGAIN;
[fe5a9fc]751 }
[597c948]752
[87e373b]753 /*
754 * We are a random passer-by who merely joins an already waiting
755 * fibril in waiting for the translation.
756 */
[fc3dba14]757 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
758 ARP_TRANS_WAIT);
759 if (rc == ETIMEOUT)
760 return ENOENT;
[597c948]761
[87e373b]762 /*
763 * Need to recheck because we did not hold the lock while
764 * sleeping on the condition variable.
765 */
[fc3dba14]766 retry = true;
767 goto restart;
[3bb5735]768 }
[597c948]769
[fc3dba14]770 if (retry)
771 return EAGAIN;
[87e373b]772
773 /*
774 * We are under the protection of arp_globals.lock, so we can afford to
775 * first send the ARP request and then insert an incomplete ARP record.
776 * The incomplete record is used to tell any other potential waiter
777 * that this fibril has already sent the request and that it is waiting
778 * for the answer. Lastly, any fibril which sees the incomplete request
779 * can perform a timed wait on its condition variable to wait for the
780 * ARP reply to arrive.
781 */
782
783 rc = arp_send_request(device_id, protocol, target, device, proto);
784 if (rc != EOK)
785 return rc;
[597c948]786
[fc3dba14]787 trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
788 if (!trans)
789 return ENOMEM;
[fe5a9fc]790
[fc3dba14]791 trans->hw_addr = NULL;
792 fibril_condvar_initialize(&trans->cv);
[fe5a9fc]793
[fc3dba14]794 rc = arp_addr_add(&proto->addresses, target->value, target->length,
795 trans);
796 if (rc != EOK) {
797 /* The generic char map has already freed trans! */
798 return rc;
799 }
800
801 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
802 ARP_TRANS_WAIT);
[87e373b]803 if (rc == ETIMEOUT) {
804 /*
805 * Remove the incomplete record so that it is possible to make
806 * new ARP requests.
807 */
808 arp_clear_trans(trans);
809 arp_addr_exclude(&proto->addresses, target->value,
810 target->length);
[fc3dba14]811 return ENOENT;
[87e373b]812 }
[597c948]813
[87e373b]814 /*
815 * We need to recheck that the translation has indeed become available,
816 * because we dropped the arp_globals.lock while sleeping on the
817 * condition variable and someone else might have e.g. removed the
818 * translation before we managed to lock arp_globals.lock again.
819 */
820
[fc3dba14]821 retry = true;
822 goto restart;
[21580dd]823}
824
[fe5a9fc]825/** Process the ARP message.
[849ed54]826 *
[fe5a9fc]827 * @param[in] callid Message identifier.
828 * @param[in] call Message parameters.
829 * @param[out] answer Answer.
830 * @param[out] count Number of arguments of the answer.
831 *
832 * @return EOK on success.
833 * @return ENOTSUP if the message is not known.
[849ed54]834 *
[e9caf47]835 * @see arp_interface.h
836 * @see IS_NET_ARP_MESSAGE()
[fe5a9fc]837 *
[849ed54]838 */
[797b704]839int il_module_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
[fe5a9fc]840 size_t *count)
[e9caf47]841{
[4eca056]842 measured_string_t *address;
843 measured_string_t *translation;
[61bfc370]844 uint8_t *data;
[a852181]845 int rc;
[e9caf47]846
[fe5a9fc]847 *count = 0;
[228e490]848 switch (IPC_GET_IMETHOD(*call)) {
[e9caf47]849 case IPC_M_PHONE_HUNGUP:
850 return EOK;
851
852 case NET_ARP_DEVICE:
[a852181]853 rc = measured_strings_receive(&address, &data, 1);
854 if (rc != EOK)
855 return rc;
856
[774e6d1a]857 rc = arp_device_message(IPC_GET_DEVICE(*call),
858 IPC_GET_SERVICE(*call), ARP_GET_NETIF(*call), address);
[a852181]859 if (rc != EOK) {
[e9caf47]860 free(address);
861 free(data);
862 }
[fe5a9fc]863
[a852181]864 return rc;
[e9caf47]865
866 case NET_ARP_TRANSLATE:
[a852181]867 rc = measured_strings_receive(&address, &data, 1);
868 if (rc != EOK)
869 return rc;
870
[fc3dba14]871 fibril_mutex_lock(&arp_globals.lock);
[774e6d1a]872 rc = arp_translate_message(IPC_GET_DEVICE(*call),
873 IPC_GET_SERVICE(*call), address, &translation);
[e9caf47]874 free(address);
875 free(data);
[fe5a9fc]876
[3bb5735]877 if (rc != EOK) {
[fc3dba14]878 fibril_mutex_unlock(&arp_globals.lock);
[3bb5735]879 return rc;
880 }
[fe5a9fc]881
[e9caf47]882 if (!translation) {
[fc3dba14]883 fibril_mutex_unlock(&arp_globals.lock);
[e9caf47]884 return ENOENT;
885 }
[fe5a9fc]886
[a852181]887 rc = measured_strings_reply(translation, 1);
[fc3dba14]888 fibril_mutex_unlock(&arp_globals.lock);
[a852181]889 return rc;
[fe5a9fc]890
[e9caf47]891 case NET_ARP_CLEAR_DEVICE:
[774e6d1a]892 return arp_clear_device_req(0, IPC_GET_DEVICE(*call));
[fe5a9fc]893
[e9caf47]894 case NET_ARP_CLEAR_ADDRESS:
[a852181]895 rc = measured_strings_receive(&address, &data, 1);
896 if (rc != EOK)
897 return rc;
898
[774e6d1a]899 arp_clear_address_req(0, IPC_GET_DEVICE(*call),
900 IPC_GET_SERVICE(*call), address);
[e9caf47]901 free(address);
902 free(data);
903 return EOK;
904
905 case NET_ARP_CLEAN_CACHE:
906 return arp_clean_cache_req(0);
907 }
908
909 return ENOTSUP;
910}
911
[849ed54]912int main(int argc, char *argv[])
913{
914 /* Start the module */
[797b704]915 return il_module_start(SERVICE_ARP);
[849ed54]916}
917
[21580dd]918/** @}
919 */
Note: See TracBrowser for help on using the repository browser.