Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/inetsrv/inet_link.c

    r417a2ba1 r4a5a18be  
    4343#include <stdlib.h>
    4444#include <str.h>
     45
    4546#include "addrobj.h"
    4647#include "inetsrv.h"
     
    4849#include "pdu.h"
    4950
    50 static bool first_link = true;
    51 static bool first_link6 = true;
    52 
    53 static FIBRIL_MUTEX_INITIALIZE(ip_ident_lock);
    54 static uint16_t ip_ident = 0;
    55 
    56 static int inet_iplink_recv(iplink_t *, iplink_recv_sdu_t *, ip_ver_t);
    57 static inet_link_t *inet_link_get_by_id_locked(sysarg_t);
     51static int inet_link_open(service_id_t sid);
     52static int inet_iplink_recv(iplink_t *ilink, iplink_sdu_t *sdu);
    5853
    5954static iplink_ev_ops_t inet_iplink_ev_ops = {
     
    6156};
    6257
    63 static LIST_INITIALIZE(inet_links);
    64 static FIBRIL_MUTEX_INITIALIZE(inet_links_lock);
    65 
    66 static addr128_t link_local_node_ip =
    67     {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0, 0, 0};
    68 
    69 static void inet_link_local_node_ip(addr48_t mac_addr,
    70     addr128_t ip_addr)
    71 {
    72         memcpy(ip_addr, link_local_node_ip, 16);
    73        
    74         ip_addr[8] = mac_addr[0] ^ 0x02;
    75         ip_addr[9] = mac_addr[1];
    76         ip_addr[10] = mac_addr[2];
    77         ip_addr[13] = mac_addr[3];
    78         ip_addr[14] = mac_addr[4];
    79         ip_addr[15] = mac_addr[5];
    80 }
    81 
    82 static int inet_iplink_recv(iplink_t *iplink, iplink_recv_sdu_t *sdu, ip_ver_t ver)
    83 {
     58static LIST_INITIALIZE(inet_link_list);
     59static FIBRIL_MUTEX_INITIALIZE(inet_discovery_lock);
     60
     61static int inet_iplink_recv(iplink_t *iplink, iplink_sdu_t *sdu)
     62{
     63        inet_packet_t packet;
     64        int rc;
     65
    8466        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
    85        
    86         int rc;
    87         inet_packet_t packet;
    88        
    89         switch (ver) {
    90         case ip_v4:
    91                 rc = inet_pdu_decode(sdu->data, sdu->size, &packet);
    92                 break;
    93         case ip_v6:
    94                 rc = inet_pdu_decode6(sdu->data, sdu->size, &packet);
    95                 break;
    96         default:
    97                 log_msg(LOG_DEFAULT, LVL_DEBUG, "invalid IP version");
    98                 return EINVAL;
    99         }
    100        
     67        rc = inet_pdu_decode(sdu->data, sdu->size, &packet);
    10168        if (rc != EOK) {
    10269                log_msg(LOG_DEFAULT, LVL_DEBUG, "failed decoding PDU");
    10370                return rc;
    10471        }
    105        
     72
    10673        log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet()");
    10774        rc = inet_recv_packet(&packet);
    10875        log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet -> %d", rc);
    10976        free(packet.data);
    110        
     77
    11178        return rc;
     79}
     80
     81static int inet_link_check_new(void)
     82{
     83        bool already_known;
     84        category_id_t iplink_cat;
     85        service_id_t *svcs;
     86        size_t count, i;
     87        int rc;
     88
     89        fibril_mutex_lock(&inet_discovery_lock);
     90
     91        rc = loc_category_get_id("iplink", &iplink_cat, IPC_FLAG_BLOCKING);
     92        if (rc != EOK) {
     93                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed resolving category 'iplink'.");
     94                fibril_mutex_unlock(&inet_discovery_lock);
     95                return ENOENT;
     96        }
     97
     98        rc = loc_category_get_svcs(iplink_cat, &svcs, &count);
     99        if (rc != EOK) {
     100                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting list of IP links.");
     101                fibril_mutex_unlock(&inet_discovery_lock);
     102                return EIO;
     103        }
     104
     105        for (i = 0; i < count; i++) {
     106                already_known = false;
     107
     108                list_foreach(inet_link_list, ilink_link) {
     109                        inet_link_t *ilink = list_get_instance(ilink_link,
     110                            inet_link_t, link_list);
     111                        if (ilink->svc_id == svcs[i]) {
     112                                already_known = true;
     113                                break;
     114                        }
     115                }
     116
     117                if (!already_known) {
     118                        log_msg(LOG_DEFAULT, LVL_DEBUG, "Found IP link '%lu'",
     119                            (unsigned long) svcs[i]);
     120                        rc = inet_link_open(svcs[i]);
     121                        if (rc != EOK)
     122                                log_msg(LOG_DEFAULT, LVL_ERROR, "Could not open IP link.");
     123                }
     124        }
     125
     126        fibril_mutex_unlock(&inet_discovery_lock);
     127        return EOK;
    112128}
    113129
     
    131147        if (ilink->svc_name != NULL)
    132148                free(ilink->svc_name);
    133        
    134149        free(ilink);
    135150}
    136151
    137 int inet_link_open(service_id_t sid)
     152static int inet_link_open(service_id_t sid)
    138153{
    139154        inet_link_t *ilink;
    140         inet_addr_t iaddr;
     155        iplink_addr_t iaddr;
    141156        int rc;
    142157
     
    174189                goto error;
    175190        }
    176        
    177         /*
    178          * Get the MAC address of the link. If the link has a MAC
    179          * address, we assume that it supports NDP.
    180          */
    181         rc = iplink_get_mac48(ilink->iplink, &ilink->mac);
    182         ilink->mac_valid = (rc == EOK);
    183191
    184192        log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
    185 
    186         fibril_mutex_lock(&inet_links_lock);
    187 
    188         if (inet_link_get_by_id_locked(sid) != NULL) {
    189                 fibril_mutex_unlock(&inet_links_lock);
    190                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %zu already open",
    191                     sid);
    192                 rc = EEXIST;
    193                 goto error;
    194         }
    195 
    196         list_append(&ilink->link_list, &inet_links);
    197         fibril_mutex_unlock(&inet_links_lock);
    198 
    199         inet_addrobj_t *addr = NULL;
    200        
    201         /* XXX FIXME Cannot rely on loopback being the first IP link service!! */
    202         if (first_link) {
    203                 addr = inet_addrobj_new();
    204                
    205                 inet_naddr(&addr->naddr, 127, 0, 0, 1, 24);
    206                 first_link = false;
    207         }
    208        
    209         if (addr != NULL) {
    210                 addr->ilink = ilink;
    211                 addr->name = str_dup("v4a");
    212                
    213                 rc = inet_addrobj_add(addr);
    214                 if (rc == EOK) {
    215                         inet_naddr_addr(&addr->naddr, &iaddr);
    216                         rc = iplink_addr_add(ilink->iplink, &iaddr);
    217                         if (rc != EOK) {
    218                                 log_msg(LOG_DEFAULT, LVL_ERROR,
    219                                     "Failed setting IPv4 address on internet link.");
    220                                 inet_addrobj_remove(addr);
    221                                 inet_addrobj_delete(addr);
    222                         }
    223                 } else {
    224                         log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv4 address.");
    225                         inet_addrobj_delete(addr);
    226                 }
    227         }
    228        
    229         inet_addrobj_t *addr6 = NULL;
    230        
    231         if (first_link6) {
    232                 addr6 = inet_addrobj_new();
    233                
    234                 inet_naddr6(&addr6->naddr, 0, 0, 0, 0, 0, 0, 0, 1, 128);
    235                 first_link6 = false;
    236         } else if (ilink->mac_valid) {
    237                 addr6 = inet_addrobj_new();
    238                
    239                 addr128_t link_local;
    240                 inet_link_local_node_ip(ilink->mac, link_local);
    241                
    242                 inet_naddr_set6(link_local, 64, &addr6->naddr);
    243         }
    244        
    245         if (addr6 != NULL) {
    246                 addr6->ilink = ilink;
    247                 addr6->name = str_dup("v6a");
    248                
    249                 rc = inet_addrobj_add(addr6);
    250                 if (rc == EOK) {
    251                         inet_naddr_addr(&addr6->naddr, &iaddr);
    252                         rc = iplink_addr_add(ilink->iplink, &iaddr);
    253                         if (rc != EOK) {
    254                                 log_msg(LOG_DEFAULT, LVL_ERROR,
    255                                     "Failed setting IPv6 address on internet link.");
    256                                 inet_addrobj_remove(addr6);
    257                                 inet_addrobj_delete(addr6);
    258                         }
    259                 } else {
    260                         log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv6 address.");
    261                         inet_addrobj_delete(addr6);
    262                 }
    263         }
    264        
    265         log_msg(LOG_DEFAULT, LVL_DEBUG, "Configured link '%s'.", ilink->svc_name);
     193        list_append(&ilink->link_list, &inet_link_list);
     194
     195        inet_addrobj_t *addr;
     196
     197        static int first = 1;
     198        /* XXX For testing: set static IP address 10.0.2.15/24 */
     199        addr = inet_addrobj_new();
     200        if (first) {
     201                addr->naddr.ipv4 = (127 << 24) + (0 << 16) + (0 << 8) + 1;
     202                first = 0;
     203        } else {
     204                addr->naddr.ipv4 = (10 << 24) + (0 << 16) + (2 << 8) + 15;
     205        }
     206        addr->naddr.bits = 24;
     207        addr->ilink = ilink;
     208        addr->name = str_dup("v4a");
     209        rc = inet_addrobj_add(addr);
     210        if (rc != EOK) {
     211                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed setting IP address on internet link.");
     212                inet_addrobj_delete(addr);
     213                /* XXX Roll back */
     214                return rc;
     215        }
     216
     217        iaddr.ipv4 = addr->naddr.ipv4;
     218        rc = iplink_addr_add(ilink->iplink, &iaddr);
     219        if (rc != EOK) {
     220                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed setting IP address on internet link.");
     221                inet_addrobj_remove(addr);
     222                inet_addrobj_delete(addr);
     223                /* XXX Roll back */
     224                return rc;
     225        }
     226
    266227        return EOK;
    267        
     228
    268229error:
    269230        if (ilink->iplink != NULL)
    270231                iplink_close(ilink->iplink);
    271        
    272232        inet_link_delete(ilink);
    273233        return rc;
    274234}
    275235
    276 /** Send IPv4 datagram over Internet link
    277  *
    278  * @param ilink Internet link
    279  * @param lsrc  Source IPv4 address
    280  * @param ldest Destination IPv4 address
    281  * @param dgram IPv4 datagram body
    282  * @param proto Protocol
    283  * @param ttl   Time-to-live
    284  * @param df    Do-not-Fragment flag
    285  *
    286  * @return EOK on success
    287  * @return ENOMEM when not enough memory to create the datagram
    288  * @return ENOTSUP if networking mode is not supported
    289  *
    290  */
    291 int inet_link_send_dgram(inet_link_t *ilink, addr32_t lsrc, addr32_t ldest,
    292     inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
    293 {
    294         addr32_t src_v4;
    295         ip_ver_t src_ver = inet_addr_get(&dgram->src, &src_v4, NULL);
    296         if (src_ver != ip_v4)
    297                 return EINVAL;
    298        
    299         addr32_t dest_v4;
    300         ip_ver_t dest_ver = inet_addr_get(&dgram->dest, &dest_v4, NULL);
    301         if (dest_ver != ip_v4)
    302                 return EINVAL;
    303        
     236static void inet_link_cat_change_cb(void)
     237{
     238        (void) inet_link_check_new();
     239}
     240
     241int inet_link_discovery_start(void)
     242{
     243        int rc;
     244
     245        rc = loc_register_cat_change_cb(inet_link_cat_change_cb);
     246        if (rc != EOK) {
     247                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering callback for IP link "
     248                    "discovery (%d).", rc);
     249                return rc;
     250        }
     251
     252        return inet_link_check_new();
     253}
     254
     255/** Send datagram over Internet link */
     256int inet_link_send_dgram(inet_link_t *ilink, inet_addr_t *lsrc,
     257    inet_addr_t *ldest, inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
     258{
     259        iplink_sdu_t sdu;
     260        inet_packet_t packet;
     261        int rc;
     262        size_t offs, roffs;
     263
    304264        /*
    305265         * Fill packet structure. Fragmentation is performed by
    306266         * inet_pdu_encode().
    307267         */
    308        
    309         iplink_sdu_t sdu;
    310        
    311         sdu.src = lsrc;
    312         sdu.dest = ldest;
    313        
    314         inet_packet_t packet;
    315        
    316268        packet.src = dgram->src;
    317269        packet.dest = dgram->dest;
     
    319271        packet.proto = proto;
    320272        packet.ttl = ttl;
    321        
    322         /* Allocate identifier */
    323         fibril_mutex_lock(&ip_ident_lock);
    324         packet.ident = ++ip_ident;
    325         fibril_mutex_unlock(&ip_ident_lock);
    326        
    327273        packet.df = df;
    328274        packet.data = dgram->data;
    329275        packet.size = dgram->size;
    330        
    331         int rc;
    332         size_t offs = 0;
    333        
     276
     277        sdu.lsrc.ipv4 = lsrc->ipv4;
     278        sdu.ldest.ipv4 = ldest->ipv4;
     279
     280        offs = 0;
    334281        do {
    335282                /* Encode one fragment */
    336                
    337                 size_t roffs;
    338                 rc = inet_pdu_encode(&packet, src_v4, dest_v4, offs, ilink->def_mtu,
    339                     &sdu.data, &sdu.size, &roffs);
     283                rc = inet_pdu_encode(&packet, offs, ilink->def_mtu, &sdu.data,
     284                    &sdu.size, &roffs);
    340285                if (rc != EOK)
    341286                        return rc;
    342                
     287
    343288                /* Send the PDU */
    344289                rc = iplink_send(ilink->iplink, &sdu);
    345                
    346290                free(sdu.data);
     291
    347292                offs = roffs;
    348293        } while (offs < packet.size);
    349        
     294
    350295        return rc;
    351296}
    352297
    353 /** Send IPv6 datagram over Internet link
    354  *
    355  * @param ilink Internet link
    356  * @param ldest Destination MAC address
    357  * @param dgram IPv6 datagram body
    358  * @param proto Next header
    359  * @param ttl   Hop limit
    360  * @param df    Do-not-Fragment flag (unused)
    361  *
    362  * @return EOK on success
    363  * @return ENOMEM when not enough memory to create the datagram
    364  *
    365  */
    366 int inet_link_send_dgram6(inet_link_t *ilink, addr48_t ldest,
    367     inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
    368 {
    369         addr128_t src_v6;
    370         ip_ver_t src_ver = inet_addr_get(&dgram->src, NULL, &src_v6);
    371         if (src_ver != ip_v6)
    372                 return EINVAL;
    373        
    374         addr128_t dest_v6;
    375         ip_ver_t dest_ver = inet_addr_get(&dgram->dest, NULL, &dest_v6);
    376         if (dest_ver != ip_v6)
    377                 return EINVAL;
    378        
    379         iplink_sdu6_t sdu6;
    380         addr48(ldest, sdu6.dest);
    381        
    382         /*
    383          * Fill packet structure. Fragmentation is performed by
    384          * inet_pdu_encode6().
    385          */
    386        
    387         inet_packet_t packet;
    388        
    389         packet.src = dgram->src;
    390         packet.dest = dgram->dest;
    391         packet.tos = dgram->tos;
    392         packet.proto = proto;
    393         packet.ttl = ttl;
    394        
    395         /* Allocate identifier */
    396         fibril_mutex_lock(&ip_ident_lock);
    397         packet.ident = ++ip_ident;
    398         fibril_mutex_unlock(&ip_ident_lock);
    399        
    400         packet.df = df;
    401         packet.data = dgram->data;
    402         packet.size = dgram->size;
    403        
    404         int rc;
    405         size_t offs = 0;
    406        
    407         do {
    408                 /* Encode one fragment */
    409                
    410                 size_t roffs;
    411                 rc = inet_pdu_encode6(&packet, src_v6, dest_v6, offs, ilink->def_mtu,
    412                     &sdu6.data, &sdu6.size, &roffs);
    413                 if (rc != EOK)
    414                         return rc;
    415                
    416                 /* Send the PDU */
    417                 rc = iplink_send6(ilink->iplink, &sdu6);
    418                
    419                 free(sdu6.data);
    420                 offs = roffs;
    421         } while (offs < packet.size);
    422        
    423         return rc;
    424 }
    425 
    426 static inet_link_t *inet_link_get_by_id_locked(sysarg_t link_id)
    427 {
    428         assert(fibril_mutex_is_locked(&inet_links_lock));
    429 
    430         list_foreach(inet_links, link_list, inet_link_t, ilink) {
    431                 if (ilink->svc_id == link_id)
     298inet_link_t *inet_link_get_by_id(sysarg_t link_id)
     299{
     300        fibril_mutex_lock(&inet_discovery_lock);
     301
     302        list_foreach(inet_link_list, elem) {
     303                inet_link_t *ilink = list_get_instance(elem, inet_link_t,
     304                    link_list);
     305
     306                if (ilink->svc_id == link_id) {
     307                        fibril_mutex_unlock(&inet_discovery_lock);
    432308                        return ilink;
    433         }
    434 
     309                }
     310        }
     311
     312        fibril_mutex_unlock(&inet_discovery_lock);
    435313        return NULL;
    436 }
    437 
    438 inet_link_t *inet_link_get_by_id(sysarg_t link_id)
    439 {
    440         inet_link_t *ilink;
    441 
    442         fibril_mutex_lock(&inet_links_lock);
    443         ilink = inet_link_get_by_id_locked(link_id);
    444         fibril_mutex_unlock(&inet_links_lock);
    445 
    446         return ilink;
    447 }
    448 
    449 /** Get IDs of all links. */
    450 int inet_link_get_id_list(sysarg_t **rid_list, size_t *rcount)
    451 {
    452         sysarg_t *id_list;
    453         size_t count, i;
    454 
    455         fibril_mutex_lock(&inet_links_lock);
    456         count = list_count(&inet_links);
    457 
    458         id_list = calloc(count, sizeof(sysarg_t));
    459         if (id_list == NULL) {
    460                 fibril_mutex_unlock(&inet_links_lock);
    461                 return ENOMEM;
    462         }
    463 
    464         i = 0;
    465         list_foreach(inet_links, link_list, inet_link_t, ilink) {
    466                 id_list[i++] = ilink->svc_id;
    467                 log_msg(LOG_DEFAULT, LVL_NOTE, "add link to list");
    468         }
    469 
    470         fibril_mutex_unlock(&inet_links_lock);
    471 
    472         log_msg(LOG_DEFAULT, LVL_NOTE, "return %zu links", count);
    473         *rid_list = id_list;
    474         *rcount = count;
    475 
    476         return EOK;
    477314}
    478315
Note: See TracChangeset for help on using the changeset viewer.