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

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

more unification of basic types

  • use sysarg_t and native_t (unsigned and signed variant) in both kernel and uspace
  • remove ipcarg_t in favour of sysarg_t

(no change in functionality)

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