Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/dhcp/dhcp.c

    r5a324d99 r947e2ef  
    3535 */
    3636
    37 #include <adt/list.h>
    3837#include <bitops.h>
    39 #include <errno.h>
    40 #include <fibril_synch.h>
    4138#include <inet/addr.h>
    4239#include <inet/dnsr.h>
    4340#include <inet/inetcfg.h>
    44 #include <io/log.h>
    4541#include <loc.h>
     42#include <net/in.h>
     43#include <net/inet.h>
     44#include <net/socket.h>
    4645#include <stdio.h>
    4746#include <stdlib.h>
    4847
    49 #include "dhcp.h"
    5048#include "dhcp_std.h"
    51 #include "transport.h"
    52 
    53 enum {
    54         /** In microseconds */
    55         dhcp_discover_timeout_val = 5 * 1000 * 1000,
    56         /** In microseconds */
    57         dhcp_request_timeout_val = 1 * 1000 * 1000,
    58         dhcp_discover_retries = 5,
    59         dhcp_request_retries = 3
    60 };
     49
     50#define NAME "dhcp"
    6151
    6252#define MAX_MSG_SIZE 1024
     53
     54static int transport_fd = -1;
     55static inet_link_info_t link_info;
    6356static uint8_t msgbuf[MAX_MSG_SIZE];
    64 
    65 /** List of registered links (of dhcp_link_t) */
    66 static list_t dhcp_links;
    67 
    68 static void dhcpsrv_discover_timeout(void *);
    69 static void dhcpsrv_request_timeout(void *);
    70 
    71 typedef enum {
    72         ds_bound,
    73         ds_fail,
    74         ds_init,
    75         ds_init_reboot,
    76         ds_rebinding,
    77         ds_renewing,
    78         ds_requesting,
    79         ds_selecting
    80 } dhcp_state_t;
    8157
    8258typedef struct {
     
    9369} dhcp_offer_t;
    9470
    95 typedef struct {
    96         /** Link to dhcp_links list */
    97         link_t links;
    98         /** Link service ID */
    99         service_id_t link_id;
    100         /** Link info */
    101         inet_link_info_t link_info;
    102         /** Transport */
    103         dhcp_transport_t dt;
    104         /** Transport timeout */
    105         fibril_timer_t *timeout;
    106         /** Number of retries */
    107         int retries_left;
    108         /** Link state */
    109         dhcp_state_t state;
    110         /** Last received offer */
    111         dhcp_offer_t offer;
    112 } dhcp_link_t;
    113 
    114 static void dhcpsrv_recv(void *, void *, size_t);
    115 
    11671/** Decode subnet mask into subnet prefix length. */
    11772static int subnet_mask_decode(uint32_t mask, int *bits)
     
    146101}
    147102
    148 static int dhcp_send_discover(dhcp_link_t *dlink)
     103static int dhcp_send(void *msg, size_t size)
     104{
     105        struct sockaddr_in addr;
     106        int rc;
     107
     108        addr.sin_family = AF_INET;
     109        addr.sin_port = htons(dhcp_server_port);
     110        addr.sin_addr.s_addr = htonl(addr32_broadcast_all_hosts);
     111
     112        rc = sendto(transport_fd, msg, size, 0,
     113            (struct sockaddr *)&addr, sizeof(addr));
     114        if (rc != EOK) {
     115                printf("Sending failed\n");
     116                return rc;
     117        }
     118
     119        return EOK;
     120}
     121
     122static int dhcp_send_discover(void)
    149123{
    150124        dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf;
     
    158132        hdr->flags = flag_broadcast;
    159133
    160         addr48(dlink->link_info.mac_addr, hdr->chaddr);
     134        addr48(link_info.mac_addr, hdr->chaddr);
    161135        hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic);
    162136
     
    166140        opt[3] = opt_end;
    167141
    168         return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + 4);
    169 }
    170 
    171 static int dhcp_send_request(dhcp_link_t *dlink, dhcp_offer_t *offer)
     142        return dhcp_send(msgbuf, sizeof(dhcp_hdr_t) + 4);
     143}
     144
     145static int dhcp_recv_msg(void **rmsg, size_t *rsize)
     146{
     147        struct sockaddr_in src_addr;
     148        socklen_t src_addr_size;
     149        size_t recv_size;
     150        int rc;
     151
     152        src_addr_size = sizeof(src_addr);
     153        rc = recvfrom(transport_fd, msgbuf, MAX_MSG_SIZE, 0,
     154            (struct sockaddr *)&src_addr, &src_addr_size);
     155        if (rc < 0) {
     156                printf("recvfrom failed (%d)\n", rc);
     157                return rc;
     158        }
     159
     160        recv_size = (size_t)rc;
     161        *rmsg = msgbuf;
     162        *rsize = recv_size;
     163
     164        return EOK;
     165}
     166
     167static int dhcp_send_request(dhcp_offer_t *offer)
    172168{
    173169        dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf;
     
    182178        hdr->flags = flag_broadcast;
    183179        hdr->ciaddr = host2uint32_t_be(offer->oaddr.addr);
    184         addr48(dlink->link_info.mac_addr, hdr->chaddr);
     180        addr48(link_info.mac_addr, hdr->chaddr);
    185181        hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic);
    186182
     
    207203        opt[i++] = opt_end;
    208204
    209         return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + i);
    210 }
    211 
    212 static int dhcp_parse_reply(void *msg, size_t size, dhcp_offer_t *offer)
     205        return dhcp_send(msgbuf, sizeof(dhcp_hdr_t) + i);
     206}
     207
     208static int dhcp_recv_reply(void *msg, size_t size, dhcp_offer_t *offer)
    213209{
    214210        dhcp_hdr_t *hdr = (dhcp_hdr_t *)msg;
     
    226222        size_t i;
    227223
    228         log_msg(LOG_DEFAULT, LVL_DEBUG, "Receive reply");
     224        printf("Receive reply\n");
    229225        memset(offer, 0, sizeof(*offer));
    230226
    231         inet_addr_set(uint32_t_be2host(hdr->yiaddr), &yiaddr);
     227        yiaddr.family = AF_INET;
     228        yiaddr.addr = uint32_t_be2host(hdr->yiaddr);
    232229        rc = inet_addr_format(&yiaddr, &saddr);
    233230        if (rc != EOK)
    234231                return rc;
    235232
    236         log_msg(LOG_DEFAULT, LVL_DEBUG, "Your IP address: %s", saddr);
     233        printf("Your IP address: %s\n", saddr);
    237234        free(saddr);
    238235
    239         inet_addr_set(uint32_t_be2host(hdr->siaddr), &siaddr);
     236        siaddr.family = AF_INET;
     237        siaddr.addr = uint32_t_be2host(hdr->siaddr);
    240238        rc = inet_addr_format(&siaddr, &saddr);
    241239        if (rc != EOK)
    242240                return rc;
    243241
    244         log_msg(LOG_DEFAULT, LVL_DEBUG, "Next server IP address: %s", saddr);
     242        printf("Next server IP address: %s\n", saddr);
    245243        free(saddr);
    246244
    247         inet_addr_set(uint32_t_be2host(hdr->giaddr), &giaddr);
     245        giaddr.family = AF_INET;
     246        giaddr.addr = uint32_t_be2host(hdr->giaddr);
    248247        rc = inet_addr_format(&giaddr, &saddr);
    249248        if (rc != EOK)
    250249                return rc;
    251250
    252         log_msg(LOG_DEFAULT, LVL_DEBUG, "Relay agent IP address: %s", saddr);
     251        printf("Relay agent IP address: %s\n", saddr);
    253252        free(saddr);
    254253
    255         inet_naddr_set(yiaddr.addr, 0, &offer->oaddr);
     254        offer->oaddr.family = AF_INET;
     255        offer->oaddr.addr = yiaddr.addr;
    256256
    257257        msgb = (uint8_t *)msg;
     
    293293                        if (opt_len != 4)
    294294                                return EINVAL;
    295                         inet_addr_set(dhcp_uint32_decode(&msgb[i]),
    296                             &offer->srv_addr);
     295                        offer->srv_addr.family = AF_INET;
     296                        offer->srv_addr.addr = dhcp_uint32_decode(&msgb[i]);
    297297                        have_server_id = true;
    298298                        break;
     
    300300                        if (opt_len != 4)
    301301                                return EINVAL;
    302                         inet_addr_set(dhcp_uint32_decode(&msgb[i]),
    303                             &offer->router);
     302                        offer->router.family = AF_INET;
     303                        offer->router.addr = dhcp_uint32_decode(&msgb[i]);
    304304                        break;
    305305                case opt_dns_server:
    306306                        if (opt_len != 4)
    307307                                return EINVAL;
    308                         inet_addr_set(dhcp_uint32_decode(&msgb[i]),
    309                             &offer->dns_server);
     308                        offer->dns_server.family = AF_INET;
     309                        offer->dns_server.addr = dhcp_uint32_decode(&msgb[i]);
    310310                        break;
    311311                case opt_end:
     
    320320
    321321        if (!have_server_id) {
    322                 log_msg(LOG_DEFAULT, LVL_ERROR, "Missing server ID option.");
     322                printf("Missing server ID option.\n");
    323323                return rc;
    324324        }
    325325
    326326        if (!have_subnet_mask) {
    327                 log_msg(LOG_DEFAULT, LVL_ERROR, "Missing subnet mask option.");
     327                printf("Missing subnet mask option.\n");
    328328                return rc;
    329329        }
     
    333333                return rc;
    334334
    335         log_msg(LOG_DEFAULT, LVL_DEBUG, "Offered network address: %s", saddr);
     335        printf("Offered network address: %s\n", saddr);
    336336        free(saddr);
    337337
     
    341341                        return rc;
    342342
    343                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Router address: %s", saddr);
     343                printf("Router address: %s\n", saddr);
    344344                free(saddr);
    345345        }
     
    350350                        return rc;
    351351
    352                 log_msg(LOG_DEFAULT, LVL_DEBUG, "DNS server: %s", saddr);
     352                printf("DNS server: %s\n", saddr);
    353353                free(saddr);
    354354        }
     
    367367            &addr_id);
    368368        if (rc != EOK) {
    369                 log_msg(LOG_DEFAULT, LVL_ERROR,
    370                     "Error creating IP address %s (%d)", "dhcp4a", rc);
     369                printf("Error creating IP address %s (%d)\n", "dhcp4a", rc);
    371370                return rc;
    372371        }
    373372
    374373        if (offer->router.addr != 0) {
    375                 inet_naddr_set(0, 0, &defr);
     374                defr.family = AF_INET;
     375                defr.addr = 0;
     376                defr.prefix = 0;
    376377
    377378                rc = inetcfg_sroute_create("dhcpdef", &defr, &offer->router, &sroute_id);
    378379                if (rc != EOK) {
    379                         log_msg(LOG_DEFAULT, LVL_ERROR, "Error creating "
    380                             "default route %s (%d).", "dhcpdef", rc);
     380                        printf("Error creating default route %s (%d).\n", "dhcpdef",
     381                            rc);
    381382                        return rc;
    382383                }
     
    386387                rc = dnsr_set_srvaddr(&offer->dns_server);
    387388                if (rc != EOK) {
    388                         log_msg(LOG_DEFAULT, LVL_ERROR, "Error setting "
    389                             "nameserver address (%d))", rc);
     389                        printf("%s: Error setting nameserver address (%d))\n",
     390                            NAME, rc);
    390391                        return rc;
    391392                }
     
    395396}
    396397
    397 void dhcpsrv_links_init(void)
    398 {
    399         list_initialize(&dhcp_links);
    400 }
    401 
    402 static dhcp_link_t *dhcpsrv_link_find(service_id_t link_id)
    403 {
    404         list_foreach(dhcp_links, links, dhcp_link_t, dlink) {
    405                 if (dlink->link_id == link_id)
    406                         return dlink;
    407         }
    408 
    409         return NULL;
    410 }
    411 
    412 static void dhcp_link_set_failed(dhcp_link_t *dlink)
    413 {
    414         log_msg(LOG_DEFAULT, LVL_NOTE, "Giving up on link %s",
    415             dlink->link_info.name);
    416         dlink->state = ds_fail;
    417 }
    418 
    419 int dhcpsrv_link_add(service_id_t link_id)
    420 {
    421         dhcp_link_t *dlink;
    422         int rc;
    423 
    424         log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcpsrv_link_add(%zu)", link_id);
    425 
    426         if (dhcpsrv_link_find(link_id) != NULL) {
    427                 log_msg(LOG_DEFAULT, LVL_NOTE, "Link %zu already added",
    428                     link_id);
    429                 return EEXIST;
    430         }
    431 
    432         dlink = calloc(1, sizeof(dhcp_link_t));
    433         if (dlink == NULL)
    434                 return ENOMEM;
    435 
    436         dlink->link_id = link_id;
    437         dlink->timeout = fibril_timer_create();
    438         if (dlink->timeout == NULL) {
    439                 rc = ENOMEM;
    440                 goto error;
    441         }
    442 
    443         /* Get link hardware address */
    444         rc = inetcfg_link_get(link_id, &dlink->link_info);
    445         if (rc != EOK) {
    446                 log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting properties "
    447                     "for link %zu.", link_id);
    448                 rc = EIO;
    449                 goto error;
    450         }
    451 
    452         rc = dhcp_transport_init(&dlink->dt, link_id, dhcpsrv_recv, dlink);
    453         if (rc != EOK) {
    454                 log_msg(LOG_DEFAULT, LVL_ERROR, "Error initializing DHCP "
    455                     "transport for link %s.", dlink->link_info.name);
    456                 rc = EIO;
    457                 goto error;
    458         }
    459 
    460         dlink->state = ds_selecting;
    461 
    462         log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER");
    463         rc = dhcp_send_discover(dlink);
    464         if (rc != EOK) {
    465                 log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER.");
    466                 dhcp_link_set_failed(dlink);
    467                 rc = EIO;
    468                 goto error;
    469         }
    470 
    471         dlink->retries_left = dhcp_discover_retries;
    472         fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val,
    473             dhcpsrv_discover_timeout, dlink);
    474 
    475         list_append(&dlink->links, &dhcp_links);
    476 
    477         return EOK;
    478 error:
    479         if (dlink != NULL && dlink->timeout != NULL)
    480                 fibril_timer_destroy(dlink->timeout);
    481         free(dlink);
    482         return rc;
    483 }
    484 
    485 int dhcpsrv_link_remove(service_id_t link_id)
    486 {
    487         return ENOTSUP;
    488 }
    489 
    490 static void dhcpsrv_recv_offer(dhcp_link_t *dlink, dhcp_offer_t *offer)
    491 {
    492         int rc;
    493 
    494         if (dlink->state != ds_selecting) {
    495                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received offer in state "
    496                     " %d, ignoring.", (int)dlink->state);
    497                 return;
    498         }
    499 
    500         fibril_timer_clear(dlink->timeout);
    501         dlink->offer = *offer;
    502         dlink->state = ds_requesting;
    503 
    504         log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST");
    505         rc = dhcp_send_request(dlink, offer);
    506         if (rc != EOK) {
    507                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request.");
    508                 return;
    509         }
    510 
    511         dlink->retries_left = dhcp_request_retries;
    512         fibril_timer_set(dlink->timeout, dhcp_request_timeout_val,
    513             dhcpsrv_request_timeout, dlink);
    514 }
    515 
    516 static void dhcpsrv_recv_ack(dhcp_link_t *dlink, dhcp_offer_t *offer)
    517 {
    518         int rc;
    519 
    520         if (dlink->state != ds_requesting) {
    521                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received ack in state "
    522                     " %d, ignoring.", (int)dlink->state);
    523                 return;
    524         }
    525 
    526         fibril_timer_clear(dlink->timeout);
    527         dlink->offer = *offer;
    528         dlink->state = ds_bound;
    529 
    530         rc = dhcp_cfg_create(dlink->link_id, offer);
    531         if (rc != EOK) {
    532                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error creating configuration.");
    533                 return;
    534         }
    535 
    536         log_msg(LOG_DEFAULT, LVL_NOTE, "%s: Successfully configured.",
    537             dlink->link_info.name);
    538 }
    539 
    540 static void dhcpsrv_recv(void *arg, void *msg, size_t size)
    541 {
    542         dhcp_link_t *dlink = (dhcp_link_t *)arg;
     398int main(int argc, char *argv[])
     399{
     400        int fd;
     401        struct sockaddr_in laddr;
     402        void *msg;
     403        service_id_t iplink;
     404        size_t msg_size;
    543405        dhcp_offer_t offer;
    544406        int rc;
    545407
    546         log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: dhcpsrv_recv() %zu bytes",
    547             dlink->link_info.name, size);
    548 
    549         rc = dhcp_parse_reply(msg, size, &offer);
     408        if (argc < 2) {
     409                printf("syntax: %s <ip-link>\n", NAME);
     410                return 1;
     411        }
     412
     413        rc = inetcfg_init();
    550414        if (rc != EOK) {
    551                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error parsing reply");
    552                 return;
    553         }
    554 
    555         switch (offer.msg_type) {
    556         case msg_dhcpoffer:
    557                 dhcpsrv_recv_offer(dlink, &offer);
    558                 break;
    559         case msg_dhcpack:
    560                 dhcpsrv_recv_ack(dlink, &offer);
    561                 break;
    562         default:
    563                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received unexpected "
    564                     "message type. %d", (int)offer.msg_type);
    565                 break;
    566         }
    567 }
    568 
    569 static void dhcpsrv_discover_timeout(void *arg)
    570 {
    571         dhcp_link_t *dlink = (dhcp_link_t *)arg;
    572         int rc;
    573 
    574         assert(dlink->state == ds_selecting);
    575         log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dcpsrv_discover_timeout",
    576             dlink->link_info.name);
    577 
    578         if (dlink->retries_left == 0) {
    579                 log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted");
    580                 dhcp_link_set_failed(dlink);
    581                 return;
    582         }
    583         --dlink->retries_left;
    584 
    585         log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER");
    586         rc = dhcp_send_discover(dlink);
     415                printf("Error contacting inet configuration service.\n");
     416                return 1;
     417        }
     418
     419        rc = loc_service_get_id(argv[1], &iplink, 0);
    587420        if (rc != EOK) {
    588                 log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER");
    589                 dhcp_link_set_failed(dlink);
    590                 return;
    591         }
    592 
    593         fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val,
    594             dhcpsrv_discover_timeout, dlink);
    595 }
    596 
    597 static void dhcpsrv_request_timeout(void *arg)
    598 {
    599         dhcp_link_t *dlink = (dhcp_link_t *)arg;
    600         int rc;
    601 
    602         assert(dlink->state == ds_requesting);
    603         log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dcpsrv_request_timeout",
    604             dlink->link_info.name);
    605 
    606         if (dlink->retries_left == 0) {
    607                 log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted");
    608                 dhcp_link_set_failed(dlink);
    609                 return;
    610         }
    611         --dlink->retries_left;
    612 
    613         log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST");
    614         rc = dhcp_send_request(dlink, &dlink->offer);
     421                printf("Error resolving service '%s'.\n", argv[1]);
     422                return 1;
     423        }
     424
     425        /* Get link hardware address */
     426        rc = inetcfg_link_get(iplink, &link_info);
    615427        if (rc != EOK) {
    616                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request.");
    617                 dhcp_link_set_failed(dlink);
    618                 return;
    619         }
    620 
    621         fibril_timer_set(dlink->timeout, dhcp_request_timeout_val,
    622             dhcpsrv_request_timeout, dlink);
     428                printf("Error getting properties for link '%s'.\n", argv[1]);
     429                return 1;
     430        }
     431
     432        laddr.sin_family = AF_INET;
     433        laddr.sin_port = htons(dhcp_client_port);
     434        laddr.sin_addr.s_addr = INADDR_ANY;
     435
     436        fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
     437        if (fd < 0)
     438                return 1;
     439
     440        printf("Bind socket.\n");
     441        rc = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr));
     442        if (rc != EOK)
     443                return 1;
     444
     445        printf("Set socket options\n");
     446        rc = setsockopt(fd, SOL_SOCKET, SO_IPLINK, &iplink, sizeof(iplink));
     447        if (rc != EOK)
     448                return 1;
     449
     450        transport_fd = fd;
     451
     452        printf("Send DHCPDISCOVER\n");
     453        rc = dhcp_send_discover();
     454        if (rc != EOK)
     455                return 1;
     456
     457        rc = dhcp_recv_msg(&msg, &msg_size);
     458        if (rc != EOK)
     459                return 1;
     460
     461        printf("Received %zu bytes\n", msg_size);
     462
     463        rc = dhcp_recv_reply(msg, msg_size, &offer);
     464        if (rc != EOK)
     465                return 1;
     466
     467        rc = dhcp_send_request(&offer);
     468        if (rc != EOK)
     469                return 1;
     470
     471        rc = dhcp_recv_msg(&msg, &msg_size);
     472        if (rc != EOK)
     473                return 1;
     474
     475        printf("Received %zu bytes\n", msg_size);
     476
     477        rc = dhcp_recv_reply(msg, msg_size, &offer);
     478        if (rc != EOK)
     479                return 1;
     480
     481        rc = dhcp_cfg_create(iplink, &offer);
     482        if (rc != EOK)
     483                return 1;
     484
     485        closesocket(fd);
     486        return 0;
    623487}
    624488
Note: See TracChangeset for help on using the changeset viewer.