Ignore:
File:
1 edited

Legend:

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

    ra1a101d rc3b25985  
    3535 */
    3636
    37 #include <bool.h>
     37#include <stdbool.h>
    3838#include <errno.h>
    3939#include <fibril_synch.h>
     
    4343#include <stdlib.h>
    4444#include <str.h>
    45 
    4645#include "addrobj.h"
    4746#include "inetsrv.h"
     
    4948#include "pdu.h"
    5049
    51 static int inet_link_open(service_id_t sid);
    52 static int inet_iplink_recv(iplink_t *ilink, iplink_sdu_t *sdu);
     50static bool first_link = true;
     51static bool first_link6 = true;
     52
     53static FIBRIL_MUTEX_INITIALIZE(ip_ident_lock);
     54static uint16_t ip_ident = 0;
     55
     56static int inet_iplink_recv(iplink_t *, iplink_recv_sdu_t *, ip_ver_t);
     57static int inet_iplink_change_addr(iplink_t *, addr48_t);
     58static inet_link_t *inet_link_get_by_id_locked(sysarg_t);
    5359
    5460static iplink_ev_ops_t inet_iplink_ev_ops = {
    55         .recv = inet_iplink_recv
     61        .recv = inet_iplink_recv,
     62        .change_addr = inet_iplink_change_addr,
    5663};
    5764
    58 static LIST_INITIALIZE(inet_link_list);
    59 static FIBRIL_MUTEX_INITIALIZE(inet_discovery_lock);
    60 
    61 static int inet_iplink_recv(iplink_t *iplink, iplink_sdu_t *sdu)
    62 {
     65static LIST_INITIALIZE(inet_links);
     66static FIBRIL_MUTEX_INITIALIZE(inet_links_lock);
     67
     68static addr128_t link_local_node_ip =
     69    {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0, 0, 0};
     70
     71static void inet_link_local_node_ip(addr48_t mac_addr,
     72    addr128_t ip_addr)
     73{
     74        memcpy(ip_addr, link_local_node_ip, 16);
     75       
     76        ip_addr[8] = mac_addr[0] ^ 0x02;
     77        ip_addr[9] = mac_addr[1];
     78        ip_addr[10] = mac_addr[2];
     79        ip_addr[13] = mac_addr[3];
     80        ip_addr[14] = mac_addr[4];
     81        ip_addr[15] = mac_addr[5];
     82}
     83
     84static int inet_iplink_recv(iplink_t *iplink, iplink_recv_sdu_t *sdu, ip_ver_t ver)
     85{
     86        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
     87       
     88        int rc;
    6389        inet_packet_t packet;
    64         int rc;
    65 
    66         log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
    67         rc = inet_pdu_decode(sdu->data, sdu->size, &packet);
     90       
     91        switch (ver) {
     92        case ip_v4:
     93                rc = inet_pdu_decode(sdu->data, sdu->size, &packet);
     94                break;
     95        case ip_v6:
     96                rc = inet_pdu_decode6(sdu->data, sdu->size, &packet);
     97                break;
     98        default:
     99                log_msg(LOG_DEFAULT, LVL_DEBUG, "invalid IP version");
     100                return EINVAL;
     101        }
     102       
    68103        if (rc != EOK) {
    69104                log_msg(LOG_DEFAULT, LVL_DEBUG, "failed decoding PDU");
    70105                return rc;
    71106        }
    72 
     107       
    73108        log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet()");
    74109        rc = inet_recv_packet(&packet);
    75110        log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet -> %d", rc);
    76111        free(packet.data);
    77 
     112       
    78113        return rc;
    79114}
    80115
    81 static 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);
     116static int inet_iplink_change_addr(iplink_t *iplink, addr48_t mac)
     117{
     118        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_change_addr(): "
     119            "new addr=%02x:%02x:%02x:%02x:%02x:%02x",
     120            mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
     121
     122        list_foreach(inet_links, link_list, inet_link_t, ilink) {
     123                if (ilink->sess == iplink->sess)
     124                        memcpy(&ilink->mac, mac, sizeof(addr48_t));
     125        }
     126
    127127        return EOK;
    128128}
     
    147147        if (ilink->svc_name != NULL)
    148148                free(ilink->svc_name);
     149       
    149150        free(ilink);
    150151}
    151152
    152 static int inet_link_open(service_id_t sid)
     153int inet_link_open(service_id_t sid)
    153154{
    154155        inet_link_t *ilink;
    155         iplink_addr_t iaddr;
     156        inet_addr_t iaddr;
    156157        int rc;
    157158
     
    189190                goto error;
    190191        }
     192       
     193        /*
     194         * Get the MAC address of the link. If the link has a MAC
     195         * address, we assume that it supports NDP.
     196         */
     197        rc = iplink_get_mac48(ilink->iplink, &ilink->mac);
     198        ilink->mac_valid = (rc == EOK);
    191199
    192200        log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened IP 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 192.168.0.4/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 = (192 << 24) + (168 << 16) + (0 << 8) + 4;
    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 
     201
     202        fibril_mutex_lock(&inet_links_lock);
     203
     204        if (inet_link_get_by_id_locked(sid) != NULL) {
     205                fibril_mutex_unlock(&inet_links_lock);
     206                log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %zu already open",
     207                    sid);
     208                rc = EEXIST;
     209                goto error;
     210        }
     211
     212        list_append(&ilink->link_list, &inet_links);
     213        fibril_mutex_unlock(&inet_links_lock);
     214
     215        inet_addrobj_t *addr = NULL;
     216       
     217        /* XXX FIXME Cannot rely on loopback being the first IP link service!! */
     218        if (first_link) {
     219                addr = inet_addrobj_new();
     220               
     221                inet_naddr(&addr->naddr, 127, 0, 0, 1, 24);
     222                first_link = false;
     223        }
     224       
     225        if (addr != NULL) {
     226                addr->ilink = ilink;
     227                addr->name = str_dup("v4a");
     228               
     229                rc = inet_addrobj_add(addr);
     230                if (rc == EOK) {
     231                        inet_naddr_addr(&addr->naddr, &iaddr);
     232                        rc = iplink_addr_add(ilink->iplink, &iaddr);
     233                        if (rc != EOK) {
     234                                log_msg(LOG_DEFAULT, LVL_ERROR,
     235                                    "Failed setting IPv4 address on internet link.");
     236                                inet_addrobj_remove(addr);
     237                                inet_addrobj_delete(addr);
     238                        }
     239                } else {
     240                        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv4 address.");
     241                        inet_addrobj_delete(addr);
     242                }
     243        }
     244       
     245        inet_addrobj_t *addr6 = NULL;
     246       
     247        if (first_link6) {
     248                addr6 = inet_addrobj_new();
     249               
     250                inet_naddr6(&addr6->naddr, 0, 0, 0, 0, 0, 0, 0, 1, 128);
     251                first_link6 = false;
     252        } else if (ilink->mac_valid) {
     253                addr6 = inet_addrobj_new();
     254               
     255                addr128_t link_local;
     256                inet_link_local_node_ip(ilink->mac, link_local);
     257               
     258                inet_naddr_set6(link_local, 64, &addr6->naddr);
     259        }
     260       
     261        if (addr6 != NULL) {
     262                addr6->ilink = ilink;
     263                addr6->name = str_dup("v6a");
     264               
     265                rc = inet_addrobj_add(addr6);
     266                if (rc == EOK) {
     267                        inet_naddr_addr(&addr6->naddr, &iaddr);
     268                        rc = iplink_addr_add(ilink->iplink, &iaddr);
     269                        if (rc != EOK) {
     270                                log_msg(LOG_DEFAULT, LVL_ERROR,
     271                                    "Failed setting IPv6 address on internet link.");
     272                                inet_addrobj_remove(addr6);
     273                                inet_addrobj_delete(addr6);
     274                        }
     275                } else {
     276                        log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv6 address.");
     277                        inet_addrobj_delete(addr6);
     278                }
     279        }
     280       
     281        log_msg(LOG_DEFAULT, LVL_DEBUG, "Configured link '%s'.", ilink->svc_name);
    227282        return EOK;
    228 
     283       
    229284error:
    230285        if (ilink->iplink != NULL)
    231286                iplink_close(ilink->iplink);
     287       
    232288        inet_link_delete(ilink);
    233289        return rc;
    234290}
    235291
    236 static void inet_link_cat_change_cb(void)
    237 {
    238         (void) inet_link_check_new();
    239 }
    240 
    241 int 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 */
    256 int 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 
     292/** Send IPv4 datagram over Internet link
     293 *
     294 * @param ilink Internet link
     295 * @param lsrc  Source IPv4 address
     296 * @param ldest Destination IPv4 address
     297 * @param dgram IPv4 datagram body
     298 * @param proto Protocol
     299 * @param ttl   Time-to-live
     300 * @param df    Do-not-Fragment flag
     301 *
     302 * @return EOK on success
     303 * @return ENOMEM when not enough memory to create the datagram
     304 * @return ENOTSUP if networking mode is not supported
     305 *
     306 */
     307int inet_link_send_dgram(inet_link_t *ilink, addr32_t lsrc, addr32_t ldest,
     308    inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
     309{
     310        addr32_t src_v4;
     311        ip_ver_t src_ver = inet_addr_get(&dgram->src, &src_v4, NULL);
     312        if (src_ver != ip_v4)
     313                return EINVAL;
     314       
     315        addr32_t dest_v4;
     316        ip_ver_t dest_ver = inet_addr_get(&dgram->dest, &dest_v4, NULL);
     317        if (dest_ver != ip_v4)
     318                return EINVAL;
     319       
    264320        /*
    265321         * Fill packet structure. Fragmentation is performed by
    266322         * inet_pdu_encode().
    267323         */
     324       
     325        iplink_sdu_t sdu;
     326       
     327        sdu.src = lsrc;
     328        sdu.dest = ldest;
     329       
     330        inet_packet_t packet;
     331       
    268332        packet.src = dgram->src;
    269333        packet.dest = dgram->dest;
     
    271335        packet.proto = proto;
    272336        packet.ttl = ttl;
     337       
     338        /* Allocate identifier */
     339        fibril_mutex_lock(&ip_ident_lock);
     340        packet.ident = ++ip_ident;
     341        fibril_mutex_unlock(&ip_ident_lock);
     342       
    273343        packet.df = df;
    274344        packet.data = dgram->data;
    275345        packet.size = dgram->size;
    276 
    277         sdu.lsrc.ipv4 = lsrc->ipv4;
    278         sdu.ldest.ipv4 = ldest->ipv4;
    279 
    280         offs = 0;
     346       
     347        int rc;
     348        size_t offs = 0;
     349       
    281350        do {
    282351                /* Encode one fragment */
    283                 rc = inet_pdu_encode(&packet, offs, ilink->def_mtu, &sdu.data,
    284                     &sdu.size, &roffs);
     352               
     353                size_t roffs;
     354                rc = inet_pdu_encode(&packet, src_v4, dest_v4, offs, ilink->def_mtu,
     355                    &sdu.data, &sdu.size, &roffs);
    285356                if (rc != EOK)
    286357                        return rc;
    287 
     358               
    288359                /* Send the PDU */
    289360                rc = iplink_send(ilink->iplink, &sdu);
     361               
    290362                free(sdu.data);
    291 
    292363                offs = roffs;
    293364        } while (offs < packet.size);
    294 
     365       
    295366        return rc;
    296367}
    297368
     369/** Send IPv6 datagram over Internet link
     370 *
     371 * @param ilink Internet link
     372 * @param ldest Destination MAC address
     373 * @param dgram IPv6 datagram body
     374 * @param proto Next header
     375 * @param ttl   Hop limit
     376 * @param df    Do-not-Fragment flag (unused)
     377 *
     378 * @return EOK on success
     379 * @return ENOMEM when not enough memory to create the datagram
     380 *
     381 */
     382int inet_link_send_dgram6(inet_link_t *ilink, addr48_t ldest,
     383    inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
     384{
     385        addr128_t src_v6;
     386        ip_ver_t src_ver = inet_addr_get(&dgram->src, NULL, &src_v6);
     387        if (src_ver != ip_v6)
     388                return EINVAL;
     389       
     390        addr128_t dest_v6;
     391        ip_ver_t dest_ver = inet_addr_get(&dgram->dest, NULL, &dest_v6);
     392        if (dest_ver != ip_v6)
     393                return EINVAL;
     394       
     395        iplink_sdu6_t sdu6;
     396        addr48(ldest, sdu6.dest);
     397       
     398        /*
     399         * Fill packet structure. Fragmentation is performed by
     400         * inet_pdu_encode6().
     401         */
     402       
     403        inet_packet_t packet;
     404       
     405        packet.src = dgram->src;
     406        packet.dest = dgram->dest;
     407        packet.tos = dgram->tos;
     408        packet.proto = proto;
     409        packet.ttl = ttl;
     410       
     411        /* Allocate identifier */
     412        fibril_mutex_lock(&ip_ident_lock);
     413        packet.ident = ++ip_ident;
     414        fibril_mutex_unlock(&ip_ident_lock);
     415       
     416        packet.df = df;
     417        packet.data = dgram->data;
     418        packet.size = dgram->size;
     419       
     420        int rc;
     421        size_t offs = 0;
     422       
     423        do {
     424                /* Encode one fragment */
     425               
     426                size_t roffs;
     427                rc = inet_pdu_encode6(&packet, src_v6, dest_v6, offs, ilink->def_mtu,
     428                    &sdu6.data, &sdu6.size, &roffs);
     429                if (rc != EOK)
     430                        return rc;
     431               
     432                /* Send the PDU */
     433                rc = iplink_send6(ilink->iplink, &sdu6);
     434               
     435                free(sdu6.data);
     436                offs = roffs;
     437        } while (offs < packet.size);
     438       
     439        return rc;
     440}
     441
     442static inet_link_t *inet_link_get_by_id_locked(sysarg_t link_id)
     443{
     444        assert(fibril_mutex_is_locked(&inet_links_lock));
     445
     446        list_foreach(inet_links, link_list, inet_link_t, ilink) {
     447                if (ilink->svc_id == link_id)
     448                        return ilink;
     449        }
     450
     451        return NULL;
     452}
     453
    298454inet_link_t *inet_link_get_by_id(sysarg_t link_id)
    299455{
    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);
    308                         return ilink;
    309                 }
    310         }
    311 
    312         fibril_mutex_unlock(&inet_discovery_lock);
    313         return NULL;
     456        inet_link_t *ilink;
     457
     458        fibril_mutex_lock(&inet_links_lock);
     459        ilink = inet_link_get_by_id_locked(link_id);
     460        fibril_mutex_unlock(&inet_links_lock);
     461
     462        return ilink;
     463}
     464
     465/** Get IDs of all links. */
     466int inet_link_get_id_list(sysarg_t **rid_list, size_t *rcount)
     467{
     468        sysarg_t *id_list;
     469        size_t count, i;
     470
     471        fibril_mutex_lock(&inet_links_lock);
     472        count = list_count(&inet_links);
     473
     474        id_list = calloc(count, sizeof(sysarg_t));
     475        if (id_list == NULL) {
     476                fibril_mutex_unlock(&inet_links_lock);
     477                return ENOMEM;
     478        }
     479
     480        i = 0;
     481        list_foreach(inet_links, link_list, inet_link_t, ilink) {
     482                id_list[i++] = ilink->svc_id;
     483        }
     484
     485        fibril_mutex_unlock(&inet_links_lock);
     486
     487        *rid_list = id_list;
     488        *rcount = count;
     489
     490        return EOK;
    314491}
    315492
Note: See TracChangeset for help on using the changeset viewer.