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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fa76f81 was 126daa2, checked in by Martin Decky <martin@…>, 14 years ago

cstyle

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