Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

arch_dhcp.c

/* $Id: arch_dhcp.c,v 1.19 2009-01-30 12:56:23 sand Exp $ 
 *
 * Copyright (C) 2008-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#define DHCP_DEBUG 0

#ifdef INCLUDE

#include "config.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#if HAVE_NETINET_IN_SYSTM_H
#include <netinet/in_systm.h>
#endif
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#endif /* INCLUDE */

#ifdef STATE

struct {
      uint32_t server_id;
      uint32_t first_ip;
      uint32_t range;
      uint32_t netmask;
      uint32_t broadcast;
      uint32_t default_router;
      uint32_t dns_server;
      uint32_t *database;
} NAME;

#endif /* STATE */

#ifdef BEHAVIOR

/* ugly hack to use udphdr on BSD and GNU systems */
#if defined(__USE_GNU) && !defined(__FAVOR_BSD)
# define uh_sport source
# define uh_dport dest
# define uh_ulen len
# define uh_sum check
#endif

/* Definitions needed for DHCP */

struct dhcp_pkt {
      struct ip iphdr;
      struct udphdr udphdr;
      uint8_t op, htype, hlen, hops;
      uint32_t xid;
      uint16_t secs, flags;
      uint32_t ciaddr;
      uint32_t yiaddr;
      uint32_t siaddr;
      uint32_t giaddr;
      uint32_t chaddr[4];
      char sname[64];
      char file[128];
      uint8_t options[0];
} __attribute__((__packed__));

struct dhcp_option {
      uint8_t tag;
      uint8_t len;
      uint8_t data[0];
} __attribute__((__packed__));

#define BOOTREQUEST (1)
#define BOOTREPLY (2)

#define DHCP_OPTION_PADDING         (0)
#define DHCP_OPTION_NETMASK         (1)
#define DHCP_OPTION_TIMEOFFSET            (2)
#define DHCP_OPTION_ROUTERS         (3)
#define DHCP_OPTION_DNS_SERVER            (6)
#define DHCP_OPTION_HOSTNAME        (12)
#define DHCP_OPTION_DOMAINNAME            (15)
#define DHCP_OPTION_BROADCAST       (28)
#define DHCP_OPTION_REQUESTED_IP    (50)
#define DHCP_OPTION_LEASE_TIME            (51)
#define DHCP_OPTION_MSG_TYPE        (53)
#define DHCP_OPTION_SERVER_ID       (54)
#define DHCP_OPTION_REQUEST_LIST    (55)
#define DHCP_OPTION_END             (255)

#define DHCPDISCOVER (1)
#define DHCPOFFER (2)
#define DHCPREQUEST (3)
#define DHCPDECLINE (4)
#define DHCPACK (5)
#define DHCPNAK (6)
#define DHCPRELEASE (7)
#define DHCPINFORM (8)

/* internal Definitions */

struct dhcp_option_list {
      struct dhcp_option_list *next, *prev;
      struct dhcp_option option;
};

struct dhcp_reply {
      struct dhcp_pkt hdr;
      struct dhcp_option_list *first_option, *last_option;
};

/* DHCP option parsing */

static const struct dhcp_option *
NAME_(option_skip_to_real)(int * len, const struct dhcp_option * opt)
{
      /* skip padding */
      while (*len > 1 && opt->tag==DHCP_OPTION_PADDING) {
            len--;
            opt = (const struct dhcp_option *) &opt->len;
      }

      /* check for real option */
      if (*len < 2) return NULL;
      if (opt->tag == DHCP_OPTION_END) return NULL; /* end tag */
      if (*len < 2 + opt->len) return NULL;

      return opt;
}

/* retrieve the first real option from a dhcp packet */
static const struct dhcp_option *
NAME_(option_first)(int *len, const struct dhcp_pkt * pkt)
{
      const struct dhcp_option * opt;

      /* check for DHCP option magic bytes */
      if (pkt->options[0]==99 && pkt->options[1]==130
      &&  pkt->options[2]==83 && pkt->options[3]==99) {
            opt = (const struct dhcp_option*) &pkt->options[4];
            *len -= 4;
      } else {
            return NULL;
      }

      return NAME_(option_skip_to_real)(len, opt);
}

/* get a pointer to the next dhcp option or NULL if there is no more */
/* opt must point to a valid non-padding-non-end option */
static const struct dhcp_option *
NAME_(option_next)(int *len, const struct dhcp_option * opt)
{
      /* advance to next option */
      *len -= 2 + opt->len;
      opt = (const struct dhcp_option *) &opt->data[opt->len];

      return NAME_(option_skip_to_real)(len, opt);
}

static const uint8_t *
NAME_(option_get)(int len, const struct dhcp_pkt * pkt, uint8_t tag)
{
      const struct dhcp_option *opt;

      opt = NAME_(option_first)(&len, pkt);

      while (opt) {
            if (opt->tag == tag) return opt->data;
            opt = NAME_(option_next)(&len, opt);
      }

      return NULL;
}



/* debugging helpers */


static const char *
NAME_(msg_type)(uint8_t type)
{
      switch (type) {
      case DHCPDISCOVER: return "DHCPDISCOVER";
      case DHCPOFFER: return "DHCPOFFER";
      case DHCPREQUEST: return "DHCPREQUEST";
      case DHCPDECLINE: return "DHCPDDECLINE";
      case DHCPACK: return "DHCPACK";
      case DHCPNAK: return "DHCPNAK";
      case DHCPRELEASE: return "DHCPRELEASE";
      case DHCPINFORM: return "DHCPINFORM";
      default: return "(unknown DHCP msg type)";
      }
}

#if DHCP_DEBUG
static void
NAME_(dump)(int len, const struct dhcp_pkt * pkt)
{
      const struct dhcp_option *opt;

      switch (pkt->op) {
      case BOOTREQUEST: fprintf(stderr, "op=BOOTREQUEST "); break;
      case BOOTREPLY:   fprintf(stderr, "op=BOOTREPLY "); break;
      default: fprintf(stderr, "invalid DHCP\n"); return;
      }

      fprintf(stderr, "htype=%d hlen=%d hops=%d\n",
                  pkt->htype, pkt->hlen, pkt->hops);
      fprintf(stderr, "xid=0x%x\n", pkt->xid);
      fprintf(stderr, "secs=%d flags=0x%x\n", pkt->secs, pkt->flags);
      fprintf(stderr, "ciaddr=0x%x\n", pkt->ciaddr);
      fprintf(stderr, "yiaddr=0x%x\n", pkt->yiaddr);
      fprintf(stderr, "siaddr=0x%x\n", pkt->siaddr);
      fprintf(stderr, "giaddr=0x%x\n", pkt->giaddr);
      fprintf(stderr, "sname=%s\n", pkt->sname);
      fprintf(stderr, "file=%s\n", pkt->file);
      len -= sizeof(struct dhcp_pkt);
      fprintf(stderr, "options-len=%d\n", len);

      opt = NAME_(option_first)(&len, pkt);

      while (opt) {
            switch (opt->tag) {
            case DHCP_OPTION_MSG_TYPE:
                  fprintf(stderr, "%s\n", NAME_(msg_type)(opt->data[0]));
                  break;
            case DHCP_OPTION_SERVER_ID:
                  fprintf(stderr, "server ID %d.%d.%d.%d\n",
                              opt->data[0],opt->data[1],
                              opt->data[2],opt->data[3]);
                  break;
            case DHCP_OPTION_REQUESTED_IP:
                  fprintf(stderr, "requesting IP %d.%d.%d.%d\n",
                              opt->data[0],opt->data[1],
                              opt->data[2],opt->data[3]);
                  break;
            case DHCP_OPTION_BROADCAST:
                  fprintf(stderr, "broadcast %d.%d.%d.%d\n",
                              opt->data[0],opt->data[1],
                              opt->data[2],opt->data[3]);
                  break;
            case DHCP_OPTION_NETMASK:
                  fprintf(stderr, "netmask %d.%d.%d.%d\n",
                              opt->data[0],opt->data[1],
                              opt->data[2],opt->data[3]);
                  break;
            case DHCP_OPTION_ROUTERS:
                  fprintf(stderr, "%d routers (%d.%d.%d.%d)\n",
                              len / 4,
                              opt->data[0],opt->data[1],
                              opt->data[2],opt->data[3]);
                  break;
            case DHCP_OPTION_DNS_SERVER:
                  fprintf(stderr, "DNS server %d.%d.%d.%d\n",
                              opt->data[0],opt->data[1],
                              opt->data[2],opt->data[3]);
                  break;
            case DHCP_OPTION_LEASE_TIME:
                  fprintf(stderr, "lease time %d secs\n",
                              ntohl( * (uint32_t*) &opt->data));
                  break;
            case DHCP_OPTION_REQUEST_LIST:
                  {int i;
                  fprintf(stderr, "requesting options:");
                  for (i=0; i<opt->len; i++) {
                        fprintf(stderr, " %d", opt->data[i]);
                  }
                  fprintf(stderr, "\n");
                  break;}
            default:
                  fprintf(stderr, "tag=%d len=%d ...\n",
                              opt->tag, opt->len);
            }
            opt = NAME_(option_next)(&len, opt);
      }
}
#endif


/* dhcp helper */

/* check whether ip address is free */
static int
NAME_(is_addr_free)(struct cpssp *cpssp, uint32_t ip)
{
      int i;
      uint32_t index;

      if ((ip & cpssp->NAME.netmask)
                  != (cpssp->NAME.first_ip & cpssp->NAME.netmask)) {

            /* not in our network */
            return 0;
      }

      if (ip < cpssp->NAME.first_ip) {

            /* below valid range */
            return 0;
      }

      index = ip - cpssp->NAME.first_ip;

      for (i=0; i < 4; i++) {
            if (cpssp->NAME.database[index * 4 + i] != 0xffffffff)
                  return 0;
      }

      return 1;
}

/* set address as bound to ip with mac address chaddr */
static void
NAME_(addr_set)(struct cpssp *cpssp, uint32_t ip, const uint32_t *chaddr)
{
      int i;
      uint32_t index;

      assert(cpssp->NAME.first_ip <= ip);
      index = ip - cpssp->NAME.first_ip;

      for (i=0; i < 4; i++) {
            cpssp->NAME.database[index * 4 + i] = chaddr[i];
      }
}

/* mark ip address as invalid;
 * it will never be used again!!! */
static void
NAME_(addr_invalid)(struct cpssp *cpssp, uint32_t ip)
{
      int i;
      uint32_t index;

      assert(cpssp->NAME.first_ip <= ip);
      index = ip - cpssp->NAME.first_ip;

      for (i=0; i < 4; i++) {
            cpssp->NAME.database[index * 4 + i] = 0;
      }
}

/* check whether given ip and mac address match due to database */
static int
NAME_(addr_check)(struct cpssp *cpssp, uint32_t ip, const uint32_t *chaddr)
{
      int ret = 0;
      int i;
      uint32_t index;

      if ((ip & cpssp->NAME.netmask)
                  != (cpssp->NAME.first_ip & cpssp->NAME.netmask)) {

            /* not in our network */
            return 0;
      }

      if (ip < cpssp->NAME.first_ip) {

            /* below valid range */
            return 0;
      }

      index = ip - cpssp->NAME.first_ip;
      ret = 1;
      for (i=0; i < 4; i++) {
            if (cpssp->NAME.database[index * 4 + i] != chaddr[i]) {
                  ret = 0;
                  break;
            }
      }

      return ret;
}

/* return next free IP number */
static in_addr_t
NAME_(ip_next)(struct cpssp *cpssp, const uint32_t *chaddr)
{
      uint32_t host;
      in_addr_t ip = 0;

      for (   host = cpssp->NAME.first_ip;
            host < cpssp->NAME.first_ip + cpssp->NAME.range;
            host++
          ) {
            if (NAME_(is_addr_free)(cpssp, host)) {
                  ip = host;
                  NAME_(addr_set)(cpssp, host, chaddr);
                  break;
            }
      }

      return ip;
}

/* return IP number if already registered */
static in_addr_t
NAME_(ip_lookup)(struct cpssp *cpssp, const uint32_t *chaddr)
{
      uint32_t host;
      in_addr_t ip = 0;

      for ( host = cpssp->NAME.first_ip;
            host < cpssp->NAME.first_ip + cpssp->NAME.range;
            host++
          ) {
            if (NAME_(addr_check)(cpssp, host, chaddr)) {
                  ip = host;
                  break;
            }
      }

      return ip;
}

static struct dhcp_reply *
NAME_(reply_create)(struct cpssp *cpssp, int len, const struct dhcp_pkt *pkt)
{
      struct dhcp_reply * reply;

      reply = malloc(sizeof(struct dhcp_reply));

      memcpy(&reply->hdr, pkt, sizeof(struct dhcp_pkt));
      reply->first_option = reply->last_option = NULL;

      /* Exchange source <-> destination. */
      reply->hdr.iphdr.ip_src.s_addr = htonl(cpssp->NAME.server_id);
      reply->hdr.iphdr.ip_dst.s_addr = htonl(0xffffffff);
      reply->hdr.udphdr.uh_sport = pkt->udphdr.uh_dport;
      reply->hdr.udphdr.uh_dport = pkt->udphdr.uh_sport;

      reply->hdr.op = BOOTREPLY;

      return reply;
}

static struct dhcp_option *
NAME_(reply_add_option)(struct dhcp_reply * reply, int tag, int len)
{
      struct dhcp_option_list * opt;

      opt = malloc(sizeof(struct dhcp_option_list) + len);
      opt->option.tag = tag;
      opt->option.len = len;

      opt->next = NULL;
      opt->prev = reply->last_option;
      if (reply->last_option)
            reply->last_option->next = opt;
      reply->last_option = opt;
      if (!reply->first_option)
            reply->first_option = opt;

      return &opt->option;
}

static void
NAME_(reply_add_option32)(struct dhcp_reply * reply, uint8_t tag, uint32_t data)
{
      struct dhcp_option * opt;

      opt = NAME_(reply_add_option)(reply, tag, 4);
      opt->data[0] = data & 0xff;
      opt->data[1] = (data>>8) & 0xff;
      opt->data[2] = (data>>16) & 0xff;
      opt->data[3] = (data>>24) & 0xff;
}

/* ones-complement-addition */
static uint16_t
NAME_(csum_add)(uint16_t csum, uint16_t addend)
{
      csum += addend;
      return csum + (csum < addend ? 1 : 0);
}

/* fill in correct length, checksum */
static void
NAME_(fix_packet)(struct dhcp_pkt * pkt, int len)
{
      int i;
      uint16_t check;

      /* IP */
      pkt->iphdr.ip_len = htons(len);
      memset(&pkt->iphdr.ip_sum, 0, sizeof(pkt->iphdr.ip_sum));
      /* FIXME:
       * the previous line originally looked like this:
       *
       *   pkt->iphdr.ip_sum = 0;
       *
       * but was changed to the memset-version due to an
       * aliasing problem
       */

      /* IP header checksum */
      check = 0;
      for (i=0; i<sizeof(struct ip)/2; i++) {
            check = NAME_(csum_add)(check, ntohs(((uint16_t *)&pkt->iphdr)[i]));
      }
      pkt->iphdr.ip_sum = htons(~check);

      /* UDP */
      pkt->udphdr.uh_ulen = htons(len - sizeof(struct ip));
      pkt->udphdr.uh_sum = 0;
}

static void
NAME_(reply_send)(struct cpssp *cpssp, const struct dhcp_reply * reply)
{
      int len;
      struct dhcp_pkt *pkt;
      struct dhcp_option *opt;
      const struct dhcp_option_list *options;

      /* calculate total length */
      len = sizeof(struct dhcp_pkt);
      len += 4;
      for (options=reply->first_option; options; options=options->next) {
            len += sizeof(struct dhcp_option) + options->option.len;
      }
      len += 1;

      /* assemble packet */
      pkt = malloc(len);
      memcpy(pkt, &reply->hdr, sizeof(struct dhcp_pkt));
      NAME_(fix_packet)(pkt, len);
      pkt->options[0]=99; pkt->options[1]=130;
      pkt->options[2]=83; pkt->options[3]=99;
      opt = (struct dhcp_option *) &pkt->options[4];
      for (options=reply->first_option; options; options=options->next) {
            memcpy(opt, &options->option, 2+options->option.len);
            opt = (struct dhcp_option *) &opt->data[opt->len];
      }
      opt->tag = DHCP_OPTION_END;

      /* send this packet */
#if DHCP_DEBUG
      NAME_(dump)(len, pkt);
#endif
      dhcp_reply(cpssp, (unsigned char *) pkt, len);
      free(pkt);
}

static void
NAME_(reply_free)(struct dhcp_reply * reply)
{
      struct dhcp_option_list * options;

      options=reply->first_option;
      while (options) {
            struct dhcp_option_list * to_delete = options;
            options = options->next;
            free(to_delete);
      }

      free(reply);
}

/* helpers for common options */

static void
NAME_(reply_msg_type)(struct dhcp_reply * reply, uint8_t type)
{
      struct dhcp_option * opt;

      opt = NAME_(reply_add_option)(reply, DHCP_OPTION_MSG_TYPE, 1);
      opt->data[0] = type;
}

static void
NAME_(reply_lease_time)(struct dhcp_reply * reply, int secs)
{
      NAME_(reply_add_option32)(reply, DHCP_OPTION_LEASE_TIME, htonl(secs));
}

static void
NAME_(reply_server_id)(struct cpssp *cpssp, struct dhcp_reply * reply)
{
      NAME_(reply_add_option32)(reply, DHCP_OPTION_SERVER_ID,
                  htonl(cpssp->NAME.server_id));
}

static void
NAME_(reply_config)(struct cpssp *cpssp, struct dhcp_reply * reply)
{
      if (cpssp->NAME.broadcast)
            NAME_(reply_add_option32)(reply, DHCP_OPTION_BROADCAST,
                        htonl(cpssp->NAME.broadcast));
      if (cpssp->NAME.netmask)
            NAME_(reply_add_option32)(reply, DHCP_OPTION_NETMASK,
                        htonl(cpssp->NAME.netmask));
      if (cpssp->NAME.dns_server)
            NAME_(reply_add_option32)(reply, DHCP_OPTION_DNS_SERVER,
                        htonl(cpssp->NAME.dns_server));
      if (cpssp->NAME.default_router)
            NAME_(reply_add_option32)(reply, DHCP_OPTION_ROUTERS,
                        htonl(cpssp->NAME.default_router));
}


/* process individual messages */


/* client initiates DHCP */
static int
NAME_(discover)(struct cpssp *cpssp, int len, const struct dhcp_pkt * pkt)
{
      struct dhcp_reply * reply;
      in_addr_t ip;

#if DHCP_DEBUG
      NAME_(dump)(len, pkt);
#endif

      ip = NAME_(ip_lookup)(cpssp, pkt->chaddr);
      if (!ip) {
            ip = NAME_(ip_next)(cpssp, pkt->chaddr);
      }
      if (!ip) return 1;

      reply = NAME_(reply_create)(cpssp, len, pkt);
      reply->hdr.yiaddr = htonl(ip);
      NAME_(reply_msg_type)(reply, DHCPOFFER);
      NAME_(reply_lease_time)(reply, 3600);
      NAME_(reply_server_id)(cpssp, reply);
      NAME_(reply_config)(cpssp, reply);
      NAME_(reply_send)(cpssp, reply);
      NAME_(reply_free)(reply);

      return 1;
}

/* client requests the IP we offered him */
static int
NAME_(request2)(struct cpssp *cpssp, int len, const struct dhcp_pkt *pkt)
{
      struct dhcp_reply * reply;
      const uint8_t * ipp;
      uint32_t requested;
      uint32_t offered;

#if DHCP_DEBUG
      NAME_(dump)(len, pkt);
#endif

      /* get ip for requesting host from our database */
      offered = NAME_(ip_lookup)(cpssp, pkt->chaddr);

      /* try to find out which ip is requested */
      requested=0;

      /* first, look for a REQUESTED_IP option */
      ipp = NAME_(option_get)(len, pkt, DHCP_OPTION_REQUESTED_IP);
      if (ipp
            && (ntohl(*(const uint32_t*)ipp) & cpssp->NAME.netmask)
                  == (cpssp->NAME.netmask & cpssp->NAME.first_ip)) {
            requested = ntohl(*(const uint32_t*)ipp);
      }

      /* next, try source ip from header, if it is looking valid */
      if (!requested) {
            if ((ntohl(pkt->iphdr.ip_src.s_addr) & cpssp->NAME.netmask)
                  == (cpssp->NAME.netmask & cpssp->NAME.first_ip)) {
                  requested = ntohl(pkt->iphdr.ip_src.s_addr);
            }
      }

      if (offered != 0) {
            if (requested != 0 && requested != offered) {
                  fprintf(stderr, "DHCP REQUEST "
                              "requested and offered IP do not match\n");
                  return 1;
                  /* FIXME: might be better to reply a DHCPNACK */
            }
      } else if (requested != 0) {
            if (NAME_(is_addr_free)(cpssp, requested)) {
                  NAME_(addr_set)(cpssp, requested, pkt->chaddr);
                  offered = requested;
            } else {
                  fprintf(stderr, "DHCP REQUEST "
                              "requested IP could not be assigned\n");
                  return 1;
                  /* FIXME: would be better to reply a DHCPNACK */
            }
      } else {
            fprintf(stderr, "DHCP REQUEST "
                        "neither requested IP nor one to offer\n");
            return 1;
      }

      reply = NAME_(reply_create)(cpssp, len, pkt);
      reply->hdr.yiaddr = htonl(offered);
      NAME_(reply_msg_type)(reply, DHCPACK);
      NAME_(reply_lease_time)(reply, 3600);
      NAME_(reply_config)(cpssp, reply);
      NAME_(reply_send)(cpssp, reply);
      NAME_(reply_free)(reply);
      return 1;
}

/* the client refuses to use the IP we gave him. */
/* most likely it is already used by another machine */
static int
NAME_(decline)(struct cpssp *cpssp, int len, const struct dhcp_pkt *pkt)
{
      const uint8_t *ipopt;

      ipopt = NAME_(option_get)(len, pkt, DHCP_OPTION_SERVER_ID);
      if (! ipopt
       || ntohl(*(const uint32_t *) ipopt) != cpssp->NAME.server_id) {
            fprintf(stderr, "DHCP DECLINE without our server ID\n");
            return 1;
      }
      ipopt = NAME_(option_get)(len, pkt, DHCP_OPTION_REQUESTED_IP);
      if (! ipopt) {
            fprintf(stderr, "DHCP DECLINE without an IP\n");
            return 1;
      }

      /* don't use that IP any more */
      NAME_(addr_invalid)(cpssp, ntohl(*(const uint32_t *) ipopt));
      fprintf(stderr, "DHCPDECLINE for %s received.\n");

      return 1;
}

/* main DHCP processing */

static int
NAME_(request)(struct cpssp *cpssp, const unsigned char *_pkt, unsigned int len)
{
      const struct dhcp_pkt *pkt = (const struct dhcp_pkt *) _pkt;
      const uint8_t * type;

      /* don't do anything if DHCP is not configured yet */
      if (! cpssp->NAME.first_ip) return 0;

      type = NAME_(option_get)(len, pkt, DHCP_OPTION_MSG_TYPE);
      if (!type) {
            fprintf(stderr, "DHCP request without msg type option!\n");
            return 1;
      }

      /* multiplex based on message type */
      switch (*type) {
      case DHCPDISCOVER:
            return NAME_(discover)(cpssp, len, pkt);
      case DHCPREQUEST:
            return NAME_(request2)(cpssp, len, pkt);
      case DHCPDECLINE:
            return NAME_(decline)(cpssp, len, pkt);
      default:
            fprintf(stderr, "unimplemented DHCP message: %s\n",
                        NAME_(msg_type)(*type));
      }
      
      return 1; /* consume packet */
}

static void
NAME_(init)(struct cpssp *cpssp,
            unsigned int nr
)
{
      cpssp->NAME.database = shm_map(COMP ".dhcp", nr, cpssp->NAME.range * 16, 0);

      memset(cpssp->NAME.database, 0xff, cpssp->NAME.range * 16);
}

static void
NAME_(create)(
      struct cpssp *cpssp,
      unsigned int nr,
        uint32_t ip,
        uint32_t first_ip,
      uint32_t netmask,
      uint32_t broadcast,
      uint32_t default_router,
      uint32_t dns_server
)
{
      uint32_t max_range;

      max_range = ~netmask + 1;

      cpssp->NAME.server_id = ip;
      cpssp->NAME.first_ip = first_ip;
      cpssp->NAME.range = max_range - (first_ip & ~netmask) - 1;
      cpssp->NAME.netmask = netmask;
      cpssp->NAME.broadcast = broadcast;
      cpssp->NAME.default_router = default_router;
      cpssp->NAME.dns_server = dns_server;

      shm_create(COMP ".dhcp", nr, cpssp->NAME.range * 16);
}

static void
NAME_(destroy)(struct cpssp *cpssp, unsigned int nr)
{
      shm_destroy(COMP ".dhcp", nr);
}

#endif /* BEHAVIOR */

Generated by  Doxygen 1.6.0   Back to index