nildummy.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 <stdio.h>
00042 #include <str.h>
00043 #include <ipc/nil.h>
00044 #include <ipc/net.h>
00045 #include <ipc/services.h>
00046 
00047 #include <net/modules.h>
00048 #include <net/device.h>
00049 #include <il_remote.h>
00050 #include <adt/measured_strings.h>
00051 #include <net/packet.h>
00052 #include <packet_remote.h>
00053 #include <netif_remote.h>
00054 #include <nil_skel.h>
00055 
00056 #include "nildummy.h"
00057 
00059 #define NAME  "nildummy"
00060 
00062 #define NET_DEFAULT_MTU  1500
00063 
00065 nildummy_globals_t nildummy_globals;
00066 
00067 DEVICE_MAP_IMPLEMENT(nildummy_devices, nildummy_device_t);
00068 
00069 int nil_device_state_msg_local(int nil_phone, device_id_t device_id, int state)
00070 {
00071         fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
00072         if (nildummy_globals.proto.phone)
00073                 il_device_state_msg(nildummy_globals.proto.phone, device_id,
00074                     state, nildummy_globals.proto.service);
00075         fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
00076         
00077         return EOK;
00078 }
00079 
00080 int nil_initialize(int net_phone)
00081 {
00082         fibril_rwlock_initialize(&nildummy_globals.devices_lock);
00083         fibril_rwlock_initialize(&nildummy_globals.protos_lock);
00084         fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
00085         fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
00086         
00087         nildummy_globals.net_phone = net_phone;
00088         nildummy_globals.proto.phone = 0;
00089         int rc = nildummy_devices_initialize(&nildummy_globals.devices);
00090         
00091         fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
00092         fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
00093         
00094         return rc;
00095 }
00096 
00103 static void nildummy_receiver(ipc_callid_t iid, ipc_call_t *icall)
00104 {
00105         packet_t *packet;
00106         int rc;
00107         
00108         while (true) {
00109                 switch (IPC_GET_IMETHOD(*icall)) {
00110                 case NET_NIL_DEVICE_STATE:
00111                         rc = nil_device_state_msg_local(0,
00112                             IPC_GET_DEVICE(*icall), IPC_GET_STATE(*icall));
00113                         async_answer_0(iid, (sysarg_t) rc);
00114                         break;
00115                 
00116                 case NET_NIL_RECEIVED:
00117                         rc = packet_translate_remote(nildummy_globals.net_phone,
00118                             &packet, IPC_GET_PACKET(*icall));
00119                         if (rc == EOK)
00120                                 rc = nil_received_msg_local(0,
00121                                     IPC_GET_DEVICE(*icall), packet, 0);
00122                         
00123                         async_answer_0(iid, (sysarg_t) rc);
00124                         break;
00125                 
00126                 default:
00127                         async_answer_0(iid, (sysarg_t) ENOTSUP);
00128                 }
00129                 
00130                 iid = async_get_call(icall);
00131         }
00132 }
00133 
00151 static int nildummy_device_message(device_id_t device_id, services_t service,
00152     size_t mtu)
00153 {
00154         fibril_rwlock_write_lock(&nildummy_globals.devices_lock);
00155         
00156         /* An existing device? */
00157         nildummy_device_t *device =
00158             nildummy_devices_find(&nildummy_globals.devices, device_id);
00159         if (device) {
00160                 if (device->service != service) {
00161                         printf("Device %d already exists\n", device->device_id);
00162                         fibril_rwlock_write_unlock(
00163                             &nildummy_globals.devices_lock);
00164                         return EEXIST;
00165                 }
00166                 
00167                 /* Update MTU */
00168                 if (mtu > 0)
00169                         device->mtu = mtu;
00170                 else
00171                         device->mtu = NET_DEFAULT_MTU;
00172                 
00173                 printf("Device %d already exists:\tMTU\t= %zu\n",
00174                     device->device_id, device->mtu);
00175                 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
00176                 
00177                 /* Notify the upper layer module */
00178                 fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
00179                 if (nildummy_globals.proto.phone) {
00180                         il_mtu_changed_msg(nildummy_globals.proto.phone,
00181                             device->device_id, device->mtu,
00182                             nildummy_globals.proto.service);
00183                 }
00184                 fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
00185                 
00186                 return EOK;
00187         }
00188         
00189         /* Create a new device */
00190         device = (nildummy_device_t *) malloc(sizeof(nildummy_device_t));
00191         if (!device)
00192                 return ENOMEM;
00193         
00194         device->device_id = device_id;
00195         device->service = service;
00196         if (mtu > 0)
00197                 device->mtu = mtu;
00198         else
00199                 device->mtu = NET_DEFAULT_MTU;
00200 
00201         /* Bind the device driver */
00202         device->phone = netif_bind_service(device->service, device->device_id,
00203             SERVICE_ETHERNET, nildummy_receiver);
00204         if (device->phone < 0) {
00205                 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
00206                 free(device);
00207                 return device->phone;
00208         }
00209         
00210         /* Get hardware address */
00211         int rc = netif_get_addr_req(device->phone, device->device_id,
00212             &device->addr, &device->addr_data);
00213         if (rc != EOK) {
00214                 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
00215                 free(device);
00216                 return rc;
00217         }
00218         
00219         /* Add to the cache */
00220         int index = nildummy_devices_add(&nildummy_globals.devices,
00221             device->device_id, device);
00222         if (index < 0) {
00223                 fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
00224                 free(device->addr);
00225                 free(device->addr_data);
00226                 free(device);
00227                 return index;
00228         }
00229         
00230         printf("%s: Device registered (id: %d, service: %d, mtu: %zu)\n",
00231             NAME, device->device_id, device->service, device->mtu);
00232         fibril_rwlock_write_unlock(&nildummy_globals.devices_lock);
00233         return EOK;
00234 }
00235 
00246 static int nildummy_addr_message(device_id_t device_id,
00247     measured_string_t **address)
00248 {
00249         if (!address)
00250                 return EBADMEM;
00251         
00252         fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
00253         
00254         nildummy_device_t *device =
00255             nildummy_devices_find(&nildummy_globals.devices, device_id);
00256         if (!device) {
00257                 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
00258                 return ENOENT;
00259         }
00260         
00261         *address = device->addr;
00262         
00263         fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
00264         
00265         return (*address) ? EOK : ENOENT;
00266 }
00267 
00281 static int nildummy_packet_space_message(device_id_t device_id, size_t *addr_len,
00282     size_t *prefix, size_t *content, size_t *suffix)
00283 {
00284         if ((!addr_len) || (!prefix) || (!content) || (!suffix))
00285                 return EBADMEM;
00286         
00287         fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
00288         
00289         nildummy_device_t *device =
00290             nildummy_devices_find(&nildummy_globals.devices, device_id);
00291         if (!device) {
00292                 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
00293                 return ENOENT;
00294         }
00295         
00296         *content = device->mtu;
00297         
00298         fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
00299         
00300         *addr_len = 0;
00301         *prefix = 0;
00302         *suffix = 0;
00303         return EOK;
00304 }
00305 
00306 int nil_received_msg_local(int nil_phone, device_id_t device_id,
00307     packet_t *packet, services_t target)
00308 {
00309         fibril_rwlock_read_lock(&nildummy_globals.protos_lock);
00310         
00311         if (nildummy_globals.proto.phone) {
00312                 do {
00313                         packet_t *next = pq_detach(packet);
00314                         il_received_msg(nildummy_globals.proto.phone, device_id,
00315                             packet, nildummy_globals.proto.service);
00316                         packet = next;
00317                 } while (packet);
00318         }
00319         
00320         fibril_rwlock_read_unlock(&nildummy_globals.protos_lock);
00321         
00322         return EOK;
00323 }
00324 
00337 static int nildummy_register_message(services_t service, int phone)
00338 {
00339         fibril_rwlock_write_lock(&nildummy_globals.protos_lock);
00340         nildummy_globals.proto.service = service;
00341         nildummy_globals.proto.phone = phone;
00342         
00343         printf("%s: Protocol registered (service: %d, phone: %d)\n",
00344             NAME, nildummy_globals.proto.service, nildummy_globals.proto.phone);
00345         
00346         fibril_rwlock_write_unlock(&nildummy_globals.protos_lock);
00347         return EOK;
00348 }
00349 
00361 static int nildummy_send_message(device_id_t device_id, packet_t *packet,
00362     services_t sender)
00363 {
00364         fibril_rwlock_read_lock(&nildummy_globals.devices_lock);
00365         
00366         nildummy_device_t *device =
00367             nildummy_devices_find(&nildummy_globals.devices, device_id);
00368         if (!device) {
00369                 fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
00370                 return ENOENT;
00371         }
00372         
00373         /* Send packet queue */
00374         if (packet)
00375                 netif_send_msg(device->phone, device_id, packet,
00376                     SERVICE_NILDUMMY);
00377         
00378         fibril_rwlock_read_unlock(&nildummy_globals.devices_lock);
00379         
00380         return EOK;
00381 }
00382 
00383 int nil_module_message(ipc_callid_t callid, ipc_call_t *call,
00384     ipc_call_t *answer, size_t *answer_count)
00385 {
00386         measured_string_t *address;
00387         packet_t *packet;
00388         size_t addrlen;
00389         size_t prefix;
00390         size_t suffix;
00391         size_t content;
00392         int rc;
00393         
00394         *answer_count = 0;
00395         switch (IPC_GET_IMETHOD(*call)) {
00396         case IPC_M_PHONE_HUNGUP:
00397                 return EOK;
00398         
00399         case NET_NIL_DEVICE:
00400                 return nildummy_device_message(IPC_GET_DEVICE(*call),
00401                     IPC_GET_SERVICE(*call), IPC_GET_MTU(*call));
00402         
00403         case NET_NIL_SEND:
00404                 rc = packet_translate_remote(nildummy_globals.net_phone,
00405                     &packet, IPC_GET_PACKET(*call));
00406                 if (rc != EOK)
00407                         return rc;
00408                 return nildummy_send_message(IPC_GET_DEVICE(*call), packet,
00409                     IPC_GET_SERVICE(*call));
00410         
00411         case NET_NIL_PACKET_SPACE:
00412                 rc = nildummy_packet_space_message(IPC_GET_DEVICE(*call),
00413                     &addrlen, &prefix, &content, &suffix);
00414                 if (rc != EOK)
00415                         return rc;
00416                 IPC_SET_ADDR(*answer, addrlen);
00417                 IPC_SET_PREFIX(*answer, prefix);
00418                 IPC_SET_CONTENT(*answer, content);
00419                 IPC_SET_SUFFIX(*answer, suffix);
00420                 *answer_count = 4;
00421                 return EOK;
00422         
00423         case NET_NIL_ADDR:
00424                 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &address);
00425                 if (rc != EOK)
00426                         return rc;
00427                 return measured_strings_reply(address, 1);
00428         
00429         case NET_NIL_BROADCAST_ADDR:
00430                 rc = nildummy_addr_message(IPC_GET_DEVICE(*call), &address);
00431                 if (rc != EOK)
00432                         return rc;
00433                 return measured_strings_reply(address, 1);
00434         
00435         case IPC_M_CONNECT_TO_ME:
00436                 return nildummy_register_message(NIL_GET_PROTO(*call),
00437                     IPC_GET_PHONE(*call));
00438         }
00439         
00440         return ENOTSUP;
00441 }
00442 
00443 int main(int argc, char *argv[])
00444 {
00445         /* Start the module */
00446         return nil_module_start(SERVICE_NILDUMMY);
00447 }
00448 

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