Changeset 357b5f5 in mainline for uspace/srv/net/il/arp/arp.c


Ignore:
Timestamp:
2011-01-23T20:09:13Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
fdb9982c
Parents:
cead2aa (diff), 7e36c8d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/il/arp/arp.c

    rcead2aa r357b5f5  
    3636 */
    3737
    38 #include "arp.h"
    39 #include "arp_header.h"
    40 #include "arp_oc.h"
    41 #include "arp_module.h"
    42 
    4338#include <async.h>
    4439#include <malloc.h>
    4540#include <mem.h>
    4641#include <fibril_synch.h>
     42#include <assert.h>
    4743#include <stdio.h>
    4844#include <str.h>
     
    5450#include <ipc/arp.h>
    5551#include <ipc/il.h>
     52#include <ipc/nil.h>
    5653#include <byteorder.h>
    5754#include <errno.h>
    58 
    5955#include <net/modules.h>
    6056#include <net/device.h>
    6157#include <net/packet.h>
    62 
    63 #include <nil_interface.h>
     58#include <nil_remote.h>
    6459#include <protocol_map.h>
    6560#include <packet_client.h>
    6661#include <packet_remote.h>
    67 #include <il_interface.h>
    68 #include <il_local.h>
    69 
     62#include <il_remote.h>
     63#include <il_skel.h>
     64#include "arp.h"
    7065
    7166/** ARP module name. */
    7267#define NAME  "arp"
    7368
     69/** Number of microseconds to wait for an ARP reply. */
     70#define ARP_TRANS_WAIT  1000000
     71
     72/** @name ARP operation codes definitions */
     73/*@{*/
     74
     75/** REQUEST operation code. */
     76#define ARPOP_REQUEST  1
     77
     78/** REPLY operation code. */
     79#define ARPOP_REPLY  2
     80
     81/*@}*/
     82
     83/** Type definition of an ARP protocol header.
     84 * @see arp_header
     85 */
     86typedef struct arp_header arp_header_t;
     87
     88/** ARP protocol header. */
     89struct arp_header {
     90        /**
     91         * Hardware type identifier.
     92         * @see hardware.h
     93         */
     94        uint16_t hardware;
     95       
     96        /** Protocol identifier. */
     97        uint16_t protocol;
     98        /** Hardware address length in bytes. */
     99        uint8_t hardware_length;
     100        /** Protocol address length in bytes. */
     101        uint8_t protocol_length;
     102       
     103        /**
     104         * ARP packet type.
     105         * @see arp_oc.h
     106         */
     107        uint16_t operation;
     108} __attribute__ ((packed));
     109
    74110/** ARP global data. */
    75111arp_globals_t arp_globals;
     
    77113DEVICE_MAP_IMPLEMENT(arp_cache, arp_device_t);
    78114INT_MAP_IMPLEMENT(arp_protos, arp_proto_t);
    79 GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, measured_string_t);
    80 
    81 /** Clears the device specific data.
    82  *
    83  * @param[in] device    The device specific data.
     115GENERIC_CHAR_MAP_IMPLEMENT(arp_addr, arp_trans_t);
     116
     117static void arp_clear_trans(arp_trans_t *trans)
     118{
     119        if (trans->hw_addr) {
     120                free(trans->hw_addr);
     121                trans->hw_addr = NULL;
     122        }
     123       
     124        fibril_condvar_broadcast(&trans->cv);
     125}
     126
     127static void arp_clear_addr(arp_addr_t *addresses)
     128{
     129        int count;
     130       
     131        for (count = arp_addr_count(addresses) - 1; count >= 0; count--) {
     132                arp_trans_t *trans = arp_addr_items_get_index(&addresses->values,
     133                    count);
     134                if (trans)
     135                        arp_clear_trans(trans);
     136        }
     137}
     138
     139/** Clear the device specific data.
     140 *
     141 * @param[in] device Device specific data.
    84142 */
    85143static void arp_clear_device(arp_device_t *device)
    86144{
    87145        int count;
    88         arp_proto_t *proto;
    89 
     146       
    90147        for (count = arp_protos_count(&device->protos) - 1; count >= 0;
    91148            count--) {
    92                 proto = arp_protos_get_index(&device->protos, count);
     149                arp_proto_t *proto = arp_protos_get_index(&device->protos,
     150                    count);
     151               
    93152                if (proto) {
    94153                        if (proto->addr)
    95154                                free(proto->addr);
     155                       
    96156                        if (proto->addr_data)
    97157                                free(proto->addr_data);
     158                       
     159                        arp_clear_addr(&proto->addresses);
    98160                        arp_addr_destroy(&proto->addresses);
    99161                }
    100162        }
     163       
    101164        arp_protos_clear(&device->protos);
    102165}
     
    105168{
    106169        int count;
    107         arp_device_t *device;
    108 
    109         fibril_rwlock_write_lock(&arp_globals.lock);
     170       
     171        fibril_mutex_lock(&arp_globals.lock);
    110172        for (count = arp_cache_count(&arp_globals.cache) - 1; count >= 0;
    111173            count--) {
    112                 device = arp_cache_get_index(&arp_globals.cache, count);
     174                arp_device_t *device = arp_cache_get_index(&arp_globals.cache,
     175                    count);
     176               
    113177                if (device) {
    114178                        arp_clear_device(device);
    115179                        if (device->addr_data)
    116180                                free(device->addr_data);
     181                       
    117182                        if (device->broadcast_data)
    118183                                free(device->broadcast_data);
    119184                }
    120185        }
     186       
    121187        arp_cache_clear(&arp_globals.cache);
    122         fibril_rwlock_write_unlock(&arp_globals.lock);
    123         printf("Cache cleaned\n");
     188        fibril_mutex_unlock(&arp_globals.lock);
     189       
    124190        return EOK;
    125191}
     
    128194    services_t protocol, measured_string_t *address)
    129195{
    130         arp_device_t *device;
    131         arp_proto_t *proto;
    132 
    133         fibril_rwlock_write_lock(&arp_globals.lock);
    134         device = arp_cache_find(&arp_globals.cache, device_id);
     196        fibril_mutex_lock(&arp_globals.lock);
     197       
     198        arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
    135199        if (!device) {
    136                 fibril_rwlock_write_unlock(&arp_globals.lock);
     200                fibril_mutex_unlock(&arp_globals.lock);
    137201                return ENOENT;
    138202        }
    139         proto = arp_protos_find(&device->protos, protocol);
     203       
     204        arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
    140205        if (!proto) {
    141                 fibril_rwlock_write_unlock(&arp_globals.lock);
     206                fibril_mutex_unlock(&arp_globals.lock);
    142207                return ENOENT;
    143208        }
     209       
     210        arp_trans_t *trans = arp_addr_find(&proto->addresses, address->value,
     211            address->length);
     212        if (trans)
     213                arp_clear_trans(trans);
     214       
    144215        arp_addr_exclude(&proto->addresses, address->value, address->length);
    145         fibril_rwlock_write_unlock(&arp_globals.lock);
     216       
     217        fibril_mutex_unlock(&arp_globals.lock);
    146218        return EOK;
    147219}
    148220
    149 
    150221static int arp_clear_device_req(int arp_phone, device_id_t device_id)
    151222{
    152         arp_device_t *device;
    153 
    154         fibril_rwlock_write_lock(&arp_globals.lock);
    155         device = arp_cache_find(&arp_globals.cache, device_id);
     223        fibril_mutex_lock(&arp_globals.lock);
     224       
     225        arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
    156226        if (!device) {
    157                 fibril_rwlock_write_unlock(&arp_globals.lock);
     227                fibril_mutex_unlock(&arp_globals.lock);
    158228                return ENOENT;
    159229        }
     230       
    160231        arp_clear_device(device);
    161         printf("Device %d cleared\n", device_id);
    162         fibril_rwlock_write_unlock(&arp_globals.lock);
     232       
     233        fibril_mutex_unlock(&arp_globals.lock);
    163234        return EOK;
    164235}
    165236
    166 /** Creates new protocol specific data.
    167  *
    168  * Allocates and returns the needed memory block as the proto parameter.
    169  *
    170  * @param[out] proto    The allocated protocol specific data.
    171  * @param[in] service   The protocol module service.
    172  * @param[in] address   The actual protocol device address.
    173  * @return              EOK on success.
    174  * @return              ENOMEM if there is not enough memory left.
     237/** Create new protocol specific data.
     238 *
     239 * Allocate and return the needed memory block as the proto parameter.
     240 *
     241 * @param[out] proto   Allocated protocol specific data.
     242 * @param[in]  service Protocol module service.
     243 * @param[in]  address Actual protocol device address.
     244 *
     245 * @return EOK on success.
     246 * @return ENOMEM if there is not enough memory left.
     247 *
    175248 */
    176249static int arp_proto_create(arp_proto_t **proto, services_t service,
    177250    measured_string_t *address)
    178251{
    179         int rc;
    180 
    181252        *proto = (arp_proto_t *) malloc(sizeof(arp_proto_t));
    182253        if (!*proto)
     
    187258        (*proto)->addr_data = address->value;
    188259       
    189         rc = arp_addr_initialize(&(*proto)->addresses);
     260        int rc = arp_addr_initialize(&(*proto)->addresses);
    190261        if (rc != EOK) {
    191262                free(*proto);
     
    196267}
    197268
    198 /** Registers the device.
    199  *
    200  * Creates new device entry in the cache or updates the protocol address if the
    201  * device with the device identifier and the driver service exists.
    202  *
    203  * @param[in] device_id The device identifier.
    204  * @param[in] service   The device driver service.
    205  * @param[in] protocol  The protocol service.
    206  * @param[in] address   The actual device protocol address.
    207  * @return              EOK on success.
    208  * @return              EEXIST if another device with the same device identifier
    209  *                      and different driver service exists.
    210  * @return              ENOMEM if there is not enough memory left.
    211  * @return              Other error codes as defined for the
    212  *                      measured_strings_return() function.
    213  */
    214 static int arp_device_message(device_id_t device_id, services_t service,
    215     services_t protocol, measured_string_t *address)
    216 {
    217         arp_device_t *device;
    218         arp_proto_t *proto;
    219         hw_type_t hardware;
    220         int index;
     269/** Process the received ARP packet.
     270 *
     271 * Update the source hardware address if the source entry exists or the packet
     272 * is targeted to my protocol address.
     273 *
     274 * Respond to the ARP request if the packet is the ARP request and is
     275 * targeted to my address.
     276 *
     277 * @param[in]     device_id Source device identifier.
     278 * @param[in,out] packet    Received packet.
     279 *
     280 * @return EOK on success and the packet is no longer needed.
     281 * @return One on success and the packet has been reused.
     282 * @return EINVAL if the packet is too small to carry an ARP
     283 *         packet.
     284 * @return EINVAL if the received address lengths differs from
     285 *         the registered values.
     286 * @return ENOENT if the device is not found in the cache.
     287 * @return ENOENT if the protocol for the device is not found in
     288 *         the cache.
     289 * @return ENOMEM if there is not enough memory left.
     290 *
     291 */
     292static int arp_receive_message(device_id_t device_id, packet_t *packet)
     293{
    221294        int rc;
    222 
    223         fibril_rwlock_write_lock(&arp_globals.lock);
    224 
    225         /* An existing device? */
    226         device = arp_cache_find(&arp_globals.cache, device_id);
    227 
    228         if (device) {
    229                 if (device->service != service) {
    230                         printf("Device %d already exists\n", device->device_id);
    231                         fibril_rwlock_write_unlock(&arp_globals.lock);
    232                         return EEXIST;
    233                 }
    234                 proto = arp_protos_find(&device->protos, protocol);
    235                 if (proto) {
    236                         free(proto->addr);
    237                         free(proto->addr_data);
    238                         proto->addr = address;
    239                         proto->addr_data = address->value;
    240                 } else {
    241                         rc = arp_proto_create(&proto, protocol, address);
    242                         if (rc != EOK) {
    243                                 fibril_rwlock_write_unlock(&arp_globals.lock);
    244                                 return rc;
    245                         }
    246                         index = arp_protos_add(&device->protos, proto->service,
    247                             proto);
    248                         if (index < 0) {
    249                                 fibril_rwlock_write_unlock(&arp_globals.lock);
    250                                 free(proto);
    251                                 return index;
    252                         }
    253                         printf("New protocol added:\n\tdevice id\t= "
    254                             "%d\n\tproto\t= %d", device_id, protocol);
    255                 }
    256         } else {
    257                 hardware = hardware_map(service);
    258                 if (!hardware)
    259                         return ENOENT;
    260                
    261                 /* Create a new device */
    262                 device = (arp_device_t *) malloc(sizeof(arp_device_t));
    263                 if (!device) {
    264                         fibril_rwlock_write_unlock(&arp_globals.lock);
    265                         return ENOMEM;
    266                 }
    267                 device->hardware = hardware;
    268                 device->device_id = device_id;
    269                 rc = arp_protos_initialize(&device->protos);
    270                 if (rc != EOK) {
    271                         fibril_rwlock_write_unlock(&arp_globals.lock);
    272                         free(device);
    273                         return rc;
    274                 }
    275                 rc = arp_proto_create(&proto, protocol, address);
    276                 if (rc != EOK) {
    277                         fibril_rwlock_write_unlock(&arp_globals.lock);
    278                         free(device);
    279                         return rc;
    280                 }
    281                 index = arp_protos_add(&device->protos, proto->service, proto);
    282                 if (index < 0) {
    283                         fibril_rwlock_write_unlock(&arp_globals.lock);
    284                         arp_protos_destroy(&device->protos);
    285                         free(device);
    286                         return index;
    287                 }
    288                 device->service = service;
    289                
    290                 /* Bind the new one */
    291                 device->phone = nil_bind_service(device->service,
    292                     (ipcarg_t) device->device_id, SERVICE_ARP,
    293                     arp_globals.client_connection);
    294                 if (device->phone < 0) {
    295                         fibril_rwlock_write_unlock(&arp_globals.lock);
    296                         arp_protos_destroy(&device->protos);
    297                         free(device);
    298                         return EREFUSED;
    299                 }
    300                
    301                 /* Get packet dimensions */
    302                 rc = nil_packet_size_req(device->phone, device_id,
    303                     &device->packet_dimension);
    304                 if (rc != EOK) {
    305                         fibril_rwlock_write_unlock(&arp_globals.lock);
    306                         arp_protos_destroy(&device->protos);
    307                         free(device);
    308                         return rc;
    309                 }
    310                
    311                 /* Get hardware address */
    312                 rc = nil_get_addr_req(device->phone, device_id, &device->addr,
    313                     &device->addr_data);
    314                 if (rc != EOK) {
    315                         fibril_rwlock_write_unlock(&arp_globals.lock);
    316                         arp_protos_destroy(&device->protos);
    317                         free(device);
    318                         return rc;
    319                 }
    320                
    321                 /* Get broadcast address */
    322                 rc = nil_get_broadcast_addr_req(device->phone, device_id,
    323                     &device->broadcast_addr, &device->broadcast_data);
    324                 if (rc != EOK) {
    325                         fibril_rwlock_write_unlock(&arp_globals.lock);
    326                         free(device->addr);
    327                         free(device->addr_data);
    328                         arp_protos_destroy(&device->protos);
    329                         free(device);
    330                         return rc;
    331                 }
    332                
    333                 rc = arp_cache_add(&arp_globals.cache, device->device_id,
    334                     device);
    335                 if (rc != EOK) {
    336                         fibril_rwlock_write_unlock(&arp_globals.lock);
    337                         free(device->addr);
    338                         free(device->addr_data);
    339                         free(device->broadcast_addr);
    340                         free(device->broadcast_data);
    341                         arp_protos_destroy(&device->protos);
    342                         free(device);
    343                         return rc;
    344                 }
    345                 printf("%s: Device registered (id: %d, type: 0x%x, service: %d,"
    346                     " proto: %d)\n", NAME, device->device_id, device->hardware,
    347                     device->service, protocol);
    348         }
    349         fibril_rwlock_write_unlock(&arp_globals.lock);
    350        
    351         return EOK;
    352 }
    353 
    354 /** Initializes the ARP module.
    355  *
    356  *  @param[in] client_connection The client connection processing function.
    357  *                      The module skeleton propagates its own one.
    358  *  @return             EOK on success.
    359  *  @return             ENOMEM if there is not enough memory left.
    360  */
    361 int arp_initialize(async_client_conn_t client_connection)
    362 {
    363         int rc;
    364 
    365         fibril_rwlock_initialize(&arp_globals.lock);
    366         fibril_rwlock_write_lock(&arp_globals.lock);
    367         arp_globals.client_connection = client_connection;
    368         rc = arp_cache_initialize(&arp_globals.cache);
    369         fibril_rwlock_write_unlock(&arp_globals.lock);
    370        
    371         return rc;
    372 }
    373 
    374 /** Updates the device content length according to the new MTU value.
    375  *
    376  * @param[in] device_id The device identifier.
    377  * @param[in] mtu       The new mtu value.
    378  * @return              ENOENT if device is not found.
    379  * @return              EOK on success.
    380  */
    381 static int arp_mtu_changed_message(device_id_t device_id, size_t mtu)
    382 {
    383         arp_device_t *device;
    384 
    385         fibril_rwlock_write_lock(&arp_globals.lock);
    386         device = arp_cache_find(&arp_globals.cache, device_id);
    387         if (!device) {
    388                 fibril_rwlock_write_unlock(&arp_globals.lock);
    389                 return ENOENT;
    390         }
    391         device->packet_dimension.content = mtu;
    392         fibril_rwlock_write_unlock(&arp_globals.lock);
    393         printf("arp - device %d changed mtu to %zu\n\n", device_id, mtu);
    394         return EOK;
    395 }
    396 
    397 /** Processes the received ARP packet.
    398  *
    399  * Updates the source hardware address if the source entry exists or the packet
    400  * is targeted to my protocol address.
    401  * Responses to the ARP request if the packet is the ARP request and is
    402  * targeted to my address.
    403  *
    404  * @param[in] device_id The source device identifier.
    405  * @param[in,out] packet The received packet.
    406  * @return              EOK on success and the packet is no longer needed.
    407  * @return              One on success and the packet has been reused.
    408  * @return              EINVAL if the packet is too small to carry an ARP
    409  *                      packet.
    410  * @return              EINVAL if the received address lengths differs from
    411  *                      the registered values.
    412  * @return              ENOENT if the device is not found in the cache.
    413  * @return              ENOENT if the protocol for the device is not found in
    414  *                      the cache.
    415  * @return              ENOMEM if there is not enough memory left.
    416  */
    417 static int arp_receive_message(device_id_t device_id, packet_t *packet)
    418 {
    419         size_t length;
    420         arp_header_t *header;
    421         arp_device_t *device;
    422         arp_proto_t *proto;
    423         measured_string_t *hw_source;
    424         uint8_t *src_hw;
    425         uint8_t *src_proto;
    426         uint8_t *des_hw;
    427         uint8_t *des_proto;
    428         int rc;
    429 
    430         length = packet_get_data_length(packet);
     295       
     296        size_t length = packet_get_data_length(packet);
    431297        if (length <= sizeof(arp_header_t))
    432298                return EINVAL;
    433 
    434         device = arp_cache_find(&arp_globals.cache, device_id);
     299       
     300        arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
    435301        if (!device)
    436302                return ENOENT;
    437 
    438         header = (arp_header_t *) packet_get_data(packet);
     303       
     304        arp_header_t *header = (arp_header_t *) packet_get_data(packet);
    439305        if ((ntohs(header->hardware) != device->hardware) ||
    440306            (length < sizeof(arp_header_t) + header->hardware_length * 2U +
     
    442308                return EINVAL;
    443309        }
    444 
    445         proto = arp_protos_find(&device->protos,
     310       
     311        arp_proto_t *proto = arp_protos_find(&device->protos,
    446312            protocol_unmap(device->service, ntohs(header->protocol)));
    447313        if (!proto)
    448314                return ENOENT;
    449 
    450         src_hw = ((uint8_t *) header) + sizeof(arp_header_t);
    451         src_proto = src_hw + header->hardware_length;
    452         des_hw = src_proto + header->protocol_length;
    453         des_proto = des_hw + header->hardware_length;
    454         hw_source = arp_addr_find(&proto->addresses, (char *) src_proto,
    455             CONVERT_SIZE(uint8_t, char, header->protocol_length));
    456         /* Exists? */
    457         if (hw_source) {
    458                 if (hw_source->length != CONVERT_SIZE(uint8_t, char,
    459                     header->hardware_length)) {
     315       
     316        uint8_t *src_hw = ((uint8_t *) header) + sizeof(arp_header_t);
     317        uint8_t *src_proto = src_hw + header->hardware_length;
     318        uint8_t *des_hw = src_proto + header->protocol_length;
     319        uint8_t *des_proto = des_hw + header->hardware_length;
     320       
     321        arp_trans_t *trans = arp_addr_find(&proto->addresses, src_proto,
     322            header->protocol_length);
     323       
     324        if ((trans) && (trans->hw_addr)) {
     325                /* Translation exists */
     326                if (trans->hw_addr->length != header->hardware_length)
    460327                        return EINVAL;
    461                 }
    462                 memcpy(hw_source->value, src_hw, hw_source->length);
    463         }
     328               
     329                memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
     330        }
     331       
    464332        /* Is my protocol address? */
    465         if (proto->addr->length != CONVERT_SIZE(uint8_t, char,
    466             header->protocol_length)) {
     333        if (proto->addr->length != header->protocol_length)
    467334                return EINVAL;
    468         }
    469         if (!str_lcmp(proto->addr->value, (char *) des_proto,
    470             proto->addr->length)) {
    471                 /* Not already updated? */
    472                 if (!hw_source) {
    473                         hw_source = measured_string_create_bulk((char *) src_hw,
    474                             CONVERT_SIZE(uint8_t, char,
    475                             header->hardware_length));
    476                         if (!hw_source)
     335       
     336        if (!bcmp(proto->addr->value, des_proto, proto->addr->length)) {
     337                if (!trans) {
     338                        /* Update the translation */
     339                        trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
     340                        if (!trans)
    477341                                return ENOMEM;
    478 
    479                         rc = arp_addr_add(&proto->addresses, (char *) src_proto,
    480                             CONVERT_SIZE(uint8_t, char,
    481                             header->protocol_length), hw_source);
    482                         if (rc != EOK)
     342                       
     343                        trans->hw_addr = NULL;
     344                        fibril_condvar_initialize(&trans->cv);
     345                        rc = arp_addr_add(&proto->addresses, src_proto,
     346                            header->protocol_length, trans);
     347                        if (rc != EOK) {
     348                                /* The generic char map has already freed trans! */
    483349                                return rc;
    484                 }
     350                        }
     351                }
     352               
     353                if (!trans->hw_addr) {
     354                        trans->hw_addr = measured_string_create_bulk(src_hw,
     355                            header->hardware_length);
     356                        if (!trans->hw_addr)
     357                                return ENOMEM;
     358                       
     359                        /* Notify the fibrils that wait for the translation. */
     360                        fibril_condvar_broadcast(&trans->cv);
     361                }
     362               
    485363                if (ntohs(header->operation) == ARPOP_REQUEST) {
    486364                        header->operation = htons(ARPOP_REPLY);
     
    490368                        memcpy(src_hw, device->addr->value,
    491369                            device->packet_dimension.addr_len);
    492                         memcpy(des_hw, hw_source->value,
     370                        memcpy(des_hw, trans->hw_addr->value,
    493371                            header->hardware_length);
    494372                       
     
    503381                }
    504382        }
    505 
     383       
    506384        return EOK;
    507385}
    508386
    509 
    510 /** Returns the hardware address for the given protocol address.
    511  *
    512  * Sends the ARP request packet if the hardware address is not found in the
    513  * cache.
    514  *
    515  * @param[in] device_id The device identifier.
    516  * @param[in] protocol  The protocol service.
    517  * @param[in] target    The target protocol address.
    518  * @return              The hardware address of the target.
    519  * @return              NULL if the target parameter is NULL.
    520  * @return              NULL if the device is not found.
    521  * @return              NULL if the device packet is too small to send a
    522  *                      request.
    523  * @return              NULL if the hardware address is not found in the cache.
    524  */
    525 static measured_string_t *
    526 arp_translate_message(device_id_t device_id, services_t protocol,
    527     measured_string_t *target)
    528 {
    529         arp_device_t *device;
    530         arp_proto_t *proto;
    531         measured_string_t *addr;
    532         size_t length;
     387/** Update the device content length according to the new MTU value.
     388 *
     389 * @param[in] device_id Device identifier.
     390 * @param[in] mtu       New MTU value.
     391 *
     392 * @return ENOENT if device is not found.
     393 * @return EOK on success.
     394 *
     395 */
     396static int arp_mtu_changed_message(device_id_t device_id, size_t mtu)
     397{
     398        fibril_mutex_lock(&arp_globals.lock);
     399       
     400        arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
     401        if (!device) {
     402                fibril_mutex_unlock(&arp_globals.lock);
     403                return ENOENT;
     404        }
     405       
     406        device->packet_dimension.content = mtu;
     407       
     408        fibril_mutex_unlock(&arp_globals.lock);
     409       
     410        printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
     411       
     412        return EOK;
     413}
     414
     415/** Process IPC messages from the registered device driver modules
     416 *
     417 * @param[in]     iid   Message identifier.
     418 * @param[in,out] icall Message parameters.
     419 *
     420 */
     421static void arp_receiver(ipc_callid_t iid, ipc_call_t *icall)
     422{
    533423        packet_t *packet;
    534         arp_header_t *header;
    535 
    536         if (!target)
    537                 return NULL;
    538 
    539         device = arp_cache_find(&arp_globals.cache, device_id);
    540         if (!device)
    541                 return NULL;
    542 
    543         proto = arp_protos_find(&device->protos, protocol);
    544         if (!proto || (proto->addr->length != target->length))
    545                 return NULL;
    546 
    547         addr = arp_addr_find(&proto->addresses, target->value, target->length);
    548         if (addr)
    549                 return addr;
    550 
     424        int rc;
     425       
     426        while (true) {
     427                switch (IPC_GET_IMETHOD(*icall)) {
     428                case NET_IL_DEVICE_STATE:
     429                        /* Do nothing - keep the cache */
     430                        ipc_answer_0(iid, (sysarg_t) EOK);
     431                        break;
     432               
     433                case NET_IL_RECEIVED:
     434                        rc = packet_translate_remote(arp_globals.net_phone, &packet,
     435                            IPC_GET_PACKET(*icall));
     436                        if (rc == EOK) {
     437                                fibril_mutex_lock(&arp_globals.lock);
     438                                do {
     439                                        packet_t *next = pq_detach(packet);
     440                                        rc = arp_receive_message(IPC_GET_DEVICE(*icall), packet);
     441                                        if (rc != 1) {
     442                                                pq_release_remote(arp_globals.net_phone,
     443                                                    packet_get_id(packet));
     444                                        }
     445                                       
     446                                        packet = next;
     447                                } while (packet);
     448                                fibril_mutex_unlock(&arp_globals.lock);
     449                        }
     450                        ipc_answer_0(iid, (sysarg_t) rc);
     451                        break;
     452               
     453                case NET_IL_MTU_CHANGED:
     454                        rc = arp_mtu_changed_message(IPC_GET_DEVICE(*icall),
     455                            IPC_GET_MTU(*icall));
     456                        ipc_answer_0(iid, (sysarg_t) rc);
     457                        break;
     458               
     459                default:
     460                        ipc_answer_0(iid, (sysarg_t) ENOTSUP);
     461                }
     462               
     463                iid = async_get_call(icall);
     464        }
     465}
     466
     467/** Register the device.
     468 *
     469 * Create new device entry in the cache or update the protocol address if the
     470 * device with the device identifier and the driver service exists.
     471 *
     472 * @param[in] device_id Device identifier.
     473 * @param[in] service   Device driver service.
     474 * @param[in] protocol  Protocol service.
     475 * @param[in] address   Actual device protocol address.
     476 *
     477 * @return EOK on success.
     478 * @return EEXIST if another device with the same device identifier
     479 *         and different driver service exists.
     480 * @return ENOMEM if there is not enough memory left.
     481 * @return Other error codes as defined for the
     482 *         measured_strings_return() function.
     483 *
     484 */
     485static int arp_device_message(device_id_t device_id, services_t service,
     486    services_t protocol, measured_string_t *address)
     487{
     488        int index;
     489        int rc;
     490       
     491        fibril_mutex_lock(&arp_globals.lock);
     492       
     493        /* An existing device? */
     494        arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
     495        if (device) {
     496                if (device->service != service) {
     497                        printf("%s: Device %d already exists\n", NAME,
     498                            device->device_id);
     499                        fibril_mutex_unlock(&arp_globals.lock);
     500                        return EEXIST;
     501                }
     502               
     503                arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
     504                if (proto) {
     505                        free(proto->addr);
     506                        free(proto->addr_data);
     507                        proto->addr = address;
     508                        proto->addr_data = address->value;
     509                } else {
     510                        rc = arp_proto_create(&proto, protocol, address);
     511                        if (rc != EOK) {
     512                                fibril_mutex_unlock(&arp_globals.lock);
     513                                return rc;
     514                        }
     515                       
     516                        index = arp_protos_add(&device->protos, proto->service,
     517                            proto);
     518                        if (index < 0) {
     519                                fibril_mutex_unlock(&arp_globals.lock);
     520                                free(proto);
     521                                return index;
     522                        }
     523                       
     524                        printf("%s: New protocol added (id: %d, proto: %d)\n", NAME,
     525                            device_id, protocol);
     526                }
     527        } else {
     528                hw_type_t hardware = hardware_map(service);
     529                if (!hardware)
     530                        return ENOENT;
     531               
     532                /* Create new device */
     533                device = (arp_device_t *) malloc(sizeof(arp_device_t));
     534                if (!device) {
     535                        fibril_mutex_unlock(&arp_globals.lock);
     536                        return ENOMEM;
     537                }
     538               
     539                device->hardware = hardware;
     540                device->device_id = device_id;
     541                rc = arp_protos_initialize(&device->protos);
     542                if (rc != EOK) {
     543                        fibril_mutex_unlock(&arp_globals.lock);
     544                        free(device);
     545                        return rc;
     546                }
     547               
     548                arp_proto_t *proto;
     549                rc = arp_proto_create(&proto, protocol, address);
     550                if (rc != EOK) {
     551                        fibril_mutex_unlock(&arp_globals.lock);
     552                        free(device);
     553                        return rc;
     554                }
     555               
     556                index = arp_protos_add(&device->protos, proto->service, proto);
     557                if (index < 0) {
     558                        fibril_mutex_unlock(&arp_globals.lock);
     559                        arp_protos_destroy(&device->protos);
     560                        free(device);
     561                        return index;
     562                }
     563               
     564                device->service = service;
     565               
     566                /* Bind */
     567                device->phone = nil_bind_service(device->service,
     568                    (sysarg_t) device->device_id, SERVICE_ARP,
     569                    arp_receiver);
     570                if (device->phone < 0) {
     571                        fibril_mutex_unlock(&arp_globals.lock);
     572                        arp_protos_destroy(&device->protos);
     573                        free(device);
     574                        return EREFUSED;
     575                }
     576               
     577                /* Get packet dimensions */
     578                rc = nil_packet_size_req(device->phone, device_id,
     579                    &device->packet_dimension);
     580                if (rc != EOK) {
     581                        fibril_mutex_unlock(&arp_globals.lock);
     582                        arp_protos_destroy(&device->protos);
     583                        free(device);
     584                        return rc;
     585                }
     586               
     587                /* Get hardware address */
     588                rc = nil_get_addr_req(device->phone, device_id, &device->addr,
     589                    &device->addr_data);
     590                if (rc != EOK) {
     591                        fibril_mutex_unlock(&arp_globals.lock);
     592                        arp_protos_destroy(&device->protos);
     593                        free(device);
     594                        return rc;
     595                }
     596               
     597                /* Get broadcast address */
     598                rc = nil_get_broadcast_addr_req(device->phone, device_id,
     599                    &device->broadcast_addr, &device->broadcast_data);
     600                if (rc != EOK) {
     601                        fibril_mutex_unlock(&arp_globals.lock);
     602                        free(device->addr);
     603                        free(device->addr_data);
     604                        arp_protos_destroy(&device->protos);
     605                        free(device);
     606                        return rc;
     607                }
     608               
     609                rc = arp_cache_add(&arp_globals.cache, device->device_id,
     610                    device);
     611                if (rc != EOK) {
     612                        fibril_mutex_unlock(&arp_globals.lock);
     613                        free(device->addr);
     614                        free(device->addr_data);
     615                        free(device->broadcast_addr);
     616                        free(device->broadcast_data);
     617                        arp_protos_destroy(&device->protos);
     618                        free(device);
     619                        return rc;
     620                }
     621                printf("%s: Device registered (id: %d, type: 0x%x, service: %d,"
     622                    " proto: %d)\n", NAME, device->device_id, device->hardware,
     623                    device->service, protocol);
     624        }
     625       
     626        fibril_mutex_unlock(&arp_globals.lock);
     627        return EOK;
     628}
     629
     630int il_initialize(int net_phone)
     631{
     632        fibril_mutex_initialize(&arp_globals.lock);
     633       
     634        fibril_mutex_lock(&arp_globals.lock);
     635        arp_globals.net_phone = net_phone;
     636        int rc = arp_cache_initialize(&arp_globals.cache);
     637        fibril_mutex_unlock(&arp_globals.lock);
     638       
     639        return rc;
     640}
     641
     642static int arp_send_request(device_id_t device_id, services_t protocol,
     643    measured_string_t *target, arp_device_t *device, arp_proto_t *proto)
     644{
    551645        /* ARP packet content size = header + (address + translation) * 2 */
    552         length = 8 + 2 * (CONVERT_SIZE(char, uint8_t, proto->addr->length) +
    553             CONVERT_SIZE(char, uint8_t, device->addr->length));
     646        size_t length = 8 + 2 * (proto->addr->length + device->addr->length);
    554647        if (length > device->packet_dimension.content)
    555                 return NULL;
    556 
    557         packet = packet_get_4_remote(arp_globals.net_phone,
     648                return ELIMIT;
     649       
     650        packet_t *packet = packet_get_4_remote(arp_globals.net_phone,
    558651            device->packet_dimension.addr_len, device->packet_dimension.prefix,
    559652            length, device->packet_dimension.suffix);
    560653        if (!packet)
    561                 return NULL;
    562 
    563         header = (arp_header_t *) packet_suffix(packet, length);
     654                return ENOMEM;
     655       
     656        arp_header_t *header = (arp_header_t *) packet_suffix(packet, length);
    564657        if (!header) {
    565658                pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
    566                 return NULL;
    567         }
    568 
     659                return ENOMEM;
     660        }
     661       
    569662        header->hardware = htons(device->hardware);
    570663        header->hardware_length = (uint8_t) device->addr->length;
     
    572665        header->protocol_length = (uint8_t) proto->addr->length;
    573666        header->operation = htons(ARPOP_REQUEST);
     667       
    574668        length = sizeof(arp_header_t);
     669       
    575670        memcpy(((uint8_t *) header) + length, device->addr->value,
    576671            device->addr->length);
     
    582677        length += device->addr->length;
    583678        memcpy(((uint8_t *) header) + length, target->value, target->length);
    584 
    585         if (packet_set_addr(packet, (uint8_t *) device->addr->value,
    586             (uint8_t *) device->broadcast_addr->value,
    587             CONVERT_SIZE(char, uint8_t, device->addr->length)) != EOK) {
     679       
     680        int rc = packet_set_addr(packet, (uint8_t *) device->addr->value,
     681            (uint8_t *) device->broadcast_addr->value, device->addr->length);
     682        if (rc != EOK) {
    588683                pq_release_remote(arp_globals.net_phone, packet_get_id(packet));
    589                 return NULL;
    590         }
    591 
     684                return rc;
     685        }
     686       
    592687        nil_send_msg(device->phone, device_id, packet, SERVICE_ARP);
    593         return NULL;
    594 }
    595 
    596 
    597 /** Processes the ARP message.
    598  *
    599  * @param[in] callid    The message identifier.
    600  * @param[in] call      The message parameters.
    601  * @param[out] answer   The message answer parameters.
    602  * @param[out] answer_count The last parameter for the actual answer in the
    603  *                      answer parameter.
    604  * @return              EOK on success.
    605  * @return              ENOTSUP if the message is not known.
     688        return EOK;
     689}
     690
     691/** Return the hardware address for the given protocol address.
     692 *
     693 * Send the ARP request packet if the hardware address is not found in the
     694 * cache.
     695 *
     696 * @param[in]  device_id   Device identifier.
     697 * @param[in]  protocol    Protocol service.
     698 * @param[in]  target      Target protocol address.
     699 * @param[out] translation Where the hardware address of the target is stored.
     700 *
     701 * @return EOK on success.
     702 * @return EAGAIN if the caller should try again.
     703 * @return Other error codes in case of error.
     704 *
     705 */
     706static int arp_translate_message(device_id_t device_id, services_t protocol,
     707    measured_string_t *target, measured_string_t **translation)
     708{
     709        bool retry = false;
     710        int rc;
     711
     712        assert(fibril_mutex_is_locked(&arp_globals.lock));
     713       
     714restart:
     715        if ((!target) || (!translation))
     716                return EBADMEM;
     717       
     718        arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
     719        if (!device)
     720                return ENOENT;
     721       
     722        arp_proto_t *proto = arp_protos_find(&device->protos, protocol);
     723        if ((!proto) || (proto->addr->length != target->length))
     724                return ENOENT;
     725       
     726        arp_trans_t *trans = arp_addr_find(&proto->addresses, target->value,
     727            target->length);
     728        if (trans) {
     729                if (trans->hw_addr) {
     730                        /* The translation is in place. */
     731                        *translation = trans->hw_addr;
     732                        return EOK;
     733                }
     734               
     735                if (retry) {
     736                        /*
     737                         * We may get here as a result of being signalled for
     738                         * some reason while waiting for the translation (e.g.
     739                         * translation becoming available, record being removed
     740                         * from the table) and then losing the race for
     741                         * the arp_globals.lock with someone else who modified
     742                         * the table.
     743                         *
     744                         * Remove the incomplete record so that it is possible
     745                         * to make new ARP requests.
     746                         */
     747                        arp_clear_trans(trans);
     748                        arp_addr_exclude(&proto->addresses, target->value,
     749                            target->length);
     750                        return EAGAIN;
     751                }
     752               
     753                /*
     754                 * We are a random passer-by who merely joins an already waiting
     755                 * fibril in waiting for the translation.
     756                 */
     757                rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
     758                    ARP_TRANS_WAIT);
     759                if (rc == ETIMEOUT)
     760                        return ENOENT;
     761               
     762                /*
     763                 * Need to recheck because we did not hold the lock while
     764                 * sleeping on the condition variable.
     765                 */
     766                retry = true;
     767                goto restart;
     768        }
     769       
     770        if (retry)
     771                return EAGAIN;
     772
     773        /*
     774         * We are under the protection of arp_globals.lock, so we can afford to
     775         * first send the ARP request and then insert an incomplete ARP record.
     776         * The incomplete record is used to tell any other potential waiter
     777         * that this fibril has already sent the request and that it is waiting
     778         * for the answer. Lastly, any fibril which sees the incomplete request
     779         * can perform a timed wait on its condition variable to wait for the
     780         * ARP reply to arrive.
     781         */
     782
     783        rc = arp_send_request(device_id, protocol, target, device, proto);
     784        if (rc != EOK)
     785                return rc;
     786       
     787        trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
     788        if (!trans)
     789                return ENOMEM;
     790       
     791        trans->hw_addr = NULL;
     792        fibril_condvar_initialize(&trans->cv);
     793       
     794        rc = arp_addr_add(&proto->addresses, target->value, target->length,
     795            trans);
     796        if (rc != EOK) {
     797                /* The generic char map has already freed trans! */
     798                return rc;
     799        }
     800       
     801        rc = fibril_condvar_wait_timeout(&trans->cv, &arp_globals.lock,
     802            ARP_TRANS_WAIT);
     803        if (rc == ETIMEOUT) {
     804                /*
     805                 * Remove the incomplete record so that it is possible to make
     806                 * new ARP requests.
     807                 */
     808                arp_clear_trans(trans);
     809                arp_addr_exclude(&proto->addresses, target->value,
     810                    target->length);
     811                return ENOENT;
     812        }
     813       
     814        /*
     815         * We need to recheck that the translation has indeed become available,
     816         * because we dropped the arp_globals.lock while sleeping on the
     817         * condition variable and someone else might have e.g. removed the
     818         * translation before we managed to lock arp_globals.lock again.
     819         */
     820
     821        retry = true;
     822        goto restart;
     823}
     824
     825/** Process the ARP message.
     826 *
     827 * @param[in]  callid Message identifier.
     828 * @param[in]  call   Message parameters.
     829 * @param[out] answer Answer.
     830 * @param[out] count  Number of arguments of the answer.
     831 *
     832 * @return EOK on success.
     833 * @return ENOTSUP if the message is not known.
    606834 *
    607835 * @see arp_interface.h
    608836 * @see IS_NET_ARP_MESSAGE()
    609  */
    610 int
    611 arp_message_standalone(ipc_callid_t callid, ipc_call_t *call,
    612     ipc_call_t *answer, int *answer_count)
     837 *
     838 */
     839int il_module_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
     840    size_t *count)
    613841{
    614842        measured_string_t *address;
    615843        measured_string_t *translation;
    616         char *data;
    617         packet_t *packet;
    618         packet_t *next;
     844        uint8_t *data;
    619845        int rc;
    620846       
    621         *answer_count = 0;
    622         switch (IPC_GET_METHOD(*call)) {
     847        *count = 0;
     848        switch (IPC_GET_IMETHOD(*call)) {
    623849        case IPC_M_PHONE_HUNGUP:
    624850                return EOK;
     
    629855                        return rc;
    630856               
    631                 rc = arp_device_message(IPC_GET_DEVICE(call),
    632                     IPC_GET_SERVICE(call), ARP_GET_NETIF(call), address);
     857                rc = arp_device_message(IPC_GET_DEVICE(*call),
     858                    IPC_GET_SERVICE(*call), ARP_GET_NETIF(*call), address);
    633859                if (rc != EOK) {
    634860                        free(address);
    635861                        free(data);
    636862                }
     863               
    637864                return rc;
    638865       
     
    642869                        return rc;
    643870               
    644                 fibril_rwlock_read_lock(&arp_globals.lock);
    645                 translation = arp_translate_message(IPC_GET_DEVICE(call),
    646                     IPC_GET_SERVICE(call), address);
     871                fibril_mutex_lock(&arp_globals.lock);
     872                rc = arp_translate_message(IPC_GET_DEVICE(*call),
     873                    IPC_GET_SERVICE(*call), address, &translation);
    647874                free(address);
    648875                free(data);
     876               
     877                if (rc != EOK) {
     878                        fibril_mutex_unlock(&arp_globals.lock);
     879                        return rc;
     880                }
     881               
    649882                if (!translation) {
    650                         fibril_rwlock_read_unlock(&arp_globals.lock);
     883                        fibril_mutex_unlock(&arp_globals.lock);
    651884                        return ENOENT;
    652885                }
     886               
    653887                rc = measured_strings_reply(translation, 1);
    654                 fibril_rwlock_read_unlock(&arp_globals.lock);
     888                fibril_mutex_unlock(&arp_globals.lock);
    655889                return rc;
    656 
     890       
    657891        case NET_ARP_CLEAR_DEVICE:
    658                 return arp_clear_device_req(0, IPC_GET_DEVICE(call));
    659 
     892                return arp_clear_device_req(0, IPC_GET_DEVICE(*call));
     893       
    660894        case NET_ARP_CLEAR_ADDRESS:
    661895                rc = measured_strings_receive(&address, &data, 1);
     
    663897                        return rc;
    664898               
    665                 arp_clear_address_req(0, IPC_GET_DEVICE(call),
    666                     IPC_GET_SERVICE(call), address);
     899                arp_clear_address_req(0, IPC_GET_DEVICE(*call),
     900                    IPC_GET_SERVICE(*call), address);
    667901                free(address);
    668902                free(data);
     
    671905        case NET_ARP_CLEAN_CACHE:
    672906                return arp_clean_cache_req(0);
    673        
    674         case NET_IL_DEVICE_STATE:
    675                 /* Do nothing - keep the cache */
    676                 return EOK;
    677        
    678         case NET_IL_RECEIVED:
    679                 rc = packet_translate_remote(arp_globals.net_phone, &packet,
    680                     IPC_GET_PACKET(call));
    681                 if (rc != EOK)
    682                         return rc;
    683                
    684                 fibril_rwlock_read_lock(&arp_globals.lock);
    685                 do {
    686                         next = pq_detach(packet);
    687                         rc = arp_receive_message(IPC_GET_DEVICE(call), packet);
    688                         if (rc != 1) {
    689                                 pq_release_remote(arp_globals.net_phone,
    690                                     packet_get_id(packet));
    691                         }
    692                         packet = next;
    693                 } while (packet);
    694                 fibril_rwlock_read_unlock(&arp_globals.lock);
    695                
    696                 return EOK;
    697        
    698         case NET_IL_MTU_CHANGED:
    699                 return arp_mtu_changed_message(IPC_GET_DEVICE(call),
    700                     IPC_GET_MTU(call));
    701907        }
    702908       
     
    704910}
    705911
    706 /** Default thread for new connections.
    707  *
    708  * @param[in] iid       The initial message identifier.
    709  * @param[in] icall     The initial message call structure.
    710  */
    711 static void il_client_connection(ipc_callid_t iid, ipc_call_t *icall)
    712 {
    713         /*
    714          * Accept the connection
    715          *  - Answer the first IPC_M_CONNECT_ME_TO call.
    716          */
    717         ipc_answer_0(iid, EOK);
    718        
    719         while (true) {
    720                 ipc_call_t answer;
    721                 int answer_count;
    722                
    723                 /* Clear the answer structure */
    724                 refresh_answer(&answer, &answer_count);
    725                
    726                 /* Fetch the next message */
    727                 ipc_call_t call;
    728                 ipc_callid_t callid = async_get_call(&call);
    729                
    730                 /* Process the message */
    731                 int res = il_module_message_standalone(callid, &call, &answer,
    732                     &answer_count);
    733                
    734                 /*
    735                  * End if told to either by the message or the processing
    736                  * result.
    737                  */
    738                 if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) ||
    739                     (res == EHANGUP))
    740                         return;
    741                
    742                 /* Answer the message */
    743                 answer_call(callid, res, &answer, answer_count);
    744         }
    745 }
    746 
    747 /** Starts the module.
    748  *
    749  * @return              EOK on success.
    750  * @return              Other error codes as defined for each specific module
    751  *                      start function.
    752  */
    753912int main(int argc, char *argv[])
    754913{
    755         int rc;
    756        
    757914        /* Start the module */
    758         rc = il_module_start_standalone(il_client_connection);
    759         return rc;
     915        return il_module_start(SERVICE_ARP);
    760916}
    761917
    762918/** @}
    763919 */
    764 
Note: See TracChangeset for help on using the changeset viewer.