Ignore:
File:
1 edited

Legend:

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

    rc6bf6be r947e2ef  
    3535 */
    3636
    37 #include <adt/list.h>
    3837#include <bitops.h>
    39 #include <fibril_synch.h>
    4038#include <inet/addr.h>
    4139#include <inet/dnsr.h>
    4240#include <inet/inetcfg.h>
    43 #include <io/log.h>
    4441#include <loc.h>
    4542#include <net/in.h>
     
    4946#include <stdlib.h>
    5047
    51 #include "dhcp.h"
    5248#include "dhcp_std.h"
    53 #include "transport.h"
    54 
    55 enum {
    56         /** In microseconds */
    57         dhcp_discover_timeout_val = 5 * 1000 * 1000,
    58         /** In microseconds */
    59         dhcp_request_timeout_val = 1 * 1000 * 1000,
    60         dhcp_discover_retries = 5,
    61         dhcp_request_retries = 3
    62 };
     49
     50#define NAME "dhcp"
    6351
    6452#define MAX_MSG_SIZE 1024
     53
     54static int transport_fd = -1;
     55static inet_link_info_t link_info;
    6556static uint8_t msgbuf[MAX_MSG_SIZE];
    66 
    67 /** List of registered links (of dhcp_link_t) */
    68 static list_t dhcp_links;
    69 
    70 static void dhcpsrv_discover_timeout(void *);
    71 static void dhcpsrv_request_timeout(void *);
    72 
    73 typedef enum {
    74         ds_bound,
    75         ds_fail,
    76         ds_init,
    77         ds_init_reboot,
    78         ds_rebinding,
    79         ds_renewing,
    80         ds_requesting,
    81         ds_selecting
    82 } dhcp_state_t;
    8357
    8458typedef struct {
     
    9569} dhcp_offer_t;
    9670
    97 typedef struct {
    98         /** Link to dhcp_links list */
    99         link_t links;
    100         /** Link service ID */
    101         service_id_t link_id;
    102         /** Link info */
    103         inet_link_info_t link_info;
    104         /** Transport */
    105         dhcp_transport_t dt;
    106         /** Transport timeout */
    107         fibril_timer_t *timeout;
    108         /** Number of retries */
    109         int retries_left;
    110         /** Link state */
    111         dhcp_state_t state;
    112         /** Last received offer */
    113         dhcp_offer_t offer;
    114 } dhcp_link_t;
    115 
    116 static void dhcpsrv_recv(void *, void *, size_t);
    117 
    11871/** Decode subnet mask into subnet prefix length. */
    11972static int subnet_mask_decode(uint32_t mask, int *bits)
     
    148101}
    149102
    150 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)
    151123{
    152124        dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf;
     
    160132        hdr->flags = flag_broadcast;
    161133
    162         addr48(dlink->link_info.mac_addr, hdr->chaddr);
     134        addr48(link_info.mac_addr, hdr->chaddr);
    163135        hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic);
    164136
     
    168140        opt[3] = opt_end;
    169141
    170         return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + 4);
    171 }
    172 
    173 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)
    174168{
    175169        dhcp_hdr_t *hdr = (dhcp_hdr_t *)msgbuf;
     
    184178        hdr->flags = flag_broadcast;
    185179        hdr->ciaddr = host2uint32_t_be(offer->oaddr.addr);
    186         addr48(dlink->link_info.mac_addr, hdr->chaddr);
     180        addr48(link_info.mac_addr, hdr->chaddr);
    187181        hdr->opt_magic = host2uint32_t_be(dhcp_opt_magic);
    188182
     
    209203        opt[i++] = opt_end;
    210204
    211         return dhcp_send(&dlink->dt, msgbuf, sizeof(dhcp_hdr_t) + i);
    212 }
    213 
    214 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)
    215209{
    216210        dhcp_hdr_t *hdr = (dhcp_hdr_t *)msg;
     
    228222        size_t i;
    229223
    230         log_msg(LOG_DEFAULT, LVL_DEBUG, "Receive reply");
     224        printf("Receive reply\n");
    231225        memset(offer, 0, sizeof(*offer));
    232226
     
    237231                return rc;
    238232
    239         log_msg(LOG_DEFAULT, LVL_DEBUG, "Your IP address: %s", saddr);
     233        printf("Your IP address: %s\n", saddr);
    240234        free(saddr);
    241235
     
    246240                return rc;
    247241
    248         log_msg(LOG_DEFAULT, LVL_DEBUG, "Next server IP address: %s", saddr);
     242        printf("Next server IP address: %s\n", saddr);
    249243        free(saddr);
    250244
     
    255249                return rc;
    256250
    257         log_msg(LOG_DEFAULT, LVL_DEBUG, "Relay agent IP address: %s", saddr);
     251        printf("Relay agent IP address: %s\n", saddr);
    258252        free(saddr);
    259253
     
    326320
    327321        if (!have_server_id) {
    328                 log_msg(LOG_DEFAULT, LVL_ERROR, "Missing server ID option.");
     322                printf("Missing server ID option.\n");
    329323                return rc;
    330324        }
    331325
    332326        if (!have_subnet_mask) {
    333                 log_msg(LOG_DEFAULT, LVL_ERROR, "Missing subnet mask option.");
     327                printf("Missing subnet mask option.\n");
    334328                return rc;
    335329        }
     
    339333                return rc;
    340334
    341         log_msg(LOG_DEFAULT, LVL_DEBUG, "Offered network address: %s", saddr);
     335        printf("Offered network address: %s\n", saddr);
    342336        free(saddr);
    343337
     
    347341                        return rc;
    348342
    349                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Router address: %s", saddr);
     343                printf("Router address: %s\n", saddr);
    350344                free(saddr);
    351345        }
     
    356350                        return rc;
    357351
    358                 log_msg(LOG_DEFAULT, LVL_DEBUG, "DNS server: %s", saddr);
     352                printf("DNS server: %s\n", saddr);
    359353                free(saddr);
    360354        }
     
    373367            &addr_id);
    374368        if (rc != EOK) {
    375                 log_msg(LOG_DEFAULT, LVL_ERROR,
    376                     "Error creating IP address %s (%d)", "dhcp4a", rc);
     369                printf("Error creating IP address %s (%d)\n", "dhcp4a", rc);
    377370                return rc;
    378371        }
     
    385378                rc = inetcfg_sroute_create("dhcpdef", &defr, &offer->router, &sroute_id);
    386379                if (rc != EOK) {
    387                         log_msg(LOG_DEFAULT, LVL_ERROR, "Error creating "
    388                             "default route %s (%d).", "dhcpdef", rc);
     380                        printf("Error creating default route %s (%d).\n", "dhcpdef",
     381                            rc);
    389382                        return rc;
    390383                }
     
    394387                rc = dnsr_set_srvaddr(&offer->dns_server);
    395388                if (rc != EOK) {
    396                         log_msg(LOG_DEFAULT, LVL_ERROR, "Error setting "
    397                             "nameserver address (%d))", rc);
     389                        printf("%s: Error setting nameserver address (%d))\n",
     390                            NAME, rc);
    398391                        return rc;
    399392                }
     
    403396}
    404397
    405 void dhcpsrv_links_init(void)
    406 {
    407         list_initialize(&dhcp_links);
    408 }
    409 
    410 static dhcp_link_t *dhcpsrv_link_find(service_id_t link_id)
    411 {
    412         list_foreach(dhcp_links, links, dhcp_link_t, dlink) {
    413                 if (dlink->link_id == link_id)
    414                         return dlink;
    415         }
    416 
    417         return NULL;
    418 }
    419 
    420 static void dhcp_link_set_failed(dhcp_link_t *dlink)
    421 {
    422         log_msg(LOG_DEFAULT, LVL_NOTE, "Giving up on link %s",
    423             dlink->link_info.name);
    424         dlink->state = ds_fail;
    425 }
    426 
    427 int dhcpsrv_link_add(service_id_t link_id)
    428 {
    429         dhcp_link_t *dlink;
    430         int rc;
    431 
    432         log_msg(LOG_DEFAULT, LVL_DEBUG, "dhcpsrv_link_add(%zu)", link_id);
    433 
    434         if (dhcpsrv_link_find(link_id) != NULL) {
    435                 log_msg(LOG_DEFAULT, LVL_NOTE, "Link %zu already added",
    436                     link_id);
    437                 return EEXIST;
    438         }
    439 
    440         dlink = calloc(1, sizeof(dhcp_link_t));
    441         if (dlink == NULL)
    442                 return ENOMEM;
    443 
    444         dlink->link_id = link_id;
    445         dlink->timeout = fibril_timer_create();
    446         if (dlink->timeout == NULL) {
    447                 rc = ENOMEM;
    448                 goto error;
    449         }
    450 
    451         /* Get link hardware address */
    452         rc = inetcfg_link_get(link_id, &dlink->link_info);
    453         if (rc != EOK) {
    454                 log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting properties "
    455                     "for link %zu.", link_id);
    456                 rc = EIO;
    457                 goto error;
    458         }
    459 
    460         rc = dhcp_transport_init(&dlink->dt, link_id, dhcpsrv_recv, dlink);
    461         if (rc != EOK) {
    462                 log_msg(LOG_DEFAULT, LVL_ERROR, "Error initializing DHCP "
    463                     "transport for link %s.", dlink->link_info.name);
    464                 rc = EIO;
    465                 goto error;
    466         }
    467 
    468         dlink->state = ds_selecting;
    469 
    470         log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER");
    471         rc = dhcp_send_discover(dlink);
    472         if (rc != EOK) {
    473                 log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER.");
    474                 dhcp_link_set_failed(dlink);
    475                 rc = EIO;
    476                 goto error;
    477         }
    478 
    479         dlink->retries_left = dhcp_discover_retries;
    480         fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val,
    481             dhcpsrv_discover_timeout, dlink);
    482 
    483         list_append(&dlink->links, &dhcp_links);
    484 
    485         return EOK;
    486 error:
    487         if (dlink != NULL && dlink->timeout != NULL)
    488                 fibril_timer_destroy(dlink->timeout);
    489         free(dlink);
    490         return rc;
    491 }
    492 
    493 int dhcpsrv_link_remove(service_id_t link_id)
    494 {
    495         return ENOTSUP;
    496 }
    497 
    498 static void dhcpsrv_recv_offer(dhcp_link_t *dlink, dhcp_offer_t *offer)
    499 {
    500         int rc;
    501 
    502         if (dlink->state != ds_selecting) {
    503                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received offer in state "
    504                     " %d, ignoring.", (int)dlink->state);
    505                 return;
    506         }
    507 
    508         fibril_timer_clear(dlink->timeout);
    509         dlink->offer = *offer;
    510         dlink->state = ds_requesting;
    511 
    512         log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST");
    513         rc = dhcp_send_request(dlink, offer);
    514         if (rc != EOK) {
    515                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request.");
    516                 return;
    517         }
    518 
    519         dlink->retries_left = dhcp_request_retries;
    520         fibril_timer_set(dlink->timeout, dhcp_request_timeout_val,
    521             dhcpsrv_request_timeout, dlink);
    522 }
    523 
    524 static void dhcpsrv_recv_ack(dhcp_link_t *dlink, dhcp_offer_t *offer)
    525 {
    526         int rc;
    527 
    528         if (dlink->state != ds_requesting) {
    529                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received ack in state "
    530                     " %d, ignoring.", (int)dlink->state);
    531                 return;
    532         }
    533 
    534         fibril_timer_clear(dlink->timeout);
    535         dlink->offer = *offer;
    536         dlink->state = ds_bound;
    537 
    538         rc = dhcp_cfg_create(dlink->link_id, offer);
    539         if (rc != EOK) {
    540                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error creating configuration.");
    541                 return;
    542         }
    543 
    544         log_msg(LOG_DEFAULT, LVL_NOTE, "%s: Successfully configured.",
    545             dlink->link_info.name);
    546 }
    547 
    548 static void dhcpsrv_recv(void *arg, void *msg, size_t size)
    549 {
    550         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;
    551405        dhcp_offer_t offer;
    552406        int rc;
    553407
    554         log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: dhcpsrv_recv() %zu bytes",
    555             dlink->link_info.name, size);
    556 
    557         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();
    558414        if (rc != EOK) {
    559                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error parsing reply");
    560                 return;
    561         }
    562 
    563         switch (offer.msg_type) {
    564         case msg_dhcpoffer:
    565                 dhcpsrv_recv_offer(dlink, &offer);
    566                 break;
    567         case msg_dhcpack:
    568                 dhcpsrv_recv_ack(dlink, &offer);
    569                 break;
    570         default:
    571                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received unexpected "
    572                     "message type. %d", (int)offer.msg_type);
    573                 break;
    574         }
    575 }
    576 
    577 static void dhcpsrv_discover_timeout(void *arg)
    578 {
    579         dhcp_link_t *dlink = (dhcp_link_t *)arg;
    580         int rc;
    581 
    582         assert(dlink->state == ds_selecting);
    583         log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dcpsrv_discover_timeout",
    584             dlink->link_info.name);
    585 
    586         if (dlink->retries_left == 0) {
    587                 log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted");
    588                 dhcp_link_set_failed(dlink);
    589                 return;
    590         }
    591         --dlink->retries_left;
    592 
    593         log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPDISCOVER");
    594         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);
    595420        if (rc != EOK) {
    596                 log_msg(LOG_DEFAULT, LVL_ERROR, "Error sending DHCPDISCOVER");
    597                 dhcp_link_set_failed(dlink);
    598                 return;
    599         }
    600 
    601         fibril_timer_set(dlink->timeout, dhcp_discover_timeout_val,
    602             dhcpsrv_discover_timeout, dlink);
    603 }
    604 
    605 static void dhcpsrv_request_timeout(void *arg)
    606 {
    607         dhcp_link_t *dlink = (dhcp_link_t *)arg;
    608         int rc;
    609 
    610         assert(dlink->state == ds_requesting);
    611         log_msg(LOG_DEFAULT, LVL_NOTE, "%s: dcpsrv_request_timeout",
    612             dlink->link_info.name);
    613 
    614         if (dlink->retries_left == 0) {
    615                 log_msg(LOG_DEFAULT, LVL_NOTE, "Retries exhausted");
    616                 dhcp_link_set_failed(dlink);
    617                 return;
    618         }
    619         --dlink->retries_left;
    620 
    621         log_msg(LOG_DEFAULT, LVL_DEBUG, "Send DHCPREQUEST");
    622         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);
    623427        if (rc != EOK) {
    624                 log_msg(LOG_DEFAULT, LVL_DEBUG, "Error sending request.");
    625                 dhcp_link_set_failed(dlink);
    626                 return;
    627         }
    628 
    629         fibril_timer_set(dlink->timeout, dhcp_request_timeout_val,
    630             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;
    631487}
    632488
Note: See TracChangeset for help on using the changeset viewer.