arp.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Lukas Mejdrech
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include <async.h>
00039 #include <malloc.h>
00040 #include <mem.h>
00041 #include <fibril_synch.h>
00042 #include <assert.h>
00043 #include <stdio.h>
00044 #include <str.h>
00045 #include <task.h>
00046 #include <adt/measured_strings.h>
00047 #include <ipc/services.h>
00048 #include <ipc/net.h>
00049 #include <ipc/arp.h>
00050 #include <ipc/il.h>
00051 #include <ipc/nil.h>
00052 #include <byteorder.h>
00053 #include <errno.h>
00054 #include <net/modules.h>
00055 #include <net/device.h>
00056 #include <net/packet.h>
00057 #include <nil_remote.h>
00058 #include <protocol_map.h>
00059 #include <packet_client.h>
00060 #include <packet_remote.h>
00061 #include <il_remote.h>
00062 #include <il_skel.h>
00063 #include "arp.h"
00064 
00066 #define NAME  "arp"
00067 
00069 #define ARP_TRANS_WAIT  1000000
00070 
00073 
00075 #define ARPOP_REQUEST  1
00076 
00078 #define ARPOP_REPLY  2
00079 
00085 typedef struct arp_header arp_header_t;
00086 
00088 struct arp_header {
00093         uint16_t hardware;
00094         
00096         uint16_t protocol;
00098         uint8_t hardware_length;
00100         uint8_t protocol_length;
00101         
00106         uint16_t operation;
00107 } __attribute__ ((packed));
00108 
00110 arp_globals_t arp_globals;
00111 
00112 DEVICE_MAP_IMPLEMENT(arp_cache, arp_device_t);
00113 INT_MAP_IMPLEMENT(arp_protos, arp_proto_t);
00114 GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, arp_trans_t);
00115 
00116 static void arp_clear_trans(arp_trans_t *trans)
00117 {
00118         if (trans->hw_addr) {
00119                 free(trans->hw_addr);
00120                 trans->hw_addr = NULL;
00121         }
00122         
00123         fibril_condvar_broadcast(&trans->cv);
00124 }
00125 
00126 static void arp_clear_addr(arp_addr_t *addresses)
00127 {
00128         int count;
00129         
00130         for (count = arp_addr_count(addresses) - 1; count >= 0; count--) {
00131                 arp_trans_t *trans = arp_addr_items_get_index(&addresses->values,
00132                     count);
00133                 if (trans)
00134                         arp_clear_trans(trans);
00135         }
00136 }
00137 
00142 static void arp_clear_device(arp_device_t *device)
00143 {
00144         int count;
00145         
00146         for (count = arp_protos_count(&device->protos) - 1; count >= 0;
00147             count--) {
00148                 arp_proto_t *proto = arp_protos_get_index(&device->protos,
00149                     count);
00150                 
00151                 if (proto) {
00152                         if (proto->addr)
00153                                 free(proto->addr);
00154                         
00155                         if (proto->addr_data)
00156                                 free(proto->addr_data);
00157                         
00158                         arp_clear_addr(&proto->addresses);
00159                         arp_addr_destroy(&proto->addresses, free);
00160                 }
00161         }
00162         
00163         arp_protos_clear(&device->protos, free);
00164 }
00165 
00166 static int arp_clean_cache_req(int arp_phone)
00167 {
00168         int count;
00169         
00170         fibril_mutex_lock(&arp_globals.lock);
00171         for (count = arp_cache_count(&arp_globals.cache) - 1; count >= 0;
00172             count--) {
00173                 arp_device_t *device = arp_cache_get_index(&arp_globals.cache,
00174                     count);
00175                 
00176                 if (device) {
00177                         arp_clear_device(device);
00178                         if (device->addr_data)
00179                                 free(device->addr_data);
00180                         
00181                         if (device->broadcast_data)
00182                                 free(device->broadcast_data);
00183                 }
00184         }
00185         
00186         arp_cache_clear(&arp_globals.cache, free);
00187         fibril_mutex_unlock(&arp_globals.lock);
00188         
00189         return EOK;
00190 }
00191 
00192 static int arp_clear_address_req(int arp_phone, device_id_t device_id,
00193     services_t protocol, measured_string_t *address)
00194 {
00195         fibril_mutex_lock(&arp_globals.lock);
00196         
00197         arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
00198         if (!device) {
00199                 fibril_mutex_unlock(&arp_globals.lock);
00200                 return ENOENT;
00201         }
00202         
00203         arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
00204         if (!proto) {
00205                 fibril_mutex_unlock(&arp_globals.lock);
00206                 return ENOENT;
00207         }
00208         
00209         arp_trans_t *trans = arp_addr_find(&proto->addresses, address->value,
00210             address->length);
00211         if (trans)
00212                 arp_clear_trans(trans);
00213         
00214         arp_addr_exclude(&proto->addresses, address->value, address->length, free);
00215         
00216         fibril_mutex_unlock(&arp_globals.lock);
00217         return EOK;
00218 }
00219 
00220 static int arp_clear_device_req(int arp_phone, device_id_t device_id)
00221 {
00222         fibril_mutex_lock(&arp_globals.lock);
00223         
00224         arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
00225         if (!device) {
00226                 fibril_mutex_unlock(&arp_globals.lock);
00227                 return ENOENT;
00228         }
00229         
00230         arp_clear_device(device);
00231         
00232         fibril_mutex_unlock(&arp_globals.lock);
00233         return EOK;
00234 }
00235 
00248 static int arp_proto_create(arp_proto_t **proto, services_t service,
00249     measured_string_t *address)
00250 {
00251         *proto = (arp_proto_t *) malloc(sizeof(arp_proto_t));
00252         if (!*proto)
00253                 return ENOMEM;
00254         
00255         (*proto)->service = service;
00256         (*proto)->addr = address;
00257         (*proto)->addr_data = address->value;
00258         
00259         int rc = arp_addr_initialize(&(*proto)->addresses);
00260         if (rc != EOK) {
00261                 free(*proto);
00262                 return rc;
00263         }
00264         
00265         return EOK;
00266 }
00267 
00291 static int arp_receive_message(device_id_t device_id, packet_t *packet)
00292 {
00293         int rc;
00294         
00295         size_t length = packet_get_data_length(packet);
00296         if (length <= sizeof(arp_header_t))
00297                 return EINVAL;
00298         
00299         arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
00300         if (!device)
00301                 return ENOENT;
00302         
00303         arp_header_t *header = (arp_header_t *) packet_get_data(packet);
00304         if ((ntohs(header->hardware) != device->hardware) ||
00305             (length < sizeof(arp_header_t) + header->hardware_length * 2U +
00306             header->protocol_length * 2U)) {
00307                 return EINVAL;
00308         }
00309         
00310         arp_proto_t *proto = arp_protos_find(&device->protos,
00311             protocol_unmap(device->service, ntohs(header->protocol)));
00312         if (!proto)
00313                 return ENOENT;
00314         
00315         uint8_t *src_hw = ((uint8_t *) header) + sizeof(arp_header_t);
00316         uint8_t *src_proto = src_hw + header->hardware_length;
00317         uint8_t *des_hw = src_proto + header->protocol_length;
00318         uint8_t *des_proto = des_hw + header->hardware_length;
00319         
00320         arp_trans_t *trans = arp_addr_find(&proto->addresses, src_proto,
00321             header->protocol_length);
00322         
00323         if ((trans) && (trans->hw_addr)) {
00324                 /* Translation exists */
00325                 if (trans->hw_addr->length != header->hardware_length)
00326                         return EINVAL;
00327                 
00328                 memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
00329         }
00330         
00331         /* Is my protocol address? */
00332         if (proto->addr->length != header->protocol_length)
00333                 return EINVAL;
00334         
00335         if (!bcmp(proto->addr->value, des_proto, proto->addr->length)) {
00336                 if (!trans) {
00337                         /* Update the translation */
00338                         trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
00339                         if (!trans)
00340                                 return ENOMEM;
00341                         
00342                         trans->hw_addr = NULL;
00343                         fibril_condvar_initialize(&trans->cv);
00344                         rc = arp_addr_add(&proto->addresses, src_proto,
00345                             header->protocol_length, trans);
00346                         if (rc != EOK) {
00347                                 free(trans);
00348                                 return rc;
00349                         }
00350                 }
00351                 
00352                 if (!trans->hw_addr) {
00353                         trans->hw_addr = measured_string_create_bulk(src_hw,
00354                             header->hardware_length);
00355                         if (!trans->hw_addr)
00356                                 return ENOMEM;
00357                         
00358                         /* Notify the fibrils that wait for the translation. */
00359                         fibril_condvar_broadcast(&trans->cv);
00360                 }
00361                 
00362                 if (ntohs(header->operation) == ARPOP_REQUEST) {
00363                         header->operation = htons(ARPOP_REPLY);
00364                         memcpy(des_proto, src_proto, header->protocol_length);
00365                         memcpy(src_proto, proto->addr->value,
00366                             header->protocol_length);
00367                         memcpy(src_hw, device->addr->value,
00368                             device->packet_dimension.addr_len);
00369                         memcpy(des_hw, trans->hw_addr->value,
00370                             header->hardware_length);
00371                         
00372                         rc = packet_set_addr(packet, src_hw, des_hw,
00373                             header->hardware_length);
00374                         if (rc != EOK)
00375                                 return rc;
00376                         
00377                         nil_send_msg(device->phone, device_id, packet,
00378                             SERVICE_ARP);
00379                         return 1;
00380                 }
00381         }
00382         
00383         return EOK;
00384 }
00385 
00395 static int arp_mtu_changed_message(device_id_t device_id, size_t mtu)
00396 {
00397         fibril_mutex_lock(&arp_globals.lock);
00398         
00399         arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
00400         if (!device) {
00401                 fibril_mutex_unlock(&arp_globals.lock);
00402                 return ENOENT;
00403         }
00404         
00405         device->packet_dimension.content = mtu;
00406         
00407         fibril_mutex_unlock(&arp_globals.lock);
00408         
00409         printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
00410         
00411         return EOK;
00412 }
00413 
00420 static void arp_receiver(ipc_callid_t iid, ipc_call_t *icall)
00421 {
00422         packet_t *packet;
00423         int rc;
00424         
00425         while (true) {
00426                 switch (IPC_GET_IMETHOD(*icall)) {
00427                 case NET_IL_DEVICE_STATE:
00428                         /* Do nothing - keep the cache */
00429                         async_answer_0(iid, (sysarg_t) EOK);
00430                         break;
00431                 
00432                 case NET_IL_RECEIVED:
00433                         rc = packet_translate_remote(arp_globals.net_phone, &packet,
00434                             IPC_GET_PACKET(*icall));
00435                         if (rc == EOK) {
00436                                 fibril_mutex_lock(&arp_globals.lock);
00437                                 do {
00438                                         packet_t *next = pq_detach(packet);
00439                                         rc = arp_receive_message(IPC_GET_DEVICE(*icall), packet);
00440                                         if (rc != 1) {
00441                                                 pq_release_remote(arp_globals.net_phone,
00442                                                     packet_get_id(packet));
00443                                         }
00444                                         
00445                                         packet = next;
00446                                 } while (packet);
00447                                 fibril_mutex_unlock(&arp_globals.lock);
00448                         }
00449                         async_answer_0(iid, (sysarg_t) rc);
00450                         break;
00451                 
00452                 case NET_IL_MTU_CHANGED:
00453                         rc = arp_mtu_changed_message(IPC_GET_DEVICE(*icall),
00454                             IPC_GET_MTU(*icall));
00455                         async_answer_0(iid, (sysarg_t) rc);
00456                         break;
00457                 
00458                 default:
00459                         async_answer_0(iid, (sysarg_t) ENOTSUP);
00460                 }
00461                 
00462                 iid = async_get_call(icall);
00463         }
00464 }
00465 
00484 static int arp_device_message(device_id_t device_id, services_t service,
00485     services_t protocol, measured_string_t *address)
00486 {
00487         int index;
00488         int rc;
00489         
00490         fibril_mutex_lock(&arp_globals.lock);
00491         
00492         /* An existing device? */
00493         arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
00494         if (device) {
00495                 if (device->service != service) {
00496                         printf("%s: Device %d already exists\n", NAME,
00497                             device->device_id);
00498                         fibril_mutex_unlock(&arp_globals.lock);
00499                         return EEXIST;
00500                 }
00501                 
00502                 arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
00503                 if (proto) {
00504                         free(proto->addr);
00505                         free(proto->addr_data);
00506                         proto->addr = address;
00507                         proto->addr_data = address->value;
00508                 } else {
00509                         rc = arp_proto_create(&proto, protocol, address);
00510                         if (rc != EOK) {
00511                                 fibril_mutex_unlock(&arp_globals.lock);
00512                                 return rc;
00513                         }
00514                         
00515                         index = arp_protos_add(&device->protos, proto->service,
00516                             proto);
00517                         if (index < 0) {
00518                                 fibril_mutex_unlock(&arp_globals.lock);
00519                                 free(proto);
00520                                 return index;
00521                         }
00522                         
00523                         printf("%s: New protocol added (id: %d, proto: %d)\n", NAME,
00524                             device_id, protocol);
00525                 }
00526         } else {
00527                 hw_type_t hardware = hardware_map(service);
00528                 if (!hardware)
00529                         return ENOENT;
00530                 
00531                 /* Create new device */
00532                 device = (arp_device_t *) malloc(sizeof(arp_device_t));
00533                 if (!device) {
00534                         fibril_mutex_unlock(&arp_globals.lock);
00535                         return ENOMEM;
00536                 }
00537                 
00538                 device->hardware = hardware;
00539                 device->device_id = device_id;
00540                 rc = arp_protos_initialize(&device->protos);
00541                 if (rc != EOK) {
00542                         fibril_mutex_unlock(&arp_globals.lock);
00543                         free(device);
00544                         return rc;
00545                 }
00546                 
00547                 arp_proto_t *proto;
00548                 rc = arp_proto_create(&proto, protocol, address);
00549                 if (rc != EOK) {
00550                         fibril_mutex_unlock(&arp_globals.lock);
00551                         free(device);
00552                         return rc;
00553                 }
00554                 
00555                 index = arp_protos_add(&device->protos, proto->service, proto);
00556                 if (index < 0) {
00557                         fibril_mutex_unlock(&arp_globals.lock);
00558                         arp_protos_destroy(&device->protos, free);
00559                         free(device);
00560                         return index;
00561                 }
00562                 
00563                 device->service = service;
00564                 
00565                 /* Bind */
00566                 device->phone = nil_bind_service(device->service,
00567                     (sysarg_t) device->device_id, SERVICE_ARP,
00568                     arp_receiver);
00569                 if (device->phone < 0) {
00570                         fibril_mutex_unlock(&arp_globals.lock);
00571                         arp_protos_destroy(&device->protos, free);
00572                         free(device);
00573                         return EREFUSED;
00574                 }
00575                 
00576                 /* Get packet dimensions */
00577                 rc = nil_packet_size_req(device->phone, device_id,
00578                     &device->packet_dimension);
00579                 if (rc != EOK) {
00580                         fibril_mutex_unlock(&arp_globals.lock);
00581                         arp_protos_destroy(&device->protos, free);
00582                         free(device);
00583                         return rc;
00584                 }
00585                 
00586                 /* Get hardware address */
00587                 rc = nil_get_addr_req(device->phone, device_id, &device->addr,
00588                     &device->addr_data);
00589                 if (rc != EOK) {
00590                         fibril_mutex_unlock(&arp_globals.lock);
00591                         arp_protos_destroy(&device->protos, free);
00592                         free(device);
00593                         return rc;
00594                 }
00595                 
00596                 /* Get broadcast address */
00597                 rc = nil_get_broadcast_addr_req(device->phone, device_id,
00598                     &device->broadcast_addr, &device->broadcast_data);
00599                 if (rc != EOK) {
00600                         fibril_mutex_unlock(&arp_globals.lock);
00601                         free(device->addr);
00602                         free(device->addr_data);
00603                         arp_protos_destroy(&device->protos, free);
00604                         free(device);
00605                         return rc;
00606                 }
00607                 
00608                 rc = arp_cache_add(&arp_globals.cache, device->device_id,
00609                     device);
00610                 if (rc != EOK) {
00611                         fibril_mutex_unlock(&arp_globals.lock);
00612                         free(device->addr);
00613                         free(device->addr_data);
00614                         free(device->broadcast_addr);
00615                         free(device->broadcast_data);
00616                         arp_protos_destroy(&device->protos, free);
00617                         free(device);
00618                         return rc;
00619                 }
00620                 printf("%s: Device registered (id: %d, type: 0x%x, service: %d,"
00621                     " proto: %d)\n", NAME, device->device_id, device->hardware,
00622                     device->service, protocol);
00623         }
00624         
00625         fibril_mutex_unlock(&arp_globals.lock);
00626         return EOK;
00627 }
00628 
00629 int il_initialize(int net_phone)
00630 {
00631         fibril_mutex_initialize(&arp_globals.lock);
00632         
00633         fibril_mutex_lock(&arp_globals.lock);
00634         arp_globals.net_phone = net_phone;
00635         int rc = arp_cache_initialize(&arp_globals.cache);
00636         fibril_mutex_unlock(&arp_globals.lock);
00637         
00638         return rc;
00639 }
00640 
00641 static int arp_send_request(device_id_t device_id, services_t protocol,
00642     measured_string_t *target, arp_device_t *device, arp_proto_t *proto)
00643 {
00644         /* ARP packet content size = header + (address + translation) * 2 */
00645         size_t length = 8 + 2 * (proto->addr->length + device->addr->length);
00646         if (length > device->packet_dimension.content)
00647                 return ELIMIT;
00648         
00649         packet_t *packet = packet_get_4_remote(arp_globals.net_phone,
00650             device->packet_dimension.addr_len, device->packet_dimension.prefix,
00651             length, device->packet_dimension.suffix);
00652         if (!packet)
00653                 return ENOMEM;
00654         
00655         arp_header_t *header = (arp_header_t *) packet_suffix(packet, length);
00656         if (!header) {
00657                 pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
00658                 return ENOMEM;
00659         }
00660         
00661         header->hardware = htons(device->hardware);
00662         header->hardware_length = (uint8_t) device->addr->length;
00663         header->protocol = htons(protocol_map(device->service, protocol));
00664         header->protocol_length = (uint8_t) proto->addr->length;
00665         header->operation = htons(ARPOP_REQUEST);
00666         
00667         length = sizeof(arp_header_t);
00668         
00669         memcpy(((uint8_t *) header) + length, device->addr->value,
00670             device->addr->length);
00671         length += device->addr->length;
00672         memcpy(((uint8_t *) header) + length, proto->addr->value,
00673             proto->addr->length);
00674         length += proto->addr->length;
00675         bzero(((uint8_t *) header) + length, device->addr->length);
00676         length += device->addr->length;
00677         memcpy(((uint8_t *) header) + length, target->value, target->length);
00678         
00679         int rc = packet_set_addr(packet, (uint8_t *) device->addr->value,
00680             (uint8_t *) device->broadcast_addr->value, device->addr->length);
00681         if (rc != EOK) {
00682                 pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
00683                 return rc;
00684         }
00685         
00686         nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
00687         return EOK;
00688 }
00689 
00705 static int arp_translate_message(device_id_t device_id, services_t protocol,
00706     measured_string_t *target, measured_string_t **translation)
00707 {
00708         bool retry = false;
00709         int rc;
00710 
00711         assert(fibril_mutex_is_locked(&arp_globals.lock));
00712         
00713 restart:
00714         if ((!target) || (!translation))
00715                 return EBADMEM;
00716         
00717         arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
00718         if (!device)
00719                 return ENOENT;
00720         
00721         arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
00722         if ((!proto) || (proto->addr->length != target->length))
00723                 return ENOENT;
00724         
00725         arp_trans_t *trans = arp_addr_find(&proto->addresses, target->value,
00726             target->length);
00727         if (trans) {
00728                 if (trans->hw_addr) {
00729                         /* The translation is in place. */
00730                         *translation = trans->hw_addr;
00731                         return EOK;
00732                 }
00733                 
00734                 if (retry) {
00735                         /*
00736                          * We may get here as a result of being signalled for
00737                          * some reason while waiting for the translation (e.g.
00738                          * translation becoming available, record being removed
00739                          * from the table) and then losing the race for
00740                          * the arp_globals.lock with someone else who modified
00741                          * the table.
00742                          *
00743                          * Remove the incomplete record so that it is possible
00744                          * to make new ARP requests.
00745                          */
00746                         arp_clear_trans(trans);
00747                         arp_addr_exclude(&proto->addresses, target->value,
00748                             target->length, free);
00749                         return EAGAIN;
00750                 }
00751                 
00752                 /*
00753                  * We are a random passer-by who merely joins an already waiting
00754                  * fibril in waiting for the translation.
00755                  */
00756                 rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
00757                     ARP_TRANS_WAIT);
00758                 if (rc == ETIMEOUT)
00759                         return ENOENT;
00760                 
00761                 /*
00762                  * Need to recheck because we did not hold the lock while
00763                  * sleeping on the condition variable.
00764                  */
00765                 retry = true;
00766                 goto restart;
00767         }
00768         
00769         if (retry)
00770                 return EAGAIN;
00771 
00772         /*
00773          * We are under the protection of arp_globals.lock, so we can afford to
00774          * first send the ARP request and then insert an incomplete ARP record.
00775          * The incomplete record is used to tell any other potential waiter
00776          * that this fibril has already sent the request and that it is waiting
00777          * for the answer. Lastly, any fibril which sees the incomplete request
00778          * can perform a timed wait on its condition variable to wait for the
00779          * ARP reply to arrive.
00780          */
00781 
00782         rc = arp_send_request(device_id, protocol, target, device, proto);
00783         if (rc != EOK)
00784                 return rc;
00785         
00786         trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
00787         if (!trans)
00788                 return ENOMEM;
00789         
00790         trans->hw_addr = NULL;
00791         fibril_condvar_initialize(&trans->cv);
00792         
00793         rc = arp_addr_add(&proto->addresses, target->value, target->length,
00794             trans);
00795         if (rc != EOK) {
00796                 free(trans);
00797                 return rc;
00798         }
00799         
00800         rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
00801             ARP_TRANS_WAIT);
00802         if (rc == ETIMEOUT) {
00803                 /*
00804                  * Remove the incomplete record so that it is possible to make 
00805                  * new ARP requests.
00806                  */
00807                 arp_clear_trans(trans);
00808                 arp_addr_exclude(&proto->addresses, target->value,
00809                     target->length, free);
00810                 return ENOENT;
00811         }
00812         
00813         /*
00814          * We need to recheck that the translation has indeed become available,
00815          * because we dropped the arp_globals.lock while sleeping on the
00816          * condition variable and someone else might have e.g. removed the
00817          * translation before we managed to lock arp_globals.lock again.
00818          */
00819 
00820         retry = true;
00821         goto restart;
00822 }
00823 
00838 int il_module_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
00839     size_t *count)
00840 {
00841         measured_string_t *address;
00842         measured_string_t *translation;
00843         uint8_t *data;
00844         int rc;
00845         
00846         *count = 0;
00847         switch (IPC_GET_IMETHOD(*call)) {
00848         case IPC_M_PHONE_HUNGUP:
00849                 return EOK;
00850         
00851         case NET_ARP_DEVICE:
00852                 rc = measured_strings_receive(&address, &data, 1);
00853                 if (rc != EOK)
00854                         return rc;
00855                 
00856                 rc = arp_device_message(IPC_GET_DEVICE(*call),
00857                     IPC_GET_SERVICE(*call), ARP_GET_NETIF(*call), address);
00858                 if (rc != EOK) {
00859                         free(address);
00860                         free(data);
00861                 }
00862                 
00863                 return rc;
00864         
00865         case NET_ARP_TRANSLATE:
00866                 rc = measured_strings_receive(&address, &data, 1);
00867                 if (rc != EOK)
00868                         return rc;
00869                 
00870                 fibril_mutex_lock(&arp_globals.lock);
00871                 rc = arp_translate_message(IPC_GET_DEVICE(*call),
00872                     IPC_GET_SERVICE(*call), address, &translation);
00873                 free(address);
00874                 free(data);
00875                 
00876                 if (rc != EOK) {
00877                         fibril_mutex_unlock(&arp_globals.lock);
00878                         return rc;
00879                 }
00880                 
00881                 if (!translation) {
00882                         fibril_mutex_unlock(&arp_globals.lock);
00883                         return ENOENT;
00884                 }
00885                 
00886                 rc = measured_strings_reply(translation, 1);
00887                 fibril_mutex_unlock(&arp_globals.lock);
00888                 return rc;
00889         
00890         case NET_ARP_CLEAR_DEVICE:
00891                 return arp_clear_device_req(0, IPC_GET_DEVICE(*call));
00892         
00893         case NET_ARP_CLEAR_ADDRESS:
00894                 rc = measured_strings_receive(&address, &data, 1);
00895                 if (rc != EOK)
00896                         return rc;
00897                 
00898                 arp_clear_address_req(0, IPC_GET_DEVICE(*call),
00899                     IPC_GET_SERVICE(*call), address);
00900                 free(address);
00901                 free(data);
00902                 return EOK;
00903         
00904         case NET_ARP_CLEAN_CACHE:
00905                 return arp_clean_cache_req(0);
00906         }
00907         
00908         return ENOTSUP;
00909 }
00910 
00911 int main(int argc, char *argv[])
00912 {
00913         /* Start the module */
00914         return il_module_start(SERVICE_ARP);
00915 }
00916 

Generated on Thu Jun 2 07:45:50 2011 for HelenOS/USB by  doxygen 1.4.7