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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 61bfc370 was 61bfc370, checked in by Martin Decky <martin@…>, 14 years ago
  • make measured_string and other network-related data types binary-safe
  • fix several network-related routines binary-safe (replace clearly suspicious use of str_lcmp() with bcmp())
  • rename spawn() to net_spawn()
  • Property mode set to 100644
File size: 22.1 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;
[61bfc370]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;
[61bfc370]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;
[61bfc370]484 trans = arp_addr_find(&proto->addresses, src_proto,
[7837101]485 header->protocol_length);
[fb04cba8]486 /* Exists? */
[fc3dba14]487 if (trans && trans->hw_addr) {
[7837101]488 if (trans->hw_addr->length != header->hardware_length)
[21580dd]489 return EINVAL;
[fc3dba14]490 memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
[21580dd]491 }
[fb04cba8]492 /* Is my protocol address? */
[7837101]493 if (proto->addr->length != header->protocol_length)
[21580dd]494 return EINVAL;
[61bfc370]495
496 if (!bcmp(proto->addr->value, des_proto, proto->addr->length)) {
[fb04cba8]497 /* Not already updated? */
[fc3dba14]498 if (!trans) {
499 trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
500 if (!trans)
[aadf01e]501 return ENOMEM;
[fc3dba14]502 trans->hw_addr = NULL;
503 fibril_condvar_initialize(&trans->cv);
[61bfc370]504 rc = arp_addr_add(&proto->addresses, src_proto,
[7837101]505 header->protocol_length, trans);
[fc3dba14]506 if (rc != EOK) {
507 /* The generic char map has already freed trans! */
[a852181]508 return rc;
[fc3dba14]509 }
510 }
511 if (!trans->hw_addr) {
[61bfc370]512 trans->hw_addr = measured_string_create_bulk(src_hw,
513 header->hardware_length);
[fc3dba14]514 if (!trans->hw_addr)
515 return ENOMEM;
[61bfc370]516
[fc3dba14]517 /* Notify the fibrils that wait for the translation. */
518 fibril_condvar_broadcast(&trans->cv);
[21580dd]519 }
[e9caf47]520 if (ntohs(header->operation) == ARPOP_REQUEST) {
[aadf01e]521 header->operation = htons(ARPOP_REPLY);
522 memcpy(des_proto, src_proto, header->protocol_length);
[e9caf47]523 memcpy(src_proto, proto->addr->value,
524 header->protocol_length);
525 memcpy(src_hw, device->addr->value,
526 device->packet_dimension.addr_len);
[fc3dba14]527 memcpy(des_hw, trans->hw_addr->value,
[e9caf47]528 header->hardware_length);
[a852181]529
530 rc = packet_set_addr(packet, src_hw, des_hw,
531 header->hardware_length);
532 if (rc != EOK)
533 return rc;
534
[e9caf47]535 nil_send_msg(device->phone, device_id, packet,
536 SERVICE_ARP);
[21580dd]537 return 1;
538 }
539 }
[e9caf47]540
[21580dd]541 return EOK;
542}
543
[e9caf47]544
545/** Returns the hardware address for the given protocol address.
546 *
547 * Sends the ARP request packet if the hardware address is not found in the
548 * cache.
549 *
550 * @param[in] device_id The device identifier.
551 * @param[in] protocol The protocol service.
552 * @param[in] target The target protocol address.
[3bb5735]553 * @param[out] translation Where the hardware address of the target is stored.
554 * @return EOK on success.
555 * @return EAGAIN if the caller should try again.
556 * @return Other error codes in case of error.
[e9caf47]557 */
[3bb5735]558static int
[e9caf47]559arp_translate_message(device_id_t device_id, services_t protocol,
[3bb5735]560 measured_string_t *target, measured_string_t **translation)
[e9caf47]561{
[4e5c7ba]562 arp_device_t *device;
563 arp_proto_t *proto;
[fc3dba14]564 arp_trans_t *trans;
[a64c64d]565 size_t length;
[46d4d9f]566 packet_t *packet;
[4e5c7ba]567 arp_header_t *header;
[fc3dba14]568 bool retry = false;
[3bb5735]569 int rc;
[21580dd]570
[fc3dba14]571restart:
[3bb5735]572 if (!target || !translation)
573 return EBADMEM;
[e9caf47]574
[aadf01e]575 device = arp_cache_find(&arp_globals.cache, device_id);
[e9caf47]576 if (!device)
[3bb5735]577 return ENOENT;
[e9caf47]578
[a64c64d]579 proto = arp_protos_find(&device->protos, protocol);
[e9caf47]580 if (!proto || (proto->addr->length != target->length))
[3bb5735]581 return ENOENT;
[e9caf47]582
[fc3dba14]583 trans = arp_addr_find(&proto->addresses, target->value, target->length);
584 if (trans) {
585 if (trans->hw_addr) {
586 *translation = trans->hw_addr;
587 return EOK;
588 }
589 if (retry)
590 return EAGAIN;
591 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
592 ARP_TRANS_WAIT);
593 if (rc == ETIMEOUT)
594 return ENOENT;
595 retry = true;
596 goto restart;
[3bb5735]597 }
[fc3dba14]598 if (retry)
599 return EAGAIN;
[e9caf47]600
[fb04cba8]601 /* ARP packet content size = header + (address + translation) * 2 */
[7837101]602 length = 8 + 2 * (proto->addr->length + device->addr->length);
[e9caf47]603 if (length > device->packet_dimension.content)
[3bb5735]604 return ELIMIT;
[e9caf47]605
606 packet = packet_get_4_remote(arp_globals.net_phone,
607 device->packet_dimension.addr_len, device->packet_dimension.prefix,
608 length, device->packet_dimension.suffix);
609 if (!packet)
[3bb5735]610 return ENOMEM;
[e9caf47]611
[4e5c7ba]612 header = (arp_header_t *) packet_suffix(packet, length);
[e9caf47]613 if (!header) {
[14f1db0]614 pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
[3bb5735]615 return ENOMEM;
[a64c64d]616 }
[e9caf47]617
[a64c64d]618 header->hardware = htons(device->hardware);
619 header->hardware_length = (uint8_t) device->addr->length;
620 header->protocol = htons(protocol_map(device->service, protocol));
621 header->protocol_length = (uint8_t) proto->addr->length;
622 header->operation = htons(ARPOP_REQUEST);
623 length = sizeof(arp_header_t);
[e9caf47]624 memcpy(((uint8_t *) header) + length, device->addr->value,
625 device->addr->length);
[a64c64d]626 length += device->addr->length;
[e9caf47]627 memcpy(((uint8_t *) header) + length, proto->addr->value,
628 proto->addr->length);
[a64c64d]629 length += proto->addr->length;
630 bzero(((uint8_t *) header) + length, device->addr->length);
631 length += device->addr->length;
632 memcpy(((uint8_t *) header) + length, target->value, target->length);
[e9caf47]633
[3bb5735]634 rc = packet_set_addr(packet, (uint8_t *) device->addr->value,
[7837101]635 (uint8_t *) device->broadcast_addr->value, device->addr->length);
[3bb5735]636 if (rc != EOK) {
[14f1db0]637 pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
[3bb5735]638 return rc;
[a64c64d]639 }
[e9caf47]640
[a64c64d]641 nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
[fc3dba14]642
643 trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
644 if (!trans)
645 return ENOMEM;
646 trans->hw_addr = NULL;
647 fibril_condvar_initialize(&trans->cv);
648 rc = arp_addr_add(&proto->addresses, target->value, target->length,
649 trans);
650 if (rc != EOK) {
651 /* The generic char map has already freed trans! */
652 return rc;
653 }
654
655 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
656 ARP_TRANS_WAIT);
657 if (rc == ETIMEOUT)
658 return ENOENT;
659 retry = true;
660 goto restart;
[21580dd]661}
662
[e9caf47]663
664/** Processes the ARP message.
[849ed54]665 *
[e9caf47]666 * @param[in] callid The message identifier.
667 * @param[in] call The message parameters.
668 * @param[out] answer The message answer parameters.
669 * @param[out] answer_count The last parameter for the actual answer in the
670 * answer parameter.
[1bfd3d3]671 * @return EOK on success.
672 * @return ENOTSUP if the message is not known.
[849ed54]673 *
[e9caf47]674 * @see arp_interface.h
675 * @see IS_NET_ARP_MESSAGE()
[849ed54]676 */
[e9caf47]677int
678arp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
679 ipc_call_t *answer, int *answer_count)
680{
[4eca056]681 measured_string_t *address;
682 measured_string_t *translation;
[61bfc370]683 uint8_t *data;
[46d4d9f]684 packet_t *packet;
685 packet_t *next;
[a852181]686 int rc;
[e9caf47]687
688 *answer_count = 0;
[228e490]689 switch (IPC_GET_IMETHOD(*call)) {
[e9caf47]690 case IPC_M_PHONE_HUNGUP:
691 return EOK;
692
693 case NET_ARP_DEVICE:
[a852181]694 rc = measured_strings_receive(&address, &data, 1);
695 if (rc != EOK)
696 return rc;
697
698 rc = arp_device_message(IPC_GET_DEVICE(call),
699 IPC_GET_SERVICE(call), ARP_GET_NETIF(call), address);
700 if (rc != EOK) {
[e9caf47]701 free(address);
702 free(data);
703 }
[a852181]704 return rc;
[e9caf47]705
706 case NET_ARP_TRANSLATE:
[a852181]707 rc = measured_strings_receive(&address, &data, 1);
708 if (rc != EOK)
709 return rc;
710
[fc3dba14]711 fibril_mutex_lock(&arp_globals.lock);
[3bb5735]712 rc = arp_translate_message(IPC_GET_DEVICE(call),
713 IPC_GET_SERVICE(call), address, &translation);
[e9caf47]714 free(address);
715 free(data);
[3bb5735]716 if (rc != EOK) {
[fc3dba14]717 fibril_mutex_unlock(&arp_globals.lock);
[3bb5735]718 return rc;
719 }
[e9caf47]720 if (!translation) {
[fc3dba14]721 fibril_mutex_unlock(&arp_globals.lock);
[e9caf47]722 return ENOENT;
723 }
[a852181]724 rc = measured_strings_reply(translation, 1);
[fc3dba14]725 fibril_mutex_unlock(&arp_globals.lock);
[a852181]726 return rc;
[e9caf47]727
728 case NET_ARP_CLEAR_DEVICE:
729 return arp_clear_device_req(0, IPC_GET_DEVICE(call));
730
731 case NET_ARP_CLEAR_ADDRESS:
[a852181]732 rc = measured_strings_receive(&address, &data, 1);
733 if (rc != EOK)
734 return rc;
735
[e9caf47]736 arp_clear_address_req(0, IPC_GET_DEVICE(call),
737 IPC_GET_SERVICE(call), address);
738 free(address);
739 free(data);
740 return EOK;
741
742 case NET_ARP_CLEAN_CACHE:
743 return arp_clean_cache_req(0);
744
745 case NET_IL_DEVICE_STATE:
[fb04cba8]746 /* Do nothing - keep the cache */
[e9caf47]747 return EOK;
748
749 case NET_IL_RECEIVED:
[61bfc370]750
[a852181]751 rc = packet_translate_remote(arp_globals.net_phone, &packet,
752 IPC_GET_PACKET(call));
753 if (rc != EOK)
754 return rc;
755
[fc3dba14]756 fibril_mutex_lock(&arp_globals.lock);
[a852181]757 do {
758 next = pq_detach(packet);
759 rc = arp_receive_message(IPC_GET_DEVICE(call), packet);
760 if (rc != 1) {
761 pq_release_remote(arp_globals.net_phone,
762 packet_get_id(packet));
763 }
764 packet = next;
765 } while (packet);
[fc3dba14]766 fibril_mutex_unlock(&arp_globals.lock);
[a852181]767
768 return EOK;
[e9caf47]769
770 case NET_IL_MTU_CHANGED:
771 return arp_mtu_changed_message(IPC_GET_DEVICE(call),
772 IPC_GET_MTU(call));
773 }
774
775 return ENOTSUP;
776}
777
778/** Default thread for new connections.
779 *
780 * @param[in] iid The initial message identifier.
781 * @param[in] icall The initial message call structure.
782 */
783static void il_client_connection(ipc_callid_t iid, ipc_call_t *icall)
[849ed54]784{
785 /*
786 * Accept the connection
787 * - Answer the first IPC_M_CONNECT_ME_TO call.
788 */
789 ipc_answer_0(iid, EOK);
790
[e9caf47]791 while (true) {
[849ed54]792 ipc_call_t answer;
793 int answer_count;
794
795 /* Clear the answer structure */
796 refresh_answer(&answer, &answer_count);
797
798 /* Fetch the next message */
799 ipc_call_t call;
800 ipc_callid_t callid = async_get_call(&call);
801
802 /* Process the message */
[14f1db0]803 int res = il_module_message_standalone(callid, &call, &answer,
804 &answer_count);
[849ed54]805
[e9caf47]806 /*
807 * End if told to either by the message or the processing
808 * result.
809 */
[228e490]810 if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
[e9caf47]811 (res == EHANGUP))
[849ed54]812 return;
813
814 /* Answer the message */
815 answer_call(callid, res, &answer, answer_count);
816 }
817}
818
819/** Starts the module.
820 *
[1bfd3d3]821 * @return EOK on success.
822 * @return Other error codes as defined for each specific module
[e9caf47]823 * start function.
[849ed54]824 */
825int main(int argc, char *argv[])
826{
[a852181]827 int rc;
[849ed54]828
829 /* Start the module */
[a852181]830 rc = il_module_start_standalone(il_client_connection);
831 return rc;
[849ed54]832}
833
[21580dd]834/** @}
835 */
[e9caf47]836
Note: See TracBrowser for help on using the repository browser.