1415c960b22b4084057577fc371510864378354ddRob Landley/* dhcpd.c - DHCP server for dynamic network configuration.
2415c960b22b4084057577fc371510864378354ddRob Landley *
3415c960b22b4084057577fc371510864378354ddRob Landley * Copyright 2013 Madhur Verma <mad.flexi@gmail.com>
4415c960b22b4084057577fc371510864378354ddRob Landley * Copyright 2013 Kyungwan Han <asura321@gamil.com>
560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh * Copyright 2015 Yeongdeok Suh <skyducks111@gmail.com>
6415c960b22b4084057577fc371510864378354ddRob Landley *
7415c960b22b4084057577fc371510864378354ddRob Landley * No Standard
8c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok SuhUSE_DHCPD(NEWTOY(dhcpd, ">1P#<0>65535fi:S46[!46]", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
9415c960b22b4084057577fc371510864378354ddRob Landley
10415c960b22b4084057577fc371510864378354ddRob Landleyconfig DHCPD
11415c960b22b4084057577fc371510864378354ddRob Landley  bool "dhcpd"
12415c960b22b4084057577fc371510864378354ddRob Landley  default n
13415c960b22b4084057577fc371510864378354ddRob Landley  help
1460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh   usage: dhcpd [-46fS] [-i IFACE] [-P N] [CONFFILE]
15415c960b22b4084057577fc371510864378354ddRob Landley
16415c960b22b4084057577fc371510864378354ddRob Landley    -f    Run in foreground
1760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    -i Interface to use
18415c960b22b4084057577fc371510864378354ddRob Landley    -S    Log to syslog too
1960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    -P N  Use port N (default ipv4 67, ipv6 547)
2060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    -4, -6    Run as a DHCPv4 or DHCPv6 server
21415c960b22b4084057577fc371510864378354ddRob Landley
22415c960b22b4084057577fc371510864378354ddRob Landleyconfig DEBUG_DHCP
23415c960b22b4084057577fc371510864378354ddRob Landley  bool "debugging messeges ON/OFF"
24415c960b22b4084057577fc371510864378354ddRob Landley  default n
25415c960b22b4084057577fc371510864378354ddRob Landley  depends on DHCPD
26415c960b22b4084057577fc371510864378354ddRob Landley*/
27415c960b22b4084057577fc371510864378354ddRob Landley
2860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh/*
29c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh * TODO
3060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh * - Working as an relay agent
3160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh * - Rapid commit option support
3260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh * - Additional packet options (commented on the middle of sources)
3360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh * - Create common modules
3460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh */
3560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
36415c960b22b4084057577fc371510864378354ddRob Landley#define FOR_dhcpd
37415c960b22b4084057577fc371510864378354ddRob Landley
38415c960b22b4084057577fc371510864378354ddRob Landley#include "toys.h"
39415c960b22b4084057577fc371510864378354ddRob Landley#include <linux/sockios.h>
40415c960b22b4084057577fc371510864378354ddRob Landley#include <linux/if_ether.h>
41415c960b22b4084057577fc371510864378354ddRob Landley
42415c960b22b4084057577fc371510864378354ddRob Landley// Todo: headers not in posix
43415c960b22b4084057577fc371510864378354ddRob Landley#include <netinet/ip.h>
4460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#include <netinet/ip6.h>
45415c960b22b4084057577fc371510864378354ddRob Landley#include <netinet/udp.h>
46415c960b22b4084057577fc371510864378354ddRob Landley#include <netpacket/packet.h>
47415c960b22b4084057577fc371510864378354ddRob Landley
48415c960b22b4084057577fc371510864378354ddRob Landley#if CFG_DEBUG_DHCP==1
49415c960b22b4084057577fc371510864378354ddRob Landley# define dbg(fmt, arg...)   printf(fmt, ##arg)
50415c960b22b4084057577fc371510864378354ddRob Landley#else
51415c960b22b4084057577fc371510864378354ddRob Landley# define dbg(fmt, arg...)
52415c960b22b4084057577fc371510864378354ddRob Landley#endif
53415c960b22b4084057577fc371510864378354ddRob Landley
54415c960b22b4084057577fc371510864378354ddRob Landley#define LOG_SILENT          0x0
55415c960b22b4084057577fc371510864378354ddRob Landley#define LOG_CONSOLE         0x1
56415c960b22b4084057577fc371510864378354ddRob Landley#define LOG_SYSTEM          0x2
57415c960b22b4084057577fc371510864378354ddRob Landley
58415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_MAGIC          0x63825363
59415c960b22b4084057577fc371510864378354ddRob Landley
60415c960b22b4084057577fc371510864378354ddRob Landley#define DHCPDISCOVER        1
61415c960b22b4084057577fc371510864378354ddRob Landley#define DHCPOFFER           2
62415c960b22b4084057577fc371510864378354ddRob Landley#define DHCPREQUEST         3
63415c960b22b4084057577fc371510864378354ddRob Landley#define DHCPDECLINE         4
64415c960b22b4084057577fc371510864378354ddRob Landley#define DHCPACK             5
65415c960b22b4084057577fc371510864378354ddRob Landley#define DHCPNAK             6
66415c960b22b4084057577fc371510864378354ddRob Landley#define DHCPRELEASE         7
67415c960b22b4084057577fc371510864378354ddRob Landley#define DHCPINFORM          8
68415c960b22b4084057577fc371510864378354ddRob Landley
6960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6SOLICIT        1
7060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6ADVERTISE      2   // server -> client
7160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6REQUEST        3
7260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6CONFIRM        4
7360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6RENEW          5
7460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6REBIND         6
7560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6REPLY          7   // server -> client
7660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6RELEASE        8
7760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6DECLINE        9
7860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6RECONFIGURE    10  // server -> client
7960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6INFOREQUEST    11
8060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6RELAYFLOW      12  // relay -> relay/server
8160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6RELAYREPLY     13  // server/relay -> relay
8260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
83415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_NUM8           (1<<8)
84415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_NUM16          (1<<9)
85415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_NUM32          DHCP_NUM16 | DHCP_NUM8
86415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_STRING         (1<<10)
87415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_STRLST         (1<<11)
88415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_IP             (1<<12)
89415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_IPLIST         (1<<13)
90415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_IPPLST         (1<<14)
91415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_STCRTS         (1<<15)
92415c960b22b4084057577fc371510864378354ddRob Landley
93415c960b22b4084057577fc371510864378354ddRob Landley// DHCP option codes (partial list). See RFC 2132 and
94415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_OPT_PADDING                          0x00
95415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_OPT_HOST_NAME          DHCP_STRING | 0x0c // either client informs server or server gives name to client
96415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_OPT_REQUESTED_IP       DHCP_IP     | 0x32 // sent by client if specific IP is wanted
97415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_OPT_LEASE_TIME         DHCP_NUM32  | 0x33
98415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_OPT_OPTION_OVERLOAD                  0x34
99415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_OPT_MESSAGE_TYPE       DHCP_NUM8   | 0x35
100415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_OPT_SERVER_ID          DHCP_IP     | 0x36 // by default server's IP
101415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_OPT_PARAM_REQ          DHCP_STRING | 0x37 // list of options client wants
102415c960b22b4084057577fc371510864378354ddRob Landley#define DHCP_OPT_END                              0xff
103415c960b22b4084057577fc371510864378354ddRob Landley
10460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh// DHCPv6 option codes (partial). See RFC 3315
10560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_CLIENTID      1
10660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_SERVERID      2
10760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_IA_NA         3
10860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_IA_ADDR       5
10960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_ORO           6
11060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_PREFERENCE    7
11160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_ELAPSED_TIME  8
11260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_RELAY_MSG     9
11360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_STATUS_CODE   13
11460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_IA_PD         25
11560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_OPT_IA_PREFIX     26
11660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
11760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_STATUS_SUCCESS        0
11860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_STATUS_NOADDRSAVAIL   2
11960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
12060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_DUID_LLT    1
12160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_DUID_EN     2
12260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_DUID_LL     3
12360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh#define DHCP6_DUID_UUID   4
12460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
125415c960b22b4084057577fc371510864378354ddRob LandleyGLOBALS(
12682d8d7cb7eacabd1a498c001dd5618a1302f854bHyejin Kim    char *iface;
127415c960b22b4084057577fc371510864378354ddRob Landley    long port;
128415c960b22b4084057577fc371510864378354ddRob Landley);
129415c960b22b4084057577fc371510864378354ddRob Landley
13060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstruct config_keyword {
13160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  char *keyword;
13260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  int (*handler)(const char *str, void *var);
13360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  void *var;
13460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  char *def;
13560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh};
13660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
137415c960b22b4084057577fc371510864378354ddRob Landleytypedef struct __attribute__((packed)) dhcp_msg_s {
138415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t op;
139415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t htype;
140415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t hlen;
141415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t hops;
142415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t xid;
143415c960b22b4084057577fc371510864378354ddRob Landley  uint16_t secs;
144415c960b22b4084057577fc371510864378354ddRob Landley  uint16_t flags;
145415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t ciaddr;
146415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t yiaddr;
147415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t nsiaddr;
148415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t ngiaddr;
149415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t chaddr[16];
150415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t sname[64];
151415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t file[128];
152415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t cookie;
153415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t options[308];
154415c960b22b4084057577fc371510864378354ddRob Landley} dhcp_msg_t;
155415c960b22b4084057577fc371510864378354ddRob Landley
15660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhtypedef struct __attribute__((packed)) dhcp6_msg_s {
15760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint8_t msgtype;
15860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint8_t transaction_id[3];
15960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint8_t options[524];
16060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh} dhcp6_msg_t;
16160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
162415c960b22b4084057577fc371510864378354ddRob Landleytypedef struct __attribute__((packed)) dhcp_raw_s {
163415c960b22b4084057577fc371510864378354ddRob Landley  struct iphdr iph;
164415c960b22b4084057577fc371510864378354ddRob Landley  struct udphdr udph;
165415c960b22b4084057577fc371510864378354ddRob Landley  dhcp_msg_t dhcp;
166415c960b22b4084057577fc371510864378354ddRob Landley} dhcp_raw_t;
167415c960b22b4084057577fc371510864378354ddRob Landley
16860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhtypedef struct __attribute__((packed)) dhcp6_raw_s {
16960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct ip6_hdr iph;
17060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct udphdr udph;
17160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dhcp6_msg_t dhcp6;
17260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh} dhcp6_raw_t;
17360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
174415c960b22b4084057577fc371510864378354ddRob Landleytypedef struct static_lease_s {
175415c960b22b4084057577fc371510864378354ddRob Landley  struct static_lease_s *next;
176415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t nip;
177415c960b22b4084057577fc371510864378354ddRob Landley  int mac[6];
178415c960b22b4084057577fc371510864378354ddRob Landley} static_lease;
179415c960b22b4084057577fc371510864378354ddRob Landley
18060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhtypedef struct static_lease6_s {
18160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct static_lease6_s *next;
18260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint16_t duid_len;
18360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint16_t ia_type;
18460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t iaid;
185c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint8_t nip6[16];
18660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint8_t duid[20];
18760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh} static_lease6;
18860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
189415c960b22b4084057577fc371510864378354ddRob Landleytypedef struct {
190415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t expires;
191415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t lease_nip;
192415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t lease_mac[6];
193415c960b22b4084057577fc371510864378354ddRob Landley  char hostname[20];
194415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t pad[2];
195415c960b22b4084057577fc371510864378354ddRob Landley} dyn_lease;
196415c960b22b4084057577fc371510864378354ddRob Landley
19760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhtypedef struct {
19860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint16_t duid_len;
19960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint16_t ia_type;
20060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t expires;
20160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t iaid;
202c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint8_t lease_nip6[16];
20360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint8_t duid[20];
20460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh} dyn_lease6;
20560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
206415c960b22b4084057577fc371510864378354ddRob Landleytypedef struct option_val_s {
207415c960b22b4084057577fc371510864378354ddRob Landley  char *key;
208415c960b22b4084057577fc371510864378354ddRob Landley  uint16_t code;
209415c960b22b4084057577fc371510864378354ddRob Landley  void *val;
210415c960b22b4084057577fc371510864378354ddRob Landley  size_t len;
211415c960b22b4084057577fc371510864378354ddRob Landley} option_val_t;
212415c960b22b4084057577fc371510864378354ddRob Landley
21360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstruct __attribute__((packed)) optval_duid_llt {
21460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint16_t type;
21560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint16_t hwtype;
21660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t time;
217c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint8_t lladdr[];   //flexible
21860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh};
21960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
22060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstruct __attribute__((packed)) optval_ia_na {
22160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t iaid;
22260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t t1, t2;
223c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint8_t optval[];   //flexible
22460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh};
22560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstruct __attribute__((packed)) optval_ia_addr {
226c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint8_t ipv6_addr[16];
22760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t pref_lifetime;
22860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t valid_lifetime;
22960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh};
23060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstruct __attribute__((packed)) optval_status_code {
23160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint16_t status_code;
232c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint8_t status_msg[]; //flexible
23360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh};
23460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
235415c960b22b4084057577fc371510864378354ddRob Landleytypedef struct __attribute__((__may_alias__)) server_config_s {
236415c960b22b4084057577fc371510864378354ddRob Landley  char *interface;                // interface to use
237415c960b22b4084057577fc371510864378354ddRob Landley  int ifindex;
238c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint8_t server_nip6[16];
239415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t server_nip;
240415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t port;
241415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t server_mac[6];          // our MAC address (used only for ARP probing)
242415c960b22b4084057577fc371510864378354ddRob Landley  void *options[256];             // list of DHCP options loaded from the config file
243415c960b22b4084057577fc371510864378354ddRob Landley  /* start,end are in host order: we need to compare start <= ip <= end*/
244415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t start_ip;              // start address of leases, in host order
245415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t end_ip;                // end of leases, in host order
246c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint8_t start_ip6[16];          // start address of leases, in IPv6 mode
247c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint8_t end_ip6[16];            // end of leases, in IPv6 mode
248415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t max_lease_sec;         // maximum lease time (host order)
249415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t min_lease_sec;         // minimum lease time a client can request
250415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t max_leases;            // maximum number of leases (including reserved addresses)
251415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t auto_time;             // how long should dhcpd wait before writing a config file.
252415c960b22b4084057577fc371510864378354ddRob Landley                                  // if this is zero, it will only write one on SIGUSR1
253415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t decline_time;          // how long an address is reserved if a client returns a
254415c960b22b4084057577fc371510864378354ddRob Landley                                  // decline message
255415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t conflict_time;         // how long an arp conflict offender is leased for
256415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t offer_time;            // how long an offered address is reserved
257415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t siaddr_nip;            // "next server" bootp option
258415c960b22b4084057577fc371510864378354ddRob Landley  char *lease_file;
25960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  char *lease6_file;
260415c960b22b4084057577fc371510864378354ddRob Landley  char *pidfile;
261415c960b22b4084057577fc371510864378354ddRob Landley  char *notify_file;              // what to run whenever leases are written
262415c960b22b4084057577fc371510864378354ddRob Landley  char *sname;                    // bootp server name
263415c960b22b4084057577fc371510864378354ddRob Landley  char *boot_file;                // bootp boot file option
26460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t pref_lifetime;
26560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t valid_lifetime;
26660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t t1,t2;
267415c960b22b4084057577fc371510864378354ddRob Landley  struct static_lease *static_leases; // List of ip/mac pairs to assign static leases
268415c960b22b4084057577fc371510864378354ddRob Landley} server_config_t;
269415c960b22b4084057577fc371510864378354ddRob Landley
270415c960b22b4084057577fc371510864378354ddRob Landleytypedef struct __attribute__((__may_alias__)) server_state_s {
271c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint8_t client_nip6[16];
272c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint32_t client_port;
273415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t rqcode;
274415c960b22b4084057577fc371510864378354ddRob Landley  int listensock;
27560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  union {
27660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    dhcp_msg_t rcvd_pkt;
27760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    dhcp6_msg_t rcvd_pkt6;
27860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  } rcvd;
279415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t* rqopt;
28060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  union {
28160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    dhcp_msg_t send_pkt;
28260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    dhcp6_msg_t send_pkt6;
28360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  } send;
28460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  union {
28560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    static_lease *sleases;
28660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    static_lease6 *sleases6;
28760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  } leases;
288415c960b22b4084057577fc371510864378354ddRob Landley  struct arg_list *dleases;
289415c960b22b4084057577fc371510864378354ddRob Landley} server_state_t;
290415c960b22b4084057577fc371510864378354ddRob Landley
291415c960b22b4084057577fc371510864378354ddRob Landleystatic option_val_t options_list[] = {
292415c960b22b4084057577fc371510864378354ddRob Landley    {"lease"          , DHCP_NUM32  | 0x33, NULL, 0},
293415c960b22b4084057577fc371510864378354ddRob Landley    {"subnet"         , DHCP_IP     | 0x01, NULL, 0},
294415c960b22b4084057577fc371510864378354ddRob Landley    {"broadcast"      , DHCP_IP     | 0x1c, NULL, 0},
295415c960b22b4084057577fc371510864378354ddRob Landley    {"router"         , DHCP_IP     | 0x03, NULL, 0},
296415c960b22b4084057577fc371510864378354ddRob Landley    {"ipttl"          , DHCP_NUM8   | 0x17, NULL, 0},
297415c960b22b4084057577fc371510864378354ddRob Landley    {"mtu"            , DHCP_NUM16  | 0x1a, NULL, 0},
298415c960b22b4084057577fc371510864378354ddRob Landley    {"hostname"       , DHCP_STRING | 0x0c, NULL, 0},
299415c960b22b4084057577fc371510864378354ddRob Landley    {"domain"         , DHCP_STRING | 0x0f, NULL, 0},
300415c960b22b4084057577fc371510864378354ddRob Landley    {"search"         , DHCP_STRLST | 0x77, NULL, 0},
301415c960b22b4084057577fc371510864378354ddRob Landley    {"nisdomain"      , DHCP_STRING | 0x28, NULL, 0},
302415c960b22b4084057577fc371510864378354ddRob Landley    {"timezone"       , DHCP_NUM32  | 0x02, NULL, 0},
303415c960b22b4084057577fc371510864378354ddRob Landley    {"tftp"           , DHCP_STRING | 0x42, NULL, 0},
304415c960b22b4084057577fc371510864378354ddRob Landley    {"bootfile"       , DHCP_STRING | 0x43, NULL, 0},
305415c960b22b4084057577fc371510864378354ddRob Landley    {"bootsize"       , DHCP_NUM16  | 0x0d, NULL, 0},
306415c960b22b4084057577fc371510864378354ddRob Landley    {"rootpath"       , DHCP_STRING | 0x11, NULL, 0},
307415c960b22b4084057577fc371510864378354ddRob Landley    {"wpad"           , DHCP_STRING | 0xfc, NULL, 0},
308415c960b22b4084057577fc371510864378354ddRob Landley    {"serverid"       , DHCP_IP     | 0x36, NULL, 0},
309415c960b22b4084057577fc371510864378354ddRob Landley    {"message"        , DHCP_STRING | 0x38, NULL, 0},
310415c960b22b4084057577fc371510864378354ddRob Landley    {"vlanid"         , DHCP_NUM32  | 0x84, NULL, 0},
311415c960b22b4084057577fc371510864378354ddRob Landley    {"vlanpriority"   , DHCP_NUM32  | 0x85, NULL, 0},
312415c960b22b4084057577fc371510864378354ddRob Landley    {"dns"            , DHCP_IPLIST | 0x06, NULL, 0},
313415c960b22b4084057577fc371510864378354ddRob Landley    {"wins"           , DHCP_IPLIST | 0x2c, NULL, 0},
314415c960b22b4084057577fc371510864378354ddRob Landley    {"nissrv"         , DHCP_IPLIST | 0x29, NULL, 0},
315415c960b22b4084057577fc371510864378354ddRob Landley    {"ntpsrv"         , DHCP_IPLIST | 0x2a, NULL, 0},
316415c960b22b4084057577fc371510864378354ddRob Landley    {"lprsrv"         , DHCP_IPLIST | 0x09, NULL, 0},
317415c960b22b4084057577fc371510864378354ddRob Landley    {"swapsrv"        , DHCP_IP     | 0x10, NULL, 0},
318415c960b22b4084057577fc371510864378354ddRob Landley    {"routes"         , DHCP_STCRTS | 0x21, NULL, 0},
319415c960b22b4084057577fc371510864378354ddRob Landley    {"staticroutes"   , DHCP_STCRTS | 0x79, NULL, 0},
320415c960b22b4084057577fc371510864378354ddRob Landley    {"msstaticroutes" , DHCP_STCRTS | 0xf9, NULL, 0},
321415c960b22b4084057577fc371510864378354ddRob Landley};
322415c960b22b4084057577fc371510864378354ddRob Landley
323415c960b22b4084057577fc371510864378354ddRob Landleystruct fd_pair { int rd; int wr; };
324415c960b22b4084057577fc371510864378354ddRob Landleystatic server_config_t gconfig;
325415c960b22b4084057577fc371510864378354ddRob Landleystatic server_state_t gstate;
326415c960b22b4084057577fc371510864378354ddRob Landleystatic uint8_t infomode;
327415c960b22b4084057577fc371510864378354ddRob Landleystatic struct fd_pair sigfd;
328415c960b22b4084057577fc371510864378354ddRob Landleystatic int constone = 1;
32960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic sa_family_t addr_version = AF_INET;
33060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
331415c960b22b4084057577fc371510864378354ddRob Landley// calculate options size.
332415c960b22b4084057577fc371510864378354ddRob Landleystatic int dhcp_opt_size(uint8_t *optionptr)
333415c960b22b4084057577fc371510864378354ddRob Landley{
334415c960b22b4084057577fc371510864378354ddRob Landley  int i = 0;
33560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  for(;optionptr[i] != 0xff; i++)
33660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if(optionptr[i] != 0x00) i += optionptr[i + 1] + 2 -1;
337415c960b22b4084057577fc371510864378354ddRob Landley  return i;
338415c960b22b4084057577fc371510864378354ddRob Landley}
339415c960b22b4084057577fc371510864378354ddRob Landley
340415c960b22b4084057577fc371510864378354ddRob Landley// calculates checksum for dhcp messeges.
341415c960b22b4084057577fc371510864378354ddRob Landleystatic uint16_t dhcp_checksum(void *addr, int count)
342415c960b22b4084057577fc371510864378354ddRob Landley{
343415c960b22b4084057577fc371510864378354ddRob Landley  int32_t sum = 0;
344415c960b22b4084057577fc371510864378354ddRob Landley  uint16_t tmp = 0, *source = (uint16_t *)addr;
345415c960b22b4084057577fc371510864378354ddRob Landley
346415c960b22b4084057577fc371510864378354ddRob Landley  while (count > 1)  {
347415c960b22b4084057577fc371510864378354ddRob Landley    sum += *source++;
348415c960b22b4084057577fc371510864378354ddRob Landley    count -= 2;
349415c960b22b4084057577fc371510864378354ddRob Landley  }
350415c960b22b4084057577fc371510864378354ddRob Landley  if (count > 0) {
351415c960b22b4084057577fc371510864378354ddRob Landley    *(uint8_t*)&tmp = *(uint8_t*)source;
352415c960b22b4084057577fc371510864378354ddRob Landley    sum += tmp;
353415c960b22b4084057577fc371510864378354ddRob Landley  }
354415c960b22b4084057577fc371510864378354ddRob Landley  while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
355415c960b22b4084057577fc371510864378354ddRob Landley  return ~sum;
356415c960b22b4084057577fc371510864378354ddRob Landley}
357415c960b22b4084057577fc371510864378354ddRob Landley
358415c960b22b4084057577fc371510864378354ddRob Landley// gets information of INTERFACE and updates IFINDEX, MAC and IP
359c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suhstatic int get_interface(const char *interface, int *ifindex, void *oip,
36060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    uint8_t *mac)
361415c960b22b4084057577fc371510864378354ddRob Landley{
362415c960b22b4084057577fc371510864378354ddRob Landley  struct ifreq req;
363415c960b22b4084057577fc371510864378354ddRob Landley  struct sockaddr_in *ip;
36460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct sockaddr_in6 ip6;
36560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  int fd = xsocket(addr_version, SOCK_RAW, IPPROTO_RAW);
36660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  char ipv6_addr[40] = {0,};
367415c960b22b4084057577fc371510864378354ddRob Landley
36860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  req.ifr_addr.sa_family = addr_version;
36960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  xstrncpy(req.ifr_name, (char *)interface, IFNAMSIZ);
370415c960b22b4084057577fc371510864378354ddRob Landley
371415c960b22b4084057577fc371510864378354ddRob Landley  xioctl(fd, SIOCGIFFLAGS, &req);
37260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
373415c960b22b4084057577fc371510864378354ddRob Landley  if (!(req.ifr_flags & IFF_UP)) return -1;
37460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
37560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (addr_version == AF_INET6) {
37660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
37760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    FILE *fd6 = fopen("/proc/net/if_inet6", "r");
378c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    uint8_t *oip6 = (uint8_t*)oip;
37960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    int i;
38060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
38160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    while(fgets(toybuf, sizeof(toybuf), fd6)) {
38260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if (!strstr(toybuf, interface))
38360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        continue;
38460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
385c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh      if (sscanf(toybuf, "%32s \n", ipv6_addr) == 1)
386c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        break;
38760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
38860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    fclose(fd6);
38960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
390c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    if (oip6) {
39160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      char *ptr = ipv6_addr+sizeof(ipv6_addr)-1;
39260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
39360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      // convert giant hex string into colon-spearated ipv6 address by
39460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      // inserting ':' every 4 characters.
39560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      for (i = 32; i; i--)
39660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        if ((*(ptr--) = ipv6_addr[i])) if (!(i&3)) *(ptr--) = ':';
39760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
39860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      dbg("ipv6 %s\n", ipv6_addr);
39960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if(inet_pton(AF_INET6, ipv6_addr, &ip6.sin6_addr) <= 0)
40060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        error_msg("inet : the ipv6 address is not proper");
40160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      else
402c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        memcpy(oip6, ip6.sin6_addr.s6_addr32, sizeof(uint32_t)*4);
40360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
40460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  } else {
405c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    uint32_t *oip4 = (uint32_t*)oip;
406c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    if (oip4) {
40760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      xioctl(fd, SIOCGIFADDR, &req);
40860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      ip = (struct sockaddr_in*) &req.ifr_addr;
40960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      dbg("IP %s\n", inet_ntoa(ip->sin_addr));
410c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh      *oip4 = ntohl(ip->sin_addr.s_addr);
41160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
412415c960b22b4084057577fc371510864378354ddRob Landley  }
41360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
414415c960b22b4084057577fc371510864378354ddRob Landley  if (ifindex) {
415415c960b22b4084057577fc371510864378354ddRob Landley    xioctl(fd, SIOCGIFINDEX, &req);
416415c960b22b4084057577fc371510864378354ddRob Landley    dbg("Adapter index %d\n", req.ifr_ifindex);
417415c960b22b4084057577fc371510864378354ddRob Landley    *ifindex = req.ifr_ifindex;
418415c960b22b4084057577fc371510864378354ddRob Landley  }
419415c960b22b4084057577fc371510864378354ddRob Landley  if (mac) {
420415c960b22b4084057577fc371510864378354ddRob Landley    xioctl(fd, SIOCGIFHWADDR, &req);
421415c960b22b4084057577fc371510864378354ddRob Landley    memcpy(mac, req.ifr_hwaddr.sa_data, 6);
422415c960b22b4084057577fc371510864378354ddRob Landley    dbg("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
423415c960b22b4084057577fc371510864378354ddRob Landley  }
42460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
425415c960b22b4084057577fc371510864378354ddRob Landley  close(fd);
426415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
427415c960b22b4084057577fc371510864378354ddRob Landley}
428415c960b22b4084057577fc371510864378354ddRob Landley
429415c960b22b4084057577fc371510864378354ddRob Landley/*
430415c960b22b4084057577fc371510864378354ddRob Landley *logs messeges to syslog or console
431415c960b22b4084057577fc371510864378354ddRob Landley *opening the log is still left with applet.
432415c960b22b4084057577fc371510864378354ddRob Landley *FIXME: move to more relevent lib. probably libc.c
433415c960b22b4084057577fc371510864378354ddRob Landley */
434415c960b22b4084057577fc371510864378354ddRob Landleystatic void infomsg(uint8_t infomode, char *s, ...)
435415c960b22b4084057577fc371510864378354ddRob Landley{
436415c960b22b4084057577fc371510864378354ddRob Landley  int used;
437415c960b22b4084057577fc371510864378354ddRob Landley  char *msg;
438415c960b22b4084057577fc371510864378354ddRob Landley  va_list p, t;
439415c960b22b4084057577fc371510864378354ddRob Landley
440415c960b22b4084057577fc371510864378354ddRob Landley  if (infomode == LOG_SILENT) return;
441415c960b22b4084057577fc371510864378354ddRob Landley  va_start(p, s);
442415c960b22b4084057577fc371510864378354ddRob Landley  va_copy(t, p);
443415c960b22b4084057577fc371510864378354ddRob Landley  used = vsnprintf(NULL, 0, s, t);
444415c960b22b4084057577fc371510864378354ddRob Landley  used++;
445415c960b22b4084057577fc371510864378354ddRob Landley  va_end(t);
446415c960b22b4084057577fc371510864378354ddRob Landley
447415c960b22b4084057577fc371510864378354ddRob Landley  msg = xmalloc(used);
448415c960b22b4084057577fc371510864378354ddRob Landley  vsnprintf(msg, used, s, p);
449415c960b22b4084057577fc371510864378354ddRob Landley  va_end(p);
450415c960b22b4084057577fc371510864378354ddRob Landley
451415c960b22b4084057577fc371510864378354ddRob Landley  if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
452415c960b22b4084057577fc371510864378354ddRob Landley  if (infomode & LOG_CONSOLE) printf("%s\n", msg);
453415c960b22b4084057577fc371510864378354ddRob Landley  free(msg);
454415c960b22b4084057577fc371510864378354ddRob Landley}
455415c960b22b4084057577fc371510864378354ddRob Landley
456415c960b22b4084057577fc371510864378354ddRob Landley/*
457415c960b22b4084057577fc371510864378354ddRob Landley * Writes self PID in file PATH
458415c960b22b4084057577fc371510864378354ddRob Landley * FIXME: libc implementation only writes in /var/run
459415c960b22b4084057577fc371510864378354ddRob Landley * this is more generic as some implemenation may provide
460415c960b22b4084057577fc371510864378354ddRob Landley * arguments to write in specific file. as dhcpd does.
461415c960b22b4084057577fc371510864378354ddRob Landley */
462415c960b22b4084057577fc371510864378354ddRob Landleystatic void write_pid(char *path)
463415c960b22b4084057577fc371510864378354ddRob Landley{
464415c960b22b4084057577fc371510864378354ddRob Landley  int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
465415c960b22b4084057577fc371510864378354ddRob Landley  if (pidfile > 0) {
46679d8bc70539b7a3d459630c97e38d3cdff77e591Rob Landley    char pidbuf[12];
46779d8bc70539b7a3d459630c97e38d3cdff77e591Rob Landley
46879d8bc70539b7a3d459630c97e38d3cdff77e591Rob Landley    sprintf(pidbuf, "%u", (unsigned)getpid());
469415c960b22b4084057577fc371510864378354ddRob Landley    write(pidfile, pidbuf, strlen(pidbuf));
470415c960b22b4084057577fc371510864378354ddRob Landley    close(pidfile);
471415c960b22b4084057577fc371510864378354ddRob Landley  }
472415c960b22b4084057577fc371510864378354ddRob Landley}
473415c960b22b4084057577fc371510864378354ddRob Landley
474415c960b22b4084057577fc371510864378354ddRob Landley// Generic signal handler real handling is done in main funcrion.
475415c960b22b4084057577fc371510864378354ddRob Landleystatic void signal_handler(int sig)
476415c960b22b4084057577fc371510864378354ddRob Landley{
477415c960b22b4084057577fc371510864378354ddRob Landley  unsigned char ch = sig;
478415c960b22b4084057577fc371510864378354ddRob Landley  if (write(sigfd.wr, &ch, 1) != 1) dbg("can't send signal\n");
479415c960b22b4084057577fc371510864378354ddRob Landley}
480415c960b22b4084057577fc371510864378354ddRob Landley
481415c960b22b4084057577fc371510864378354ddRob Landley// signal setup for SIGUSR1 SIGTERM
482415c960b22b4084057577fc371510864378354ddRob Landleystatic int setup_signal()
483415c960b22b4084057577fc371510864378354ddRob Landley{
484415c960b22b4084057577fc371510864378354ddRob Landley  if (pipe((int *)&sigfd) < 0) {
485415c960b22b4084057577fc371510864378354ddRob Landley    dbg("signal pipe failed\n");
486415c960b22b4084057577fc371510864378354ddRob Landley    return -1;
487415c960b22b4084057577fc371510864378354ddRob Landley  }
488415c960b22b4084057577fc371510864378354ddRob Landley  fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC);
489415c960b22b4084057577fc371510864378354ddRob Landley  fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC);
490415c960b22b4084057577fc371510864378354ddRob Landley  int flags = fcntl(sigfd.wr, F_GETFL);
491415c960b22b4084057577fc371510864378354ddRob Landley  fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK);
492415c960b22b4084057577fc371510864378354ddRob Landley  signal(SIGUSR1, signal_handler);
493415c960b22b4084057577fc371510864378354ddRob Landley  signal(SIGTERM, signal_handler);
494415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
495415c960b22b4084057577fc371510864378354ddRob Landley}
496415c960b22b4084057577fc371510864378354ddRob Landley
497415c960b22b4084057577fc371510864378354ddRob Landley// String STR to UINT32 conversion strored in VAR
498415c960b22b4084057577fc371510864378354ddRob Landleystatic int strtou32(const char *str, void *var)
499415c960b22b4084057577fc371510864378354ddRob Landley{
500415c960b22b4084057577fc371510864378354ddRob Landley  char *endptr = NULL;
501415c960b22b4084057577fc371510864378354ddRob Landley  int base = 10;
502415c960b22b4084057577fc371510864378354ddRob Landley  errno=0;
503415c960b22b4084057577fc371510864378354ddRob Landley  *((uint32_t*)(var)) = 0;
504415c960b22b4084057577fc371510864378354ddRob Landley  if (str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
505415c960b22b4084057577fc371510864378354ddRob Landley    base = 16;
506415c960b22b4084057577fc371510864378354ddRob Landley    str+=2;
507415c960b22b4084057577fc371510864378354ddRob Landley  }
50860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
509415c960b22b4084057577fc371510864378354ddRob Landley  long ret_val = strtol(str, &endptr, base);
510415c960b22b4084057577fc371510864378354ddRob Landley  if (errno) infomsg(infomode, "config : Invalid num %s",str);
511415c960b22b4084057577fc371510864378354ddRob Landley  else if (endptr && (*endptr!='\0'||endptr == str))
512415c960b22b4084057577fc371510864378354ddRob Landley      infomsg(infomode, "config : Not a valid num %s",str);
513415c960b22b4084057577fc371510864378354ddRob Landley  else *((uint32_t*)(var)) = (uint32_t)ret_val;
514415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
515415c960b22b4084057577fc371510864378354ddRob Landley}
516415c960b22b4084057577fc371510864378354ddRob Landley
517415c960b22b4084057577fc371510864378354ddRob Landley// copy string STR in variable VAR
518415c960b22b4084057577fc371510864378354ddRob Landleystatic int strinvar(const char *str, void *var)
519415c960b22b4084057577fc371510864378354ddRob Landley{
520415c960b22b4084057577fc371510864378354ddRob Landley  char **dest = var;
521415c960b22b4084057577fc371510864378354ddRob Landley  if (*dest) free(*dest);
522415c960b22b4084057577fc371510864378354ddRob Landley  *dest = strdup(str);
523415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
524415c960b22b4084057577fc371510864378354ddRob Landley}
525415c960b22b4084057577fc371510864378354ddRob Landley
526415c960b22b4084057577fc371510864378354ddRob Landley// IP String STR to binary data.
527415c960b22b4084057577fc371510864378354ddRob Landleystatic int striptovar(const char *str, void *var)
528415c960b22b4084057577fc371510864378354ddRob Landley{
529415c960b22b4084057577fc371510864378354ddRob Landley  *((uint32_t*)(var)) = 0;
530415c960b22b4084057577fc371510864378354ddRob Landley  if(!str) {
531415c960b22b4084057577fc371510864378354ddRob Landley    error_msg("config : NULL address string \n");
532415c960b22b4084057577fc371510864378354ddRob Landley    return -1;
533415c960b22b4084057577fc371510864378354ddRob Landley  }
53460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if((inet_pton(AF_INET6, str, var)<=0) && (inet_pton(AF_INET, str, var)<=0)) {
53560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    error_msg("config : wrong address %s \n", str);
536415c960b22b4084057577fc371510864378354ddRob Landley    return -1;
537415c960b22b4084057577fc371510864378354ddRob Landley  }
538415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
539415c960b22b4084057577fc371510864378354ddRob Landley}
540415c960b22b4084057577fc371510864378354ddRob Landley
541415c960b22b4084057577fc371510864378354ddRob Landley// String to dhcp option conversion
542415c960b22b4084057577fc371510864378354ddRob Landleystatic int strtoopt(const char *str, void *var)
543415c960b22b4084057577fc371510864378354ddRob Landley{
544415c960b22b4084057577fc371510864378354ddRob Landley  char *option, *valstr, *grp, *tp;
545415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t optcode = 0, inf = infomode, convtmp, mask, nip, router;
546415c960b22b4084057577fc371510864378354ddRob Landley  uint16_t flag = 0;
547415c960b22b4084057577fc371510864378354ddRob Landley  int count, size = ARRAY_LEN(options_list);
548415c960b22b4084057577fc371510864378354ddRob Landley
549415c960b22b4084057577fc371510864378354ddRob Landley  if (!*str) return 0;
550415c960b22b4084057577fc371510864378354ddRob Landley  if (!(option = strtok((char*)str, " \t="))) return -1;
551415c960b22b4084057577fc371510864378354ddRob Landley
552415c960b22b4084057577fc371510864378354ddRob Landley  infomode = LOG_SILENT;
553415c960b22b4084057577fc371510864378354ddRob Landley  strtou32(option, (uint32_t*)&optcode);
554415c960b22b4084057577fc371510864378354ddRob Landley  infomode = inf;
555415c960b22b4084057577fc371510864378354ddRob Landley
556415c960b22b4084057577fc371510864378354ddRob Landley  if (optcode > 0 && optcode < 256) { // raw option
557415c960b22b4084057577fc371510864378354ddRob Landley    for (count = 0; count < size; count++) {
558415c960b22b4084057577fc371510864378354ddRob Landley      if ((options_list[count].code & 0X00FF) == optcode) {
559415c960b22b4084057577fc371510864378354ddRob Landley        flag = (options_list[count].code & 0XFF00);
560415c960b22b4084057577fc371510864378354ddRob Landley        break;
561415c960b22b4084057577fc371510864378354ddRob Landley      }
562415c960b22b4084057577fc371510864378354ddRob Landley    }
563415c960b22b4084057577fc371510864378354ddRob Landley  } else { //string option
564415c960b22b4084057577fc371510864378354ddRob Landley    for (count = 0; count < size; count++) {
565415c960b22b4084057577fc371510864378354ddRob Landley      if (!strncmp(options_list[count].key, option, strlen(options_list[count].key))) {
566415c960b22b4084057577fc371510864378354ddRob Landley        flag = (options_list[count].code & 0XFF00);
567415c960b22b4084057577fc371510864378354ddRob Landley        optcode = (options_list[count].code & 0X00FF);
568415c960b22b4084057577fc371510864378354ddRob Landley        break;
569415c960b22b4084057577fc371510864378354ddRob Landley      }
570415c960b22b4084057577fc371510864378354ddRob Landley    }
571415c960b22b4084057577fc371510864378354ddRob Landley  }
572415c960b22b4084057577fc371510864378354ddRob Landley  if (count == size) {
573415c960b22b4084057577fc371510864378354ddRob Landley    infomsg(inf, "config : Obsolete OR Unknown Option : %s", option);
574415c960b22b4084057577fc371510864378354ddRob Landley    return -1;
575415c960b22b4084057577fc371510864378354ddRob Landley  }
576415c960b22b4084057577fc371510864378354ddRob Landley
577415c960b22b4084057577fc371510864378354ddRob Landley  if (!flag || !optcode) return -1;
578415c960b22b4084057577fc371510864378354ddRob Landley
579415c960b22b4084057577fc371510864378354ddRob Landley  if (!(valstr = strtok(NULL, " \t"))) {
580415c960b22b4084057577fc371510864378354ddRob Landley    dbg("config : option %s has no value defined.\n", option);
581415c960b22b4084057577fc371510864378354ddRob Landley    return -1;
582415c960b22b4084057577fc371510864378354ddRob Landley  }
583415c960b22b4084057577fc371510864378354ddRob Landley  dbg(" value : %-20s : ", valstr);
584415c960b22b4084057577fc371510864378354ddRob Landley  switch (flag) {
585415c960b22b4084057577fc371510864378354ddRob Landley  case DHCP_NUM32:
586415c960b22b4084057577fc371510864378354ddRob Landley    options_list[count].len = sizeof(uint32_t);
587415c960b22b4084057577fc371510864378354ddRob Landley    options_list[count].val = xmalloc(sizeof(uint32_t));
588415c960b22b4084057577fc371510864378354ddRob Landley    strtou32(valstr, &convtmp);
589415c960b22b4084057577fc371510864378354ddRob Landley    memcpy(options_list[count].val, &convtmp, sizeof(uint32_t));
590415c960b22b4084057577fc371510864378354ddRob Landley    break;
591415c960b22b4084057577fc371510864378354ddRob Landley  case DHCP_NUM16:
592415c960b22b4084057577fc371510864378354ddRob Landley    options_list[count].len = sizeof(uint16_t);
593415c960b22b4084057577fc371510864378354ddRob Landley    options_list[count].val = xmalloc(sizeof(uint16_t));
594415c960b22b4084057577fc371510864378354ddRob Landley    strtou32(valstr, &convtmp);
595415c960b22b4084057577fc371510864378354ddRob Landley    memcpy(options_list[count].val, &convtmp, sizeof(uint16_t));
596415c960b22b4084057577fc371510864378354ddRob Landley    break;
597415c960b22b4084057577fc371510864378354ddRob Landley  case DHCP_NUM8:
598415c960b22b4084057577fc371510864378354ddRob Landley    options_list[count].len = sizeof(uint8_t);
599415c960b22b4084057577fc371510864378354ddRob Landley    options_list[count].val = xmalloc(sizeof(uint8_t));
600415c960b22b4084057577fc371510864378354ddRob Landley    strtou32(valstr, &convtmp);
601415c960b22b4084057577fc371510864378354ddRob Landley    memcpy(options_list[count].val, &convtmp, sizeof(uint8_t));
602415c960b22b4084057577fc371510864378354ddRob Landley    break;
603415c960b22b4084057577fc371510864378354ddRob Landley  case DHCP_IP:
604415c960b22b4084057577fc371510864378354ddRob Landley    options_list[count].len = sizeof(uint32_t);
605415c960b22b4084057577fc371510864378354ddRob Landley    options_list[count].val = xmalloc(sizeof(uint32_t));
606415c960b22b4084057577fc371510864378354ddRob Landley    striptovar(valstr, options_list[count].val);
607415c960b22b4084057577fc371510864378354ddRob Landley    break;
608415c960b22b4084057577fc371510864378354ddRob Landley  case DHCP_STRING:
609415c960b22b4084057577fc371510864378354ddRob Landley    options_list[count].len = strlen(valstr);
610415c960b22b4084057577fc371510864378354ddRob Landley    options_list[count].val = strdup(valstr);
611415c960b22b4084057577fc371510864378354ddRob Landley    break;
612415c960b22b4084057577fc371510864378354ddRob Landley  case DHCP_IPLIST:
613415c960b22b4084057577fc371510864378354ddRob Landley    while(valstr){
614415c960b22b4084057577fc371510864378354ddRob Landley      options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + sizeof(uint32_t));
615415c960b22b4084057577fc371510864378354ddRob Landley      striptovar(valstr, ((uint8_t*)options_list[count].val)+options_list[count].len);
616415c960b22b4084057577fc371510864378354ddRob Landley      options_list[count].len += sizeof(uint32_t);
617415c960b22b4084057577fc371510864378354ddRob Landley      valstr = strtok(NULL," \t");
618415c960b22b4084057577fc371510864378354ddRob Landley    }
619415c960b22b4084057577fc371510864378354ddRob Landley    break;
620415c960b22b4084057577fc371510864378354ddRob Landley  case DHCP_IPPLST:
621415c960b22b4084057577fc371510864378354ddRob Landley    break;
622415c960b22b4084057577fc371510864378354ddRob Landley  case DHCP_STCRTS:
623415c960b22b4084057577fc371510864378354ddRob Landley    /* Option binary format:
624415c960b22b4084057577fc371510864378354ddRob Landley     * mask [one byte, 0..32]
625415c960b22b4084057577fc371510864378354ddRob Landley     * ip [0..4 bytes depending on mask]
626415c960b22b4084057577fc371510864378354ddRob Landley     * router [4 bytes]
627415c960b22b4084057577fc371510864378354ddRob Landley     * may be repeated
628415c960b22b4084057577fc371510864378354ddRob Landley     * staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
629415c960b22b4084057577fc371510864378354ddRob Landley     */
630415c960b22b4084057577fc371510864378354ddRob Landley    grp = strtok(valstr, ",");;
631415c960b22b4084057577fc371510864378354ddRob Landley    while(grp){
632415c960b22b4084057577fc371510864378354ddRob Landley      while(*grp == ' ' || *grp == '\t') grp++;
633415c960b22b4084057577fc371510864378354ddRob Landley      tp = strchr(grp, '/');
634415c960b22b4084057577fc371510864378354ddRob Landley      if (!tp) error_exit("wrong formated static route option");
635415c960b22b4084057577fc371510864378354ddRob Landley      *tp = '\0';
636415c960b22b4084057577fc371510864378354ddRob Landley      mask = strtol(++tp, &tp, 10);
637415c960b22b4084057577fc371510864378354ddRob Landley      if (striptovar(grp, (uint8_t*)&nip)<0) error_exit("wrong formated static route option");
638415c960b22b4084057577fc371510864378354ddRob Landley      while(*tp == ' ' || *tp == '\t' || *tp == '-') tp++;
639415c960b22b4084057577fc371510864378354ddRob Landley      if (striptovar(tp, (uint8_t*)&router)<0) error_exit("wrong formated static route option");
640415c960b22b4084057577fc371510864378354ddRob Landley      options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + 1 + mask/8 + 4);
641415c960b22b4084057577fc371510864378354ddRob Landley      memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &mask, 1);
642415c960b22b4084057577fc371510864378354ddRob Landley      options_list[count].len += 1;
643415c960b22b4084057577fc371510864378354ddRob Landley      memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &nip, mask/8);
644415c960b22b4084057577fc371510864378354ddRob Landley      options_list[count].len += mask/8;
645415c960b22b4084057577fc371510864378354ddRob Landley      memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &router, 4);
646415c960b22b4084057577fc371510864378354ddRob Landley      options_list[count].len += 4;
647415c960b22b4084057577fc371510864378354ddRob Landley      tp = NULL;
648415c960b22b4084057577fc371510864378354ddRob Landley      grp = strtok(NULL, ",");
649415c960b22b4084057577fc371510864378354ddRob Landley    }
650415c960b22b4084057577fc371510864378354ddRob Landley    break;
651415c960b22b4084057577fc371510864378354ddRob Landley  }
652415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
653415c960b22b4084057577fc371510864378354ddRob Landley}
654415c960b22b4084057577fc371510864378354ddRob Landley
655415c960b22b4084057577fc371510864378354ddRob Landley// Reads Static leases from STR and updates inner structures.
656415c960b22b4084057577fc371510864378354ddRob Landleystatic int get_staticlease(const char *str, void *var)
657415c960b22b4084057577fc371510864378354ddRob Landley{
658415c960b22b4084057577fc371510864378354ddRob Landley  struct static_lease_s *sltmp;
659415c960b22b4084057577fc371510864378354ddRob Landley  char *tkmac, *tkip;
660415c960b22b4084057577fc371510864378354ddRob Landley  int count;
661415c960b22b4084057577fc371510864378354ddRob Landley
662415c960b22b4084057577fc371510864378354ddRob Landley  if (!*str) return 0;
663415c960b22b4084057577fc371510864378354ddRob Landley
664415c960b22b4084057577fc371510864378354ddRob Landley  if (!(tkmac = strtok((char*)str, " \t"))) {
665415c960b22b4084057577fc371510864378354ddRob Landley    infomsg(infomode, "config : static lease : mac not found");
666415c960b22b4084057577fc371510864378354ddRob Landley    return 0;
667415c960b22b4084057577fc371510864378354ddRob Landley  }
668415c960b22b4084057577fc371510864378354ddRob Landley  if (!(tkip = strtok(NULL, " \t"))) {
669415c960b22b4084057577fc371510864378354ddRob Landley    infomsg(infomode, "config : static lease : no ip bind to mac %s", tkmac);
670415c960b22b4084057577fc371510864378354ddRob Landley    return 0;
671415c960b22b4084057577fc371510864378354ddRob Landley  }
672415c960b22b4084057577fc371510864378354ddRob Landley  sltmp = xzalloc(sizeof(struct static_lease_s));
673415c960b22b4084057577fc371510864378354ddRob Landley  for (count = 0; count < 6; count++, tkmac++) {
674415c960b22b4084057577fc371510864378354ddRob Landley    errno = 0;
675415c960b22b4084057577fc371510864378354ddRob Landley    sltmp->mac[count] = strtol(tkmac, &tkmac, 16);
676415c960b22b4084057577fc371510864378354ddRob Landley    if (sltmp->mac[count]>255 || sltmp->mac[count]<0 || (*tkmac && *tkmac!=':') || errno) {
677415c960b22b4084057577fc371510864378354ddRob Landley      infomsg(infomode, "config : static lease : mac address wrong format");
678415c960b22b4084057577fc371510864378354ddRob Landley      free(sltmp);
679415c960b22b4084057577fc371510864378354ddRob Landley      return 0;
680415c960b22b4084057577fc371510864378354ddRob Landley    }
681415c960b22b4084057577fc371510864378354ddRob Landley  }
682415c960b22b4084057577fc371510864378354ddRob Landley  striptovar(tkip, &sltmp->nip);
68360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  sltmp->next = gstate.leases.sleases;
68460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.leases.sleases = sltmp;
685415c960b22b4084057577fc371510864378354ddRob Landley
686415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
687415c960b22b4084057577fc371510864378354ddRob Landley}
688415c960b22b4084057577fc371510864378354ddRob Landley
689415c960b22b4084057577fc371510864378354ddRob Landleystatic struct config_keyword keywords[] = {
69060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh// keyword          handler           variable address                default
691415c960b22b4084057577fc371510864378354ddRob Landley  {"start"        , striptovar      , (void*)&gconfig.start_ip     , "192.168.0.20"},
692415c960b22b4084057577fc371510864378354ddRob Landley  {"end"          , striptovar      , (void*)&gconfig.end_ip       , "192.168.0.254"},
693415c960b22b4084057577fc371510864378354ddRob Landley  {"interface"    , strinvar        , (void*)&gconfig.interface    , "eth0"},
694415c960b22b4084057577fc371510864378354ddRob Landley  {"port"         , strtou32        , (void*)&gconfig.port         , "67"},
695415c960b22b4084057577fc371510864378354ddRob Landley  {"min_lease"    , strtou32        , (void*)&gconfig.min_lease_sec, "60"},
696415c960b22b4084057577fc371510864378354ddRob Landley  {"max_leases"   , strtou32        , (void*)&gconfig.max_leases   , "235"},
697415c960b22b4084057577fc371510864378354ddRob Landley  {"auto_time"    , strtou32        , (void*)&gconfig.auto_time    , "7200"},
698415c960b22b4084057577fc371510864378354ddRob Landley  {"decline_time" , strtou32        , (void*)&gconfig.decline_time , "3600"},
699415c960b22b4084057577fc371510864378354ddRob Landley  {"conflict_time", strtou32        , (void*)&gconfig.conflict_time, "3600"},
700415c960b22b4084057577fc371510864378354ddRob Landley  {"offer_time"   , strtou32        , (void*)&gconfig.offer_time   , "60"},
701415c960b22b4084057577fc371510864378354ddRob Landley  {"lease_file"   , strinvar        , (void*)&gconfig.lease_file   , "/var/lib/misc/dhcpd.leases"}, //LEASES_FILE
70260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  {"lease6_file"  , strinvar        , (void*)&gconfig.lease6_file  , "/var/lib/misc/dhcpd6.leases"}, //LEASES_FILE
703415c960b22b4084057577fc371510864378354ddRob Landley  {"pidfile"      , strinvar        , (void*)&gconfig.pidfile      , "/var/run/dhcpd.pid"}, //DPID_FILE
704415c960b22b4084057577fc371510864378354ddRob Landley  {"siaddr"       , striptovar      , (void*)&gconfig.siaddr_nip   , "0.0.0.0"},
705415c960b22b4084057577fc371510864378354ddRob Landley  {"option"       , strtoopt        , (void*)&gconfig.options      , ""},
706415c960b22b4084057577fc371510864378354ddRob Landley  {"opt"          , strtoopt        , (void*)&gconfig.options      , ""},
707415c960b22b4084057577fc371510864378354ddRob Landley  {"notify_file"  , strinvar        , (void*)&gconfig.notify_file  , ""},
708415c960b22b4084057577fc371510864378354ddRob Landley  {"sname"        , strinvar        , (void*)&gconfig.sname        , ""},
709415c960b22b4084057577fc371510864378354ddRob Landley  {"boot_file"    , strinvar        , (void*)&gconfig.boot_file    , ""},
710415c960b22b4084057577fc371510864378354ddRob Landley  {"static_lease" , get_staticlease , (void*)&gconfig.static_leases, ""},
71160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  {"start6"       , striptovar      , (void*)&gconfig.start_ip6    , "2001:620:40b:555::100"},
71260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  {"end6"         , striptovar      , (void*)&gconfig.end_ip6      , "2001:620:40b:555::200"},
71360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  {"preferred_lifetime" , strtou32  , (void*)&gconfig.pref_lifetime, "3600"},
71460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  {"valid_lifetime"     , strtou32  , (void*)&gconfig.valid_lifetime, "7200"},
71560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  {"t1"           , strtou32        , (void*)&gconfig.t1           , "3600"},
71660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  {"t2"           , strtou32        , (void*)&gconfig.t2           , "5400"},
717415c960b22b4084057577fc371510864378354ddRob Landley};
718415c960b22b4084057577fc371510864378354ddRob Landley
719415c960b22b4084057577fc371510864378354ddRob Landley// Parses the server config file and updates the global server config accordingly.
720415c960b22b4084057577fc371510864378354ddRob Landleystatic int parse_server_config(char *config_file, struct config_keyword *confkey)
721415c960b22b4084057577fc371510864378354ddRob Landley{
722415c960b22b4084057577fc371510864378354ddRob Landley  FILE *fs = NULL;
723415c960b22b4084057577fc371510864378354ddRob Landley  char *confline_temp = NULL,*confline = NULL, *tk = NULL, *tokens[2] = {NULL, NULL};
724415c960b22b4084057577fc371510864378354ddRob Landley  int len, linelen, tcount, count, size = ARRAY_LEN(keywords);
725415c960b22b4084057577fc371510864378354ddRob Landley
726415c960b22b4084057577fc371510864378354ddRob Landley  for (count = 0; count < size; count++)
72760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if (confkey[count].handler)
72860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      confkey[count].handler(confkey[count].def, confkey[count].var);
729415c960b22b4084057577fc371510864378354ddRob Landley
730415c960b22b4084057577fc371510864378354ddRob Landley  if (!(fs = fopen(config_file, "r"))) perror_msg("%s", config_file);
731415c960b22b4084057577fc371510864378354ddRob Landley  for (len = 0, linelen = 0; fs;) {
732415c960b22b4084057577fc371510864378354ddRob Landley    len = getline(&confline_temp, (size_t*) &linelen, fs);
733415c960b22b4084057577fc371510864378354ddRob Landley    confline = confline_temp;
734415c960b22b4084057577fc371510864378354ddRob Landley    if (len <= 0) break;
735415c960b22b4084057577fc371510864378354ddRob Landley    for (; *confline == ' '; confline++, len--);
736415c960b22b4084057577fc371510864378354ddRob Landley    if ((confline[0] == '#') || (confline[0] == '\n')) goto free_conf_continue;
737415c960b22b4084057577fc371510864378354ddRob Landley    tk = strchr(confline, '#');
738415c960b22b4084057577fc371510864378354ddRob Landley    if (tk) {
739415c960b22b4084057577fc371510864378354ddRob Landley      for (; *(tk-1)==' ' || *(tk-1)=='\t'; tk--);
740415c960b22b4084057577fc371510864378354ddRob Landley      *tk = '\0';
741415c960b22b4084057577fc371510864378354ddRob Landley    }
742415c960b22b4084057577fc371510864378354ddRob Landley    tk = strchr(confline, '\n');
743415c960b22b4084057577fc371510864378354ddRob Landley    if (tk) {
744415c960b22b4084057577fc371510864378354ddRob Landley      for (; *(tk-1)==' ' || *(tk-1)=='\t'; tk--);
745415c960b22b4084057577fc371510864378354ddRob Landley      *tk = '\0';
746415c960b22b4084057577fc371510864378354ddRob Landley    }
747415c960b22b4084057577fc371510864378354ddRob Landley    for (tcount=0, tk=strtok(confline, " \t"); tk && (tcount < 2);
748415c960b22b4084057577fc371510864378354ddRob Landley        tcount++, tk=strtok(NULL,(tcount==1)?"":" \t")) {
749415c960b22b4084057577fc371510864378354ddRob Landley      while ((*tk == '\t') || (*tk == ' ')) tk++;
750415c960b22b4084057577fc371510864378354ddRob Landley      tokens[tcount] = xstrdup(tk);
751415c960b22b4084057577fc371510864378354ddRob Landley    }
752415c960b22b4084057577fc371510864378354ddRob Landley    if (tcount<=1) goto free_tk0_continue;
753415c960b22b4084057577fc371510864378354ddRob Landley    for (count = 0; count < size; count++) {
754415c960b22b4084057577fc371510864378354ddRob Landley      if (!strcmp(confkey[count].keyword,tokens[0])) {
755415c960b22b4084057577fc371510864378354ddRob Landley        dbg("got config : %15s : ", confkey[count].keyword);
756415c960b22b4084057577fc371510864378354ddRob Landley        if (confkey[count].handler(tokens[1], confkey[count].var) == 0)
757415c960b22b4084057577fc371510864378354ddRob Landley          dbg("%s \n", tokens[1]);
758415c960b22b4084057577fc371510864378354ddRob Landley        break;
759415c960b22b4084057577fc371510864378354ddRob Landley      }
760415c960b22b4084057577fc371510864378354ddRob Landley    }
761415c960b22b4084057577fc371510864378354ddRob Landley    if (tokens[1]) { free(tokens[1]); tokens[1] = NULL; }
762415c960b22b4084057577fc371510864378354ddRob Landleyfree_tk0_continue:
763415c960b22b4084057577fc371510864378354ddRob Landley    if (tokens[0]) { free(tokens[0]); tokens[0] = NULL; }
764415c960b22b4084057577fc371510864378354ddRob Landleyfree_conf_continue:
765415c960b22b4084057577fc371510864378354ddRob Landley    free(confline_temp);
766415c960b22b4084057577fc371510864378354ddRob Landley    confline_temp = NULL;
767415c960b22b4084057577fc371510864378354ddRob Landley  }
768415c960b22b4084057577fc371510864378354ddRob Landley  if (fs) fclose(fs);
769415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
770415c960b22b4084057577fc371510864378354ddRob Landley}
771415c960b22b4084057577fc371510864378354ddRob Landley
77260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh// opens UDP socket for listen ipv6 packets
77360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic int open_listensock6(void)
77460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
77560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct sockaddr_in6 addr6;
77660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct ipv6_mreq mreq;
77760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
77860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (gstate.listensock > 0) close(gstate.listensock);
77960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
78060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dbg("Opening listen socket on *:%d %s\n", gconfig.port, gconfig.interface);
78160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
78260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.listensock = xsocket(PF_INET6, SOCK_DGRAM, 0);
78360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  setsockopt(gstate.listensock, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
784c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_CHECKSUM, &constone, sizeof(constone));
78560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
78660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &constone,
78760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        sizeof(constone)) == -1) {
78860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    error_msg("failed to receive ipv6 packets.\n");
78960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    close(gstate.listensock);
79060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    return -1;
79160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
79260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
79360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  setsockopt(gstate.listensock, SOL_SOCKET, SO_BINDTODEVICE, gconfig.interface, strlen(gconfig.interface)+1);
79460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
79560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memset(&addr6, 0, sizeof(addr6));
79660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  addr6.sin6_family = AF_INET6;
797c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  addr6.sin6_port = htons(gconfig.port); //SERVER_PORT
79860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  addr6.sin6_scope_id = if_nametoindex(gconfig.interface);
79960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  //Listening for multicast packet
80060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  inet_pton(AF_INET6, "ff02::1:2", &addr6.sin6_addr);
80160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
80260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (bind(gstate.listensock, (struct sockaddr *) &addr6, sizeof(addr6)) == -1) {
80360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    close(gstate.listensock);
80460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    perror_exit("bind failed");
80560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
80660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
80760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memset(&mreq, 0, sizeof(mreq));
80860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  mreq.ipv6mr_interface = if_nametoindex(gconfig.interface);
80960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(&mreq.ipv6mr_multiaddr, &addr6.sin6_addr, sizeof(addr6.sin6_addr));
81060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
81160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if(setsockopt(gstate.listensock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1) {
81260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    error_msg("failed to join a multicast group.\n");
81360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    close(gstate.listensock);
81460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    return -1;
81560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
81660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
81760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dbg("OPEN : success\n");
81860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  return 0;
81960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
82060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
821415c960b22b4084057577fc371510864378354ddRob Landley// opens UDP socket for listen
822415c960b22b4084057577fc371510864378354ddRob Landleystatic int open_listensock(void)
823415c960b22b4084057577fc371510864378354ddRob Landley{
824415c960b22b4084057577fc371510864378354ddRob Landley  struct sockaddr_in addr;
825415c960b22b4084057577fc371510864378354ddRob Landley  struct ifreq ifr;
826415c960b22b4084057577fc371510864378354ddRob Landley
827415c960b22b4084057577fc371510864378354ddRob Landley  if (gstate.listensock > 0) close(gstate.listensock);
828415c960b22b4084057577fc371510864378354ddRob Landley
829415c960b22b4084057577fc371510864378354ddRob Landley  dbg("Opening listen socket on *:%d %s\n", gconfig.port, gconfig.interface);
830415c960b22b4084057577fc371510864378354ddRob Landley  gstate.listensock = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
831415c960b22b4084057577fc371510864378354ddRob Landley  setsockopt(gstate.listensock, SOL_SOCKET, SO_REUSEADDR, &constone, sizeof(constone));
832415c960b22b4084057577fc371510864378354ddRob Landley  if (setsockopt(gstate.listensock, SOL_SOCKET, SO_BROADCAST, &constone, sizeof(constone)) == -1) {
83360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    error_msg("failed to receive brodcast packets.\n");
83460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    close(gstate.listensock);
83560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    return -1;
836415c960b22b4084057577fc371510864378354ddRob Landley  }
837415c960b22b4084057577fc371510864378354ddRob Landley  memset(&ifr, 0, sizeof(ifr));
83882effc97f9f2d1c258ea50cb11b130753b8ba805Rob Landley  xstrncpy(ifr.ifr_name, gconfig.interface, IFNAMSIZ);
839415c960b22b4084057577fc371510864378354ddRob Landley  setsockopt(gstate.listensock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
840415c960b22b4084057577fc371510864378354ddRob Landley
841415c960b22b4084057577fc371510864378354ddRob Landley  memset(&addr, 0, sizeof(addr));
842415c960b22b4084057577fc371510864378354ddRob Landley  addr.sin_family = AF_INET;
843c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  addr.sin_port = htons(gconfig.port); //SERVER_PORT
844415c960b22b4084057577fc371510864378354ddRob Landley  addr.sin_addr.s_addr = INADDR_ANY ;
845415c960b22b4084057577fc371510864378354ddRob Landley
846415c960b22b4084057577fc371510864378354ddRob Landley  if (bind(gstate.listensock, (struct sockaddr *) &addr, sizeof(addr))) {
847415c960b22b4084057577fc371510864378354ddRob Landley    close(gstate.listensock);
848415c960b22b4084057577fc371510864378354ddRob Landley    perror_exit("bind failed");
849415c960b22b4084057577fc371510864378354ddRob Landley  }
850415c960b22b4084057577fc371510864378354ddRob Landley  dbg("OPEN : success\n");
851415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
852415c960b22b4084057577fc371510864378354ddRob Landley}
853415c960b22b4084057577fc371510864378354ddRob Landley
85460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic int send_packet6(uint8_t relay, uint8_t *client_lla, uint16_t optlen)
85560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
85660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct sockaddr_ll dest_sll;
85760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dhcp6_raw_t packet;
85860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  unsigned padding;
85960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  int fd, result = -1;
86060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
86160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memset(&packet, 0, sizeof(dhcp6_raw_t));
86260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(&packet.dhcp6, &gstate.send.send_pkt6, sizeof(dhcp6_msg_t));
86360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  padding = sizeof(packet.dhcp6.options) - optlen;
86460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
86560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6))) < 0) {
86660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    dbg("SEND : ipv6 socket failed\n");
86760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    return -1;
86860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
86960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memset(&dest_sll, 0, sizeof(dest_sll));
87060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dest_sll.sll_family = AF_PACKET;
87160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dest_sll.sll_protocol = htons(ETH_P_IPV6);
87260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dest_sll.sll_ifindex = gconfig.ifindex;
87360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dest_sll.sll_halen = ETH_ALEN;
874c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  memcpy(dest_sll.sll_addr, client_lla, sizeof(uint8_t)*6);
87560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
87660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
87760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    dbg("SEND : bind failed\n");
87860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    close(fd);
87960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    return -1;
88060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
88160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(&packet.iph.ip6_src, &gconfig.server_nip6, sizeof(uint32_t)*4);
882c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  memcpy(&packet.iph.ip6_dst, &gstate.client_nip6, sizeof(uint32_t)*4);
883c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh
884c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  packet.udph.source = htons(gconfig.port); //SERVER_PORT
885c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  packet.udph.dest = gstate.client_port; //CLIENT_PORT
88660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  packet.udph.len = htons(sizeof(dhcp6_raw_t) - sizeof(struct ip6_hdr) - padding);
88760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  packet.iph.ip6_ctlun.ip6_un1.ip6_un1_plen = htons(ntohs(packet.udph.len) + 0x11);
88860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp6_raw_t) - padding);
88960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  packet.iph.ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(0x60000000);
89060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  packet.iph.ip6_ctlun.ip6_un1.ip6_un1_plen = packet.udph.len;
89160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  packet.iph.ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP;
89260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  packet.iph.ip6_ctlun.ip6_un1.ip6_un1_hlim = 0x64;
89360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
89460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  result = sendto(fd, &packet, sizeof(dhcp6_raw_t)-padding,
89560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      0, (struct sockaddr *) &dest_sll, sizeof(dest_sll));
89660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
89760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dbg("sendto %d\n", result);
89860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  close(fd);
89960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (result < 0) dbg("PACKET send error\n");
90060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  return result;
90160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
90260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
903415c960b22b4084057577fc371510864378354ddRob Landley// Sends data through raw socket.
904415c960b22b4084057577fc371510864378354ddRob Landleystatic int send_packet(uint8_t broadcast)
905415c960b22b4084057577fc371510864378354ddRob Landley{
906415c960b22b4084057577fc371510864378354ddRob Landley  struct sockaddr_ll dest_sll;
907415c960b22b4084057577fc371510864378354ddRob Landley  dhcp_raw_t packet;
908415c960b22b4084057577fc371510864378354ddRob Landley  unsigned padding;
909415c960b22b4084057577fc371510864378354ddRob Landley  int fd, result = -1;
910415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
911415c960b22b4084057577fc371510864378354ddRob Landley
912415c960b22b4084057577fc371510864378354ddRob Landley  memset(&packet, 0, sizeof(dhcp_raw_t));
91360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(&packet.dhcp, &gstate.send.send_pkt, sizeof(dhcp_msg_t));
914415c960b22b4084057577fc371510864378354ddRob Landley
915415c960b22b4084057577fc371510864378354ddRob Landley  if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
916415c960b22b4084057577fc371510864378354ddRob Landley    dbg("SEND : socket failed\n");
917415c960b22b4084057577fc371510864378354ddRob Landley    return -1;
918415c960b22b4084057577fc371510864378354ddRob Landley  }
919415c960b22b4084057577fc371510864378354ddRob Landley  memset(&dest_sll, 0, sizeof(dest_sll));
920415c960b22b4084057577fc371510864378354ddRob Landley  dest_sll.sll_family = AF_PACKET;
921415c960b22b4084057577fc371510864378354ddRob Landley  dest_sll.sll_protocol = htons(ETH_P_IP);
922415c960b22b4084057577fc371510864378354ddRob Landley  dest_sll.sll_ifindex = gconfig.ifindex;
923415c960b22b4084057577fc371510864378354ddRob Landley  dest_sll.sll_halen = 6;
92460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(dest_sll.sll_addr, (broadcast)?bmacaddr:gstate.rcvd.rcvd_pkt.chaddr , 6);
925415c960b22b4084057577fc371510864378354ddRob Landley
926415c960b22b4084057577fc371510864378354ddRob Landley  if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
927415c960b22b4084057577fc371510864378354ddRob Landley    dbg("SEND : bind failed\n");
928415c960b22b4084057577fc371510864378354ddRob Landley    close(fd);
929415c960b22b4084057577fc371510864378354ddRob Landley    return -1;
930415c960b22b4084057577fc371510864378354ddRob Landley  }
93160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  padding = 308 - 1 - dhcp_opt_size(gstate.send.send_pkt.options);
932415c960b22b4084057577fc371510864378354ddRob Landley  packet.iph.protocol = IPPROTO_UDP;
933415c960b22b4084057577fc371510864378354ddRob Landley  packet.iph.saddr = gconfig.server_nip;
934c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  packet.iph.daddr = (broadcast || (gstate.rcvd.rcvd_pkt.ciaddr == 0))?
935c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    INADDR_BROADCAST : gstate.rcvd.rcvd_pkt.ciaddr;
936c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  packet.udph.source = htons(gconfig.port);//SERVER_PORT
937c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  packet.udph.dest = gstate.client_port; //CLIENT_PORT
938415c960b22b4084057577fc371510864378354ddRob Landley  packet.udph.len = htons(sizeof(dhcp_raw_t) - sizeof(struct iphdr) - padding);
939415c960b22b4084057577fc371510864378354ddRob Landley  packet.iph.tot_len = packet.udph.len;
940415c960b22b4084057577fc371510864378354ddRob Landley  packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp_raw_t) - padding);
941415c960b22b4084057577fc371510864378354ddRob Landley  packet.iph.tot_len = htons(sizeof(dhcp_raw_t) - padding);
942415c960b22b4084057577fc371510864378354ddRob Landley  packet.iph.ihl = sizeof(packet.iph) >> 2;
943415c960b22b4084057577fc371510864378354ddRob Landley  packet.iph.version = IPVERSION;
944415c960b22b4084057577fc371510864378354ddRob Landley  packet.iph.ttl = IPDEFTTL;
945415c960b22b4084057577fc371510864378354ddRob Landley  packet.iph.check = dhcp_checksum(&packet.iph, sizeof(packet.iph));
946415c960b22b4084057577fc371510864378354ddRob Landley
947415c960b22b4084057577fc371510864378354ddRob Landley  result = sendto(fd, &packet, sizeof(dhcp_raw_t) - padding, 0,
948415c960b22b4084057577fc371510864378354ddRob Landley      (struct sockaddr *) &dest_sll, sizeof(dest_sll));
949415c960b22b4084057577fc371510864378354ddRob Landley
950415c960b22b4084057577fc371510864378354ddRob Landley  dbg("sendto %d\n", result);
951415c960b22b4084057577fc371510864378354ddRob Landley  close(fd);
952415c960b22b4084057577fc371510864378354ddRob Landley  if (result < 0) dbg("PACKET send error\n");
953415c960b22b4084057577fc371510864378354ddRob Landley  return result;
954415c960b22b4084057577fc371510864378354ddRob Landley}
955415c960b22b4084057577fc371510864378354ddRob Landley
95660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic int read_packet6(void)
95760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
95860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  int ret;
959c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  struct sockaddr_in6 c_addr;
960c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  socklen_t c_addr_size = sizeof(c_addr);
96160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
96260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memset(&gstate.rcvd.rcvd_pkt6, 0, sizeof(dhcp6_msg_t));
963c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  ret = recvfrom(gstate.listensock, &gstate.rcvd.rcvd_pkt6, sizeof(dhcp6_msg_t),
964c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh      0, (struct sockaddr*) &c_addr, &c_addr_size);
965c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  memcpy(gstate.client_nip6, &c_addr.sin6_addr, sizeof(uint32_t)*4);
966c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  memcpy(&gstate.client_port, &c_addr.sin6_port, sizeof(uint32_t));
96760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (ret < 0) {
96860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    dbg("Packet read error, ignoring. \n");
96960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    return ret; // returns -1
97060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
97160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (gstate.rcvd.rcvd_pkt6.msgtype < 1) {
97260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    dbg("Bad message type, igroning. \n");
97360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    return -2;
97460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
97560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
97660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dbg("Received an ipv6 packet. Size : %d \n", ret);
97760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  return ret;
97860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
97960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
980415c960b22b4084057577fc371510864378354ddRob Landley// Reads from UDP socket
981415c960b22b4084057577fc371510864378354ddRob Landleystatic int read_packet(void)
982415c960b22b4084057577fc371510864378354ddRob Landley{
983415c960b22b4084057577fc371510864378354ddRob Landley  int ret;
984c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  struct sockaddr_in c_addr;
985c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  socklen_t c_addr_size = sizeof(c_addr);
986415c960b22b4084057577fc371510864378354ddRob Landley
98760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memset(&gstate.rcvd.rcvd_pkt, 0, sizeof(dhcp_msg_t));
988c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  ret = recvfrom(gstate.listensock, &gstate.rcvd.rcvd_pkt, sizeof(dhcp_msg_t),
989c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh      0, (struct sockaddr*) &c_addr, &c_addr_size);
990c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  memcpy(&gstate.client_port, &c_addr.sin_port, sizeof(uint32_t));
991c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  /*ret = read(gstate.listensock, &gstate.rcvd.rcvd_pkt, sizeof(dhcp_msg_t));*/
992415c960b22b4084057577fc371510864378354ddRob Landley  if (ret < 0) {
993415c960b22b4084057577fc371510864378354ddRob Landley    dbg("Packet read error, ignoring. \n");
994415c960b22b4084057577fc371510864378354ddRob Landley    return ret; // returns -1
995415c960b22b4084057577fc371510864378354ddRob Landley  }
99660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (gstate.rcvd.rcvd_pkt.cookie != htonl(DHCP_MAGIC)) {
997415c960b22b4084057577fc371510864378354ddRob Landley    dbg("Packet with bad magic, ignoring. \n");
998415c960b22b4084057577fc371510864378354ddRob Landley    return -2;
999415c960b22b4084057577fc371510864378354ddRob Landley  }
100060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (gstate.rcvd.rcvd_pkt.op != 1) { //BOOTPREQUEST
1001415c960b22b4084057577fc371510864378354ddRob Landley    dbg("Not a BOOT REQUEST ignoring. \n");
1002415c960b22b4084057577fc371510864378354ddRob Landley    return -2;
1003415c960b22b4084057577fc371510864378354ddRob Landley  }
100460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (gstate.rcvd.rcvd_pkt.hlen != 6) {
1005415c960b22b4084057577fc371510864378354ddRob Landley    dbg("hlen != 6 ignoring. \n");
1006415c960b22b4084057577fc371510864378354ddRob Landley    return -2;
1007415c960b22b4084057577fc371510864378354ddRob Landley  }
1008415c960b22b4084057577fc371510864378354ddRob Landley  dbg("Received a packet. Size : %d \n", ret);
1009415c960b22b4084057577fc371510864378354ddRob Landley  return ret;
1010415c960b22b4084057577fc371510864378354ddRob Landley}
1011415c960b22b4084057577fc371510864378354ddRob Landley
1012415c960b22b4084057577fc371510864378354ddRob Landley// Preapres a dhcp packet with defaults and configs
1013415c960b22b4084057577fc371510864378354ddRob Landleystatic uint8_t* prepare_send_pkt(void)
1014415c960b22b4084057577fc371510864378354ddRob Landley{
101560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memset((void*)&gstate.send.send_pkt, 0, sizeof(gstate.send.send_pkt));
101660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.send.send_pkt.op = 2; //BOOTPREPLY
101760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.send.send_pkt.htype = 1;
101860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.send.send_pkt.hlen = 6;
101960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.send.send_pkt.xid = gstate.rcvd.rcvd_pkt.xid;
102060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.send.send_pkt.cookie = htonl(DHCP_MAGIC);
102160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.send.send_pkt.nsiaddr = gconfig.server_nip;
102260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(gstate.send.send_pkt.chaddr, gstate.rcvd.rcvd_pkt.chaddr, 16);
102360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.send.send_pkt.options[0] = DHCP_OPT_END;
102460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  return gstate.send.send_pkt.options;
102560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
102660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
102760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic uint8_t* prepare_send_pkt6(uint16_t opt)
102860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
102960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memset((void*)&gstate.send.send_pkt6, 0, sizeof(gstate.send.send_pkt6));
103060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.send.send_pkt6.msgtype = opt;
103160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(gstate.send.send_pkt6.transaction_id, gstate.rcvd.rcvd_pkt6.transaction_id, 3);
103260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  return gstate.send.send_pkt6.options;
1033415c960b22b4084057577fc371510864378354ddRob Landley}
1034415c960b22b4084057577fc371510864378354ddRob Landley
1035415c960b22b4084057577fc371510864378354ddRob Landley// Sets a option value in dhcp packet's option field
1036415c960b22b4084057577fc371510864378354ddRob Landleystatic uint8_t* set_optval(uint8_t *optptr, uint16_t opt, void *var, size_t len)
1037415c960b22b4084057577fc371510864378354ddRob Landley{
1038415c960b22b4084057577fc371510864378354ddRob Landley  while (*optptr != DHCP_OPT_END) optptr++;
1039415c960b22b4084057577fc371510864378354ddRob Landley  *optptr++ = (uint8_t)(opt & 0x00FF);
1040415c960b22b4084057577fc371510864378354ddRob Landley  *optptr++ = (uint8_t) len;
1041415c960b22b4084057577fc371510864378354ddRob Landley  memcpy(optptr, var, len);
1042415c960b22b4084057577fc371510864378354ddRob Landley  optptr += len;
1043415c960b22b4084057577fc371510864378354ddRob Landley  *optptr = DHCP_OPT_END;
1044415c960b22b4084057577fc371510864378354ddRob Landley  return optptr;
1045415c960b22b4084057577fc371510864378354ddRob Landley}
1046415c960b22b4084057577fc371510864378354ddRob Landley
104760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic uint8_t* set_optval6(uint8_t *optptr, uint16_t opt, void *var, size_t len)
104860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
104960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  *((uint16_t*)optptr) = htons(opt);
105060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  *(uint16_t*)(optptr+2) = htons(len);
105160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(optptr+4, var, len);
105260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  optptr += len+4;
105360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  return optptr;
105460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
105560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1056415c960b22b4084057577fc371510864378354ddRob Landley// Gets a option value from dhcp packet's option field
1057415c960b22b4084057577fc371510864378354ddRob Landleystatic uint8_t* get_optval(uint8_t *optptr, uint16_t opt, void *var)
1058415c960b22b4084057577fc371510864378354ddRob Landley{
1059415c960b22b4084057577fc371510864378354ddRob Landley  size_t len;
1060415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t overloaded = 0;
1061415c960b22b4084057577fc371510864378354ddRob Landley
1062415c960b22b4084057577fc371510864378354ddRob Landley  while (1) {
1063415c960b22b4084057577fc371510864378354ddRob Landley    while (*optptr == DHCP_OPT_PADDING) optptr++;
1064415c960b22b4084057577fc371510864378354ddRob Landley    if ((*optptr & 0x00FF) == DHCP_OPT_END) break;
1065415c960b22b4084057577fc371510864378354ddRob Landley    if ((*optptr & 0x00FF) == DHCP_OPT_OPTION_OVERLOAD) {
1066415c960b22b4084057577fc371510864378354ddRob Landley      overloaded = optptr[2];
1067415c960b22b4084057577fc371510864378354ddRob Landley      optptr += optptr[1] + 2;
1068415c960b22b4084057577fc371510864378354ddRob Landley    }
1069415c960b22b4084057577fc371510864378354ddRob Landley    len = optptr[1];
1070415c960b22b4084057577fc371510864378354ddRob Landley    if (*optptr == (opt & 0x00FF))
1071415c960b22b4084057577fc371510864378354ddRob Landley      switch (opt & 0xFF00) {
1072415c960b22b4084057577fc371510864378354ddRob Landley        case DHCP_NUM32: // FALLTHROUGH
1073415c960b22b4084057577fc371510864378354ddRob Landley        case DHCP_IP:
1074415c960b22b4084057577fc371510864378354ddRob Landley          memcpy(var, optptr+2, sizeof(uint32_t));
1075415c960b22b4084057577fc371510864378354ddRob Landley          optptr += len + 2;
1076415c960b22b4084057577fc371510864378354ddRob Landley          return optptr;
1077415c960b22b4084057577fc371510864378354ddRob Landley          break;
1078415c960b22b4084057577fc371510864378354ddRob Landley        case DHCP_NUM16:
1079415c960b22b4084057577fc371510864378354ddRob Landley          memcpy(var, optptr+2, sizeof(uint16_t));
1080415c960b22b4084057577fc371510864378354ddRob Landley          optptr += len + 2;
1081415c960b22b4084057577fc371510864378354ddRob Landley          return optptr;
1082415c960b22b4084057577fc371510864378354ddRob Landley          break;
1083415c960b22b4084057577fc371510864378354ddRob Landley        case DHCP_NUM8:
1084415c960b22b4084057577fc371510864378354ddRob Landley          memcpy(var, optptr+2, sizeof(uint8_t));
1085415c960b22b4084057577fc371510864378354ddRob Landley          optptr += len + 2;
1086415c960b22b4084057577fc371510864378354ddRob Landley          return optptr;
1087415c960b22b4084057577fc371510864378354ddRob Landley          break;
1088415c960b22b4084057577fc371510864378354ddRob Landley        case DHCP_STRING:
1089415c960b22b4084057577fc371510864378354ddRob Landley          var = xstrndup((char*) optptr, len);
1090415c960b22b4084057577fc371510864378354ddRob Landley          optptr += len + 2;
1091415c960b22b4084057577fc371510864378354ddRob Landley          return optptr;
1092415c960b22b4084057577fc371510864378354ddRob Landley          break;
1093415c960b22b4084057577fc371510864378354ddRob Landley      }
1094415c960b22b4084057577fc371510864378354ddRob Landley    optptr += len + 2;
1095415c960b22b4084057577fc371510864378354ddRob Landley  }
109660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if ((overloaded == 1) | (overloaded == 3)) get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.file, opt, var);
109760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if ((overloaded == 2) | (overloaded == 3)) get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.sname, opt, var);
109860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  return optptr;
109960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
110060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
110160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic uint8_t* get_optval6(uint8_t *optptr, uint16_t opt, uint16_t *datalen, void **var)
110260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
110360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint16_t optcode;
110460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint16_t len;
110560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
110660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(&optcode, optptr, sizeof(uint16_t));
110760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(&len, optptr+2, sizeof(uint16_t));
110860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if(!optcode) {
110960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    dbg("Option %d is not exist.\n", opt);
111060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    return optptr;
111160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
111260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  optcode = ntohs(optcode);
111360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  len = ntohs(len);
111460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
111560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (opt == optcode) {
111660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    *var = xmalloc(len);
111760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    memcpy(*var, optptr+4, len);
111860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    optptr = optptr + len + 4;
111960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    memcpy(datalen, &len, sizeof(uint16_t));
112060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
112160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  else {
112260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    optptr = get_optval6(optptr+len+4, opt, datalen, var);
112360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
112460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1125415c960b22b4084057577fc371510864378354ddRob Landley  return optptr;
1126415c960b22b4084057577fc371510864378354ddRob Landley}
1127415c960b22b4084057577fc371510864378354ddRob Landley
1128415c960b22b4084057577fc371510864378354ddRob Landley// Retrives Requested Parameter list from dhcp req packet.
1129415c960b22b4084057577fc371510864378354ddRob Landleystatic uint8_t get_reqparam(uint8_t **list)
1130415c960b22b4084057577fc371510864378354ddRob Landley{
1131415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t len, *optptr;
1132415c960b22b4084057577fc371510864378354ddRob Landley  if(*list) free(*list);
113360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  for (optptr = gstate.rcvd.rcvd_pkt.options;
1134415c960b22b4084057577fc371510864378354ddRob Landley      *optptr && *optptr!=((DHCP_OPT_PARAM_REQ) & 0x00FF); optptr+=optptr[1]+2);
1135415c960b22b4084057577fc371510864378354ddRob Landley  len = *++optptr;
1136415c960b22b4084057577fc371510864378354ddRob Landley  *list = xzalloc(len+1);
1137415c960b22b4084057577fc371510864378354ddRob Landley  memcpy(*list, ++optptr, len);
1138415c960b22b4084057577fc371510864378354ddRob Landley  return len;
1139415c960b22b4084057577fc371510864378354ddRob Landley}
1140415c960b22b4084057577fc371510864378354ddRob Landley
1141415c960b22b4084057577fc371510864378354ddRob Landley// Sets values of req param in dhcp offer packet.
1142415c960b22b4084057577fc371510864378354ddRob Landleystatic uint8_t* set_reqparam(uint8_t *optptr, uint8_t *list)
1143415c960b22b4084057577fc371510864378354ddRob Landley{
1144415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t reqcode;
1145415c960b22b4084057577fc371510864378354ddRob Landley  int count, size = ARRAY_LEN(options_list);
1146415c960b22b4084057577fc371510864378354ddRob Landley
1147415c960b22b4084057577fc371510864378354ddRob Landley  while (*list) {
1148415c960b22b4084057577fc371510864378354ddRob Landley    reqcode = *list++;
1149415c960b22b4084057577fc371510864378354ddRob Landley    for (count = 0; count < size; count++) {
1150415c960b22b4084057577fc371510864378354ddRob Landley      if ((options_list[count].code & 0X00FF)==reqcode) {
1151415c960b22b4084057577fc371510864378354ddRob Landley        if (!(options_list[count].len) || !(options_list[count].val)) break;
1152415c960b22b4084057577fc371510864378354ddRob Landley        for (; *optptr && *optptr!=DHCP_OPT_END; optptr+=optptr[1]+2);
1153415c960b22b4084057577fc371510864378354ddRob Landley        *optptr++ = (uint8_t) (options_list[count].code & 0x00FF);
1154415c960b22b4084057577fc371510864378354ddRob Landley        *optptr++ = (uint8_t) options_list[count].len;
1155415c960b22b4084057577fc371510864378354ddRob Landley        memcpy(optptr, options_list[count].val, options_list[count].len);
1156415c960b22b4084057577fc371510864378354ddRob Landley        optptr += options_list[count].len;
1157415c960b22b4084057577fc371510864378354ddRob Landley        *optptr = DHCP_OPT_END;
1158415c960b22b4084057577fc371510864378354ddRob Landley        break;
1159415c960b22b4084057577fc371510864378354ddRob Landley      }
1160415c960b22b4084057577fc371510864378354ddRob Landley    }
1161415c960b22b4084057577fc371510864378354ddRob Landley  }
1162415c960b22b4084057577fc371510864378354ddRob Landley  return optptr;
1163415c960b22b4084057577fc371510864378354ddRob Landley}
1164415c960b22b4084057577fc371510864378354ddRob Landley
1165415c960b22b4084057577fc371510864378354ddRob Landleystatic void run_notify(char **argv)
1166415c960b22b4084057577fc371510864378354ddRob Landley{
1167415c960b22b4084057577fc371510864378354ddRob Landley  struct stat sts;
1168415c960b22b4084057577fc371510864378354ddRob Landley  volatile int error = 0;
1169415c960b22b4084057577fc371510864378354ddRob Landley  pid_t pid;
1170415c960b22b4084057577fc371510864378354ddRob Landley
1171415c960b22b4084057577fc371510864378354ddRob Landley  if (stat(argv[0], &sts) == -1 && errno == ENOENT) {
1172415c960b22b4084057577fc371510864378354ddRob Landley    infomsg(infomode, "notify file: %s : not exist.", argv[0]);
1173415c960b22b4084057577fc371510864378354ddRob Landley    return;
1174415c960b22b4084057577fc371510864378354ddRob Landley  }
1175415c960b22b4084057577fc371510864378354ddRob Landley  fflush(NULL);
1176415c960b22b4084057577fc371510864378354ddRob Landley
1177415c960b22b4084057577fc371510864378354ddRob Landley  pid = vfork();
1178415c960b22b4084057577fc371510864378354ddRob Landley  if (pid < 0) {
1179415c960b22b4084057577fc371510864378354ddRob Landley    dbg("Fork failed.\n");
1180415c960b22b4084057577fc371510864378354ddRob Landley    return;
1181415c960b22b4084057577fc371510864378354ddRob Landley  }
1182415c960b22b4084057577fc371510864378354ddRob Landley  if (!pid) {
1183415c960b22b4084057577fc371510864378354ddRob Landley    execvp(argv[0], argv);
1184415c960b22b4084057577fc371510864378354ddRob Landley    error = errno;
1185415c960b22b4084057577fc371510864378354ddRob Landley    _exit(111);
1186415c960b22b4084057577fc371510864378354ddRob Landley  }
1187415c960b22b4084057577fc371510864378354ddRob Landley  if (error) {
1188415c960b22b4084057577fc371510864378354ddRob Landley    waitpid(pid, NULL, 0);
1189415c960b22b4084057577fc371510864378354ddRob Landley    errno = error;
1190415c960b22b4084057577fc371510864378354ddRob Landley  }
1191415c960b22b4084057577fc371510864378354ddRob Landley  dbg("script complete.\n");
1192415c960b22b4084057577fc371510864378354ddRob Landley}
1193415c960b22b4084057577fc371510864378354ddRob Landley
119460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic void write_leasefile(void)
1195415c960b22b4084057577fc371510864378354ddRob Landley{
1196415c960b22b4084057577fc371510864378354ddRob Landley  int fd;
1197415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t curr, tmp_time;
1198415c960b22b4084057577fc371510864378354ddRob Landley  int64_t timestamp;
1199415c960b22b4084057577fc371510864378354ddRob Landley  struct arg_list *listdls = gstate.dleases;
1200415c960b22b4084057577fc371510864378354ddRob Landley  dyn_lease *dls;
1201415c960b22b4084057577fc371510864378354ddRob Landley
1202aebcdfa659679e5a1f92a9ad12e7c36621962988Rob Landley  if ((fd = open(gconfig.lease_file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
1203415c960b22b4084057577fc371510864378354ddRob Landley    perror_msg("can't open %s ", gconfig.lease_file);
120460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  } else {
120560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    curr = timestamp = time(NULL);
120660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    timestamp = SWAP_BE64(timestamp);
120760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    writeall(fd, &timestamp, sizeof(timestamp));
120860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
120960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    while (listdls) {
121060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      dls = (dyn_lease*)listdls->arg;
121160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      tmp_time = dls->expires;
121260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      dls->expires -= curr;
121360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if ((int32_t) dls->expires < 0) goto skip;
121460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      dls->expires = htonl(dls->expires);
121560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      writeall(fd, dls, sizeof(dyn_lease));
121660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhskip:
121760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      dls->expires = tmp_time;
121860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      listdls = listdls->next;
121960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
122060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    close(fd);
122160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if (gconfig.notify_file) {
122260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      char *argv[3];
122360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      argv[0] = gconfig.notify_file;
122460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      argv[1] = gconfig.lease_file;
122560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      argv[2] = NULL;
122660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      run_notify(argv);
122760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
1228415c960b22b4084057577fc371510864378354ddRob Landley  }
122960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
1230415c960b22b4084057577fc371510864378354ddRob Landley
123160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic void write_lease6file(void)
123260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
123360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  int fd;
123460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t curr, tmp_time;
123560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  int64_t timestamp;
123660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct arg_list *listdls = gstate.dleases;
123760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dyn_lease6 *dls6;
1238415c960b22b4084057577fc371510864378354ddRob Landley
123960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if ((fd = open(gconfig.lease6_file, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
124060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    perror_msg("can't open %s ", gconfig.lease6_file);
124160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  } else {
124260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    curr = timestamp = time(NULL);
124360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    timestamp = SWAP_BE64(timestamp);
124460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    writeall(fd, &timestamp, sizeof(timestamp));
124560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
124660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    while (listdls) {
124760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      dls6 = (dyn_lease6*)listdls->arg;
124860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      tmp_time = dls6->expires;
124960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      dls6->expires -= curr;
125060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if ((int32_t) dls6->expires < 0) goto skip;
125160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      dls6->expires = htonl(dls6->expires);
125260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      writeall(fd, dls6, sizeof(dyn_lease6));
1253415c960b22b4084057577fc371510864378354ddRob Landleyskip:
125460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      dls6->expires = tmp_time;
125560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      listdls = listdls->next;
125660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
125760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    close(fd);
125860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if (gconfig.notify_file) {
125960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      char *argv[3];
126060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      argv[0] = gconfig.notify_file;
126160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      argv[1] = gconfig.lease6_file;
126260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      argv[2] = NULL;
126360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      run_notify(argv);
126460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
1265415c960b22b4084057577fc371510864378354ddRob Landley  }
1266415c960b22b4084057577fc371510864378354ddRob Landley}
1267415c960b22b4084057577fc371510864378354ddRob Landley
1268415c960b22b4084057577fc371510864378354ddRob Landley// Update max lease time from options.
1269415c960b22b4084057577fc371510864378354ddRob Landleystatic void set_maxlease(void)
1270415c960b22b4084057577fc371510864378354ddRob Landley{
1271415c960b22b4084057577fc371510864378354ddRob Landley  int count, size = ARRAY_LEN(options_list);
1272415c960b22b4084057577fc371510864378354ddRob Landley  for (count = 0; count < size; count++)
1273415c960b22b4084057577fc371510864378354ddRob Landley    if (options_list[count].val && options_list[count].code == (DHCP_OPT_LEASE_TIME)) {
1274415c960b22b4084057577fc371510864378354ddRob Landley      gconfig.max_lease_sec = *((uint32_t*)options_list[count].val);
1275415c960b22b4084057577fc371510864378354ddRob Landley      break;
1276415c960b22b4084057577fc371510864378354ddRob Landley    }
1277415c960b22b4084057577fc371510864378354ddRob Landley  if (!gconfig.max_lease_sec) gconfig.max_lease_sec = (60*60*24*10);// DEFAULT_LEASE_TIME;
1278415c960b22b4084057577fc371510864378354ddRob Landley}
1279415c960b22b4084057577fc371510864378354ddRob Landley
1280415c960b22b4084057577fc371510864378354ddRob Landley// Returns lease time for client.
1281415c960b22b4084057577fc371510864378354ddRob Landleystatic uint32_t get_lease(uint32_t req_exp)
1282415c960b22b4084057577fc371510864378354ddRob Landley{
1283415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t now = time(NULL);
1284415c960b22b4084057577fc371510864378354ddRob Landley  req_exp = req_exp - now;
128560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if(addr_version == AF_INET6) {
128660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if ((req_exp <= 0) || req_exp > gconfig.pref_lifetime ||
128760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        req_exp > gconfig.valid_lifetime) {
128860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if ((gconfig.pref_lifetime > gconfig.valid_lifetime)) {
128960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        error_msg("The valid lifetime must be greater than the preferred lifetime, \
129060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            setting to valid lifetime", gconfig.valid_lifetime);
129160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        return gconfig.valid_lifetime;
129260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      }
129360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      return gconfig.pref_lifetime;
129460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
129560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  } else {
129660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if ((req_exp <= 0) || (req_exp > gconfig.max_lease_sec))
129760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      return gconfig.max_lease_sec;
1298415c960b22b4084057577fc371510864378354ddRob Landley
129960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if (req_exp < gconfig.min_lease_sec)
130060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      return gconfig.min_lease_sec;
130160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
1302415c960b22b4084057577fc371510864378354ddRob Landley
1303415c960b22b4084057577fc371510864378354ddRob Landley  return req_exp;
1304415c960b22b4084057577fc371510864378354ddRob Landley}
1305415c960b22b4084057577fc371510864378354ddRob Landley
1306c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suhstatic int verifyip6_in_lease(uint8_t *nip6, uint8_t *duid, uint16_t ia_type, uint32_t iaid)
130760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
130860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  static_lease6 *sls6;
130960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct arg_list *listdls;
131060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
131160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  for (listdls = gstate.dleases; listdls; listdls = listdls->next) {
131260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if (!memcmp(((dyn_lease6*) listdls->arg)->lease_nip6, nip6, sizeof(uint32_t)*4))
131360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      return -1;
131460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
131560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if (!memcmp(((dyn_lease6*) listdls->arg)->duid, duid, ((dyn_lease6*) listdls->arg)->duid_len)
131660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        && ((dyn_lease6*) listdls->arg)->ia_type == ia_type)
131760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      return -1;
131860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
131960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  for (sls6 = gstate.leases.sleases6; sls6; sls6 = sls6->next)
132060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if (memcmp(sls6->nip6, nip6, sizeof(uint32_t)*4)==0) return -2;
132160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1322c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  if (memcmp(nip6, gconfig.start_ip6, sizeof(uint32_t)*4) < 0 ||
1323c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh      memcmp(nip6, gconfig.end_ip6, sizeof(uint32_t)*4) > 0)
132460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    return -3;
132560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
132660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  return 0;
132760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
132860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1329415c960b22b4084057577fc371510864378354ddRob Landley// Verify ip NIP in current leases ( assigned or not)
1330415c960b22b4084057577fc371510864378354ddRob Landleystatic int verifyip_in_lease(uint32_t nip, uint8_t mac[6])
1331415c960b22b4084057577fc371510864378354ddRob Landley{
1332415c960b22b4084057577fc371510864378354ddRob Landley  static_lease *sls;
1333415c960b22b4084057577fc371510864378354ddRob Landley  struct arg_list *listdls;
1334415c960b22b4084057577fc371510864378354ddRob Landley
1335415c960b22b4084057577fc371510864378354ddRob Landley  for (listdls = gstate.dleases; listdls; listdls = listdls->next) {
1336415c960b22b4084057577fc371510864378354ddRob Landley    if (((dyn_lease*) listdls->arg)->lease_nip == nip) {
1337415c960b22b4084057577fc371510864378354ddRob Landley      if (((int32_t)(((dyn_lease*) listdls->arg)->expires) - time(NULL)) < 0)
1338415c960b22b4084057577fc371510864378354ddRob Landley        return 0;
1339415c960b22b4084057577fc371510864378354ddRob Landley      return -1;
1340415c960b22b4084057577fc371510864378354ddRob Landley    }
1341415c960b22b4084057577fc371510864378354ddRob Landley    if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) return -1;
1342415c960b22b4084057577fc371510864378354ddRob Landley  }
134360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  for (sls = gstate.leases.sleases; sls; sls = sls->next)
1344415c960b22b4084057577fc371510864378354ddRob Landley    if (sls->nip == nip) return -2;
1345415c960b22b4084057577fc371510864378354ddRob Landley
1346415c960b22b4084057577fc371510864378354ddRob Landley  if ((ntohl(nip) < gconfig.start_ip) || (ntohl(nip) > gconfig.end_ip))
1347415c960b22b4084057577fc371510864378354ddRob Landley    return -3;
1348415c960b22b4084057577fc371510864378354ddRob Landley
1349415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
1350415c960b22b4084057577fc371510864378354ddRob Landley}
1351415c960b22b4084057577fc371510864378354ddRob Landley
1352415c960b22b4084057577fc371510864378354ddRob Landley// add ip assigned_nip to dynamic lease.
1353415c960b22b4084057577fc371510864378354ddRob Landleystatic int addip_to_lease(uint32_t assigned_nip, uint8_t mac[6], uint32_t *req_exp, char *hostname, uint8_t update)
1354415c960b22b4084057577fc371510864378354ddRob Landley{
1355415c960b22b4084057577fc371510864378354ddRob Landley  dyn_lease *dls;
1356415c960b22b4084057577fc371510864378354ddRob Landley  struct arg_list *listdls = gstate.dleases;
1357415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t now = time(NULL);
1358415c960b22b4084057577fc371510864378354ddRob Landley
1359415c960b22b4084057577fc371510864378354ddRob Landley  while (listdls) {
1360415c960b22b4084057577fc371510864378354ddRob Landley    if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) {
1361415c960b22b4084057577fc371510864378354ddRob Landley      if (update) *req_exp = get_lease(*req_exp + ((dyn_lease*) listdls->arg)->expires);
1362415c960b22b4084057577fc371510864378354ddRob Landley      ((dyn_lease*) listdls->arg)->expires = *req_exp + now;
1363415c960b22b4084057577fc371510864378354ddRob Landley      return 0;
1364415c960b22b4084057577fc371510864378354ddRob Landley    }
1365415c960b22b4084057577fc371510864378354ddRob Landley    listdls = listdls->next;
1366415c960b22b4084057577fc371510864378354ddRob Landley  }
1367415c960b22b4084057577fc371510864378354ddRob Landley
1368415c960b22b4084057577fc371510864378354ddRob Landley  dls = xzalloc(sizeof(dyn_lease));
1369415c960b22b4084057577fc371510864378354ddRob Landley  memcpy(dls->lease_mac, mac, 6);
1370415c960b22b4084057577fc371510864378354ddRob Landley  dls->lease_nip = assigned_nip;
1371415c960b22b4084057577fc371510864378354ddRob Landley  if (hostname) memcpy(dls->hostname, hostname, 20);
1372415c960b22b4084057577fc371510864378354ddRob Landley
1373415c960b22b4084057577fc371510864378354ddRob Landley  if (update) *req_exp = get_lease(*req_exp + now);
1374415c960b22b4084057577fc371510864378354ddRob Landley  dls->expires = *req_exp + now;
1375415c960b22b4084057577fc371510864378354ddRob Landley
1376415c960b22b4084057577fc371510864378354ddRob Landley  listdls = xzalloc(sizeof(struct arg_list));
1377415c960b22b4084057577fc371510864378354ddRob Landley  listdls->next = gstate.dleases;
1378415c960b22b4084057577fc371510864378354ddRob Landley  listdls->arg = (char*)dls;
1379415c960b22b4084057577fc371510864378354ddRob Landley  gstate.dleases = listdls;
1380415c960b22b4084057577fc371510864378354ddRob Landley
1381415c960b22b4084057577fc371510864378354ddRob Landley  return 0;
1382415c960b22b4084057577fc371510864378354ddRob Landley}
1383415c960b22b4084057577fc371510864378354ddRob Landley
1384c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suhstatic int addip6_to_lease(uint8_t *assigned_nip, uint8_t *duid, uint16_t duid_len, uint16_t ia_type, uint32_t iaid, uint32_t *lifetime, uint8_t update)
138560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
138660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dyn_lease6 *dls6;
138760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct arg_list *listdls = gstate.dleases;
138860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t now = time(NULL);
138960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
139060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  while (listdls) {
139160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if (!memcmp(((dyn_lease6*) listdls->arg)->duid, duid, ((dyn_lease6*) listdls->arg)->duid_len)) {
139260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if (update) *lifetime = get_lease(*lifetime + ((dyn_lease6*) listdls->arg)->expires);
139360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      ((dyn_lease6*) listdls->arg)->expires = *lifetime + now;
139460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      return 0;
139560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
139660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    listdls = listdls->next;
139760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
139860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
139960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dls6 = xzalloc(sizeof(dyn_lease6));
1400c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  dls6->duid_len = duid_len;
1401c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  memcpy(dls6->duid, duid, duid_len);
140260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dls6->ia_type = ia_type;
140360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dls6->iaid = iaid;
140460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  memcpy(dls6->lease_nip6, assigned_nip, sizeof(uint32_t)*4);
140560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
140660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (update) *lifetime = get_lease(*lifetime + now);
140760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dls6->expires = *lifetime + now;
140860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
140960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  listdls = xzalloc(sizeof(struct arg_list));
141060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  listdls->next = gstate.dleases;
141160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  listdls->arg = (char*)dls6;
141260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  gstate.dleases = listdls;
141360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
141460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  return 0;
141560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
141660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1417415c960b22b4084057577fc371510864378354ddRob Landley// delete ip assigned_nip from dynamic lease.
1418415c960b22b4084057577fc371510864378354ddRob Landleystatic int delip_from_lease(uint32_t assigned_nip, uint8_t mac[6], uint32_t del_time)
1419415c960b22b4084057577fc371510864378354ddRob Landley{
1420415c960b22b4084057577fc371510864378354ddRob Landley  struct arg_list *listdls = gstate.dleases;
1421415c960b22b4084057577fc371510864378354ddRob Landley
1422415c960b22b4084057577fc371510864378354ddRob Landley  while (listdls) {
1423415c960b22b4084057577fc371510864378354ddRob Landley    if (!memcmp(((dyn_lease*) listdls->arg)->lease_mac, mac, 6)) {
1424415c960b22b4084057577fc371510864378354ddRob Landley      ((dyn_lease*) listdls->arg)->expires = del_time + time(NULL);
1425415c960b22b4084057577fc371510864378354ddRob Landley      return 0;
1426415c960b22b4084057577fc371510864378354ddRob Landley    }
1427415c960b22b4084057577fc371510864378354ddRob Landley    listdls = listdls->next;
1428415c960b22b4084057577fc371510864378354ddRob Landley  }
1429415c960b22b4084057577fc371510864378354ddRob Landley  return -1;
1430415c960b22b4084057577fc371510864378354ddRob Landley}
1431415c960b22b4084057577fc371510864378354ddRob Landley
1432415c960b22b4084057577fc371510864378354ddRob Landley// returns a IP from static, dynamic leases or free ip pool, 0 otherwise.
1433415c960b22b4084057577fc371510864378354ddRob Landleystatic uint32_t getip_from_pool(uint32_t req_nip, uint8_t mac[6], uint32_t *req_exp, char *hostname)
1434415c960b22b4084057577fc371510864378354ddRob Landley{
1435415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t nip = 0;
143660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  static_lease *sls = gstate.leases.sleases;
1437415c960b22b4084057577fc371510864378354ddRob Landley  struct arg_list *listdls = gstate.dleases, *tmp = NULL;
1438415c960b22b4084057577fc371510864378354ddRob Landley
1439415c960b22b4084057577fc371510864378354ddRob Landley  if (req_nip && (!verifyip_in_lease(req_nip, mac))) nip = req_nip;
1440415c960b22b4084057577fc371510864378354ddRob Landley
1441415c960b22b4084057577fc371510864378354ddRob Landley  if (!nip) {
1442415c960b22b4084057577fc371510864378354ddRob Landley    while (listdls) {
1443415c960b22b4084057577fc371510864378354ddRob Landley      if (!memcmp(((dyn_lease*)listdls->arg)->lease_mac, mac, 6)) {
1444415c960b22b4084057577fc371510864378354ddRob Landley        nip = ((dyn_lease*)listdls->arg)->lease_nip;
1445415c960b22b4084057577fc371510864378354ddRob Landley        if (tmp) tmp->next = listdls->next;
1446415c960b22b4084057577fc371510864378354ddRob Landley        else gstate.dleases = listdls->next;
1447415c960b22b4084057577fc371510864378354ddRob Landley        free(listdls->arg);
1448415c960b22b4084057577fc371510864378354ddRob Landley        free(listdls);
1449415c960b22b4084057577fc371510864378354ddRob Landley        if (verifyip_in_lease(nip, mac) < 0) nip = 0;
1450415c960b22b4084057577fc371510864378354ddRob Landley        break;
1451415c960b22b4084057577fc371510864378354ddRob Landley      }
1452415c960b22b4084057577fc371510864378354ddRob Landley      tmp = listdls;
1453415c960b22b4084057577fc371510864378354ddRob Landley      listdls = listdls->next;
1454415c960b22b4084057577fc371510864378354ddRob Landley    }
1455415c960b22b4084057577fc371510864378354ddRob Landley  }
1456415c960b22b4084057577fc371510864378354ddRob Landley  if (!nip) {
1457415c960b22b4084057577fc371510864378354ddRob Landley    while (sls) {
1458415c960b22b4084057577fc371510864378354ddRob Landley      if (memcmp(sls->mac, mac, 6) == 0) {
1459415c960b22b4084057577fc371510864378354ddRob Landley        nip = sls->nip;
1460415c960b22b4084057577fc371510864378354ddRob Landley        break;
1461415c960b22b4084057577fc371510864378354ddRob Landley      }
1462415c960b22b4084057577fc371510864378354ddRob Landley      sls = sls->next;
1463415c960b22b4084057577fc371510864378354ddRob Landley    }
1464415c960b22b4084057577fc371510864378354ddRob Landley  }
1465415c960b22b4084057577fc371510864378354ddRob Landley  if (!nip) {
1466415c960b22b4084057577fc371510864378354ddRob Landley    for (nip = htonl(gconfig.start_ip); ntohl(nip) <= gconfig.end_ip; ) {
1467415c960b22b4084057577fc371510864378354ddRob Landley      if (!verifyip_in_lease(nip, mac)) break;
1468415c960b22b4084057577fc371510864378354ddRob Landley      nip = ntohl(nip);
1469415c960b22b4084057577fc371510864378354ddRob Landley      nip = htonl(++nip);
1470415c960b22b4084057577fc371510864378354ddRob Landley    }
1471415c960b22b4084057577fc371510864378354ddRob Landley    if (ntohl(nip) > gconfig.end_ip) {
1472415c960b22b4084057577fc371510864378354ddRob Landley      nip = 0;
1473415c960b22b4084057577fc371510864378354ddRob Landley      infomsg(infomode, "can't find free IP in IP Pool.");
1474415c960b22b4084057577fc371510864378354ddRob Landley    }
1475415c960b22b4084057577fc371510864378354ddRob Landley  }
1476415c960b22b4084057577fc371510864378354ddRob Landley  if (nip) addip_to_lease(nip, mac, req_exp, hostname, 1);
1477415c960b22b4084057577fc371510864378354ddRob Landley  return nip;
1478415c960b22b4084057577fc371510864378354ddRob Landley}
1479415c960b22b4084057577fc371510864378354ddRob Landley
1480c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suhstatic uint8_t *getip6_from_pool(uint8_t *duid, uint16_t duid_len, uint16_t ia_type, uint32_t iaid, uint32_t *lifetime)
148160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
1482c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  static uint8_t nip6[16] = {0, };
148360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  static_lease6 *sls6 = gstate.leases.sleases6;
148460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  struct arg_list *listdls6 = gstate.dleases, *tmp = NULL;
148560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
148660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  while(listdls6) {
148760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    if (!memcmp(((dyn_lease6*)listdls6->arg)->duid, duid, duid_len)) {
148860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      memcpy(nip6, ((dyn_lease6*)listdls6->arg)->lease_nip6, sizeof(nip6));
148960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if(tmp) tmp->next = listdls6->next;
149060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      else gstate.dleases = listdls6->next;
149160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      free(listdls6->arg);
149260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      free(listdls6);
149360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
149460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if(verifyip6_in_lease(nip6, duid, ia_type, iaid) < 0)
149560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        memset(nip6, 0, sizeof(nip6));
149660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      break;
149760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
149860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    tmp = listdls6;
149960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    listdls6 = listdls6->next;
150060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
150160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1502c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  if(!memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
150360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    while(sls6) {
150460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if(!memcmp(sls6->duid, duid, 6)) {
150560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        memcpy(nip6, sls6->nip6, sizeof(nip6));
150660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        break;
150760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      }
150860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      sls6 = sls6->next;
150960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
151060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
151160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1512c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  if(!memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
1513c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    memcpy(nip6, gconfig.start_ip6, sizeof(nip6));
1514c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    while(memcmp(nip6, gconfig.end_ip6, sizeof(nip6)) < 0) {
151560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if(!verifyip6_in_lease(nip6, duid, ia_type, iaid)) break;
1516c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh      int i=sizeof(nip6);
151760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      while(i--) {
1518c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        ++nip6[i];
1519c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        if (!nip6[i]) {
1520c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh          if(i==(sizeof(nip6)-1)) ++nip6[i];
1521c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh          ++nip6[i-1];
1522c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        } else
152360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          break;
152460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      }
152560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
152660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1527c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    if (memcmp(nip6, gconfig.end_ip6, sizeof(nip6)) > 0) {
152860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      memset(nip6, 0, sizeof(nip6));
152960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      infomsg(infomode, "can't find free IP in IPv6 Pool.");
153060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
153160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
153260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1533c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  if(memcmp(nip6, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
1534c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    addip6_to_lease(nip6, duid, duid_len, ia_type, iaid, lifetime, 1);
1535c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    infomsg(infomode, "Assigned IPv6 %02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
1536c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        nip6[0], nip6[1], nip6[2], nip6[3], nip6[4], nip6[5], nip6[6], nip6[7], nip6[8],
1537c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        nip6[9], nip6[10], nip6[11], nip6[12], nip6[13], nip6[14], nip6[15]);
1538c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  }
153960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  return nip6;
154060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
154160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
154260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic void read_leasefile(void)
1543415c960b22b4084057577fc371510864378354ddRob Landley{
1544415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t passed, ip;
1545415c960b22b4084057577fc371510864378354ddRob Landley  int32_t tmp_time;
1546415c960b22b4084057577fc371510864378354ddRob Landley  int64_t timestamp;
1547415c960b22b4084057577fc371510864378354ddRob Landley  dyn_lease *dls;
154860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  int fd = open(gconfig.lease_file, O_RDONLY);
1549415c960b22b4084057577fc371510864378354ddRob Landley
1550415c960b22b4084057577fc371510864378354ddRob Landley  dls = xzalloc(sizeof(dyn_lease));
1551415c960b22b4084057577fc371510864378354ddRob Landley
155260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (read(fd, &timestamp, sizeof(timestamp)) != sizeof(timestamp))
155360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    goto lease_error_exit;
1554415c960b22b4084057577fc371510864378354ddRob Landley
1555415c960b22b4084057577fc371510864378354ddRob Landley  timestamp = SWAP_BE64(timestamp);
1556415c960b22b4084057577fc371510864378354ddRob Landley  passed = time(NULL) - timestamp;
155760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if ((uint64_t)passed > 12 * 60 * 60) goto lease_error_exit;
1558415c960b22b4084057577fc371510864378354ddRob Landley
1559415c960b22b4084057577fc371510864378354ddRob Landley  while (read(fd, dls, sizeof(dyn_lease)) == sizeof(dyn_lease)) {
1560415c960b22b4084057577fc371510864378354ddRob Landley    ip = ntohl(dls->lease_nip);
1561415c960b22b4084057577fc371510864378354ddRob Landley    if (ip >= gconfig.start_ip && ip <= gconfig.end_ip) {
1562415c960b22b4084057577fc371510864378354ddRob Landley      tmp_time = ntohl(dls->expires) - passed;
1563415c960b22b4084057577fc371510864378354ddRob Landley      if (tmp_time < 0) continue;
156460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      addip_to_lease(dls->lease_nip, dls->lease_mac,
156560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          (uint32_t*)&tmp_time, dls->hostname, 0);
1566415c960b22b4084057577fc371510864378354ddRob Landley    }
1567415c960b22b4084057577fc371510864378354ddRob Landley  }
156860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhlease_error_exit:
1569415c960b22b4084057577fc371510864378354ddRob Landley  free(dls);
1570415c960b22b4084057577fc371510864378354ddRob Landley  close(fd);
157160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh}
157260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
157360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhstatic void read_lease6file(void)
157460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh{
1575c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  uint32_t passed;
157660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint32_t tmp_time;
157760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  int64_t timestamp;
157860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dyn_lease6 *dls6;
157960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  int fd = open(gconfig.lease6_file, O_RDONLY);
158060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
158160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  dls6 = xzalloc(sizeof(dyn_lease6));
158260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
158360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (read(fd, &timestamp, sizeof(timestamp)) != sizeof(timestamp))
158460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    goto lease6_error_exit;
158560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
158660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  timestamp = SWAP_BE64(timestamp);
158760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  passed = time(NULL) - timestamp;
158860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if ((uint64_t)passed > 12 * 60 * 60) goto lease6_error_exit;
158960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
159060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  while (read(fd, dls6, sizeof(dyn_lease6)) == sizeof(dyn_lease6)) {
1591c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    if (memcmp(dls6->lease_nip6, gconfig.start_ip6, sizeof(uint32_t)*4) > 0 &&
1592c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        memcmp(dls6->lease_nip6, gconfig.end_ip6, sizeof(uint32_t)*4) < 0) {
159360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      tmp_time = ntohl(dls6->expires) - passed;
159460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if (tmp_time < 0U) continue;
1595c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh      addip6_to_lease(dls6->lease_nip6, dls6->duid, dls6->duid_len, dls6->ia_type, dls6->iaid,
159660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          (uint32_t*)&tmp_time, 0);
159760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    }
159860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
159960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
160060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suhlease6_error_exit:
160160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  free(dls6);
160260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  close(fd);
1603415c960b22b4084057577fc371510864378354ddRob Landley}
1604415c960b22b4084057577fc371510864378354ddRob Landley
1605415c960b22b4084057577fc371510864378354ddRob Landleyvoid dhcpd_main(void)
1606415c960b22b4084057577fc371510864378354ddRob Landley{
1607415c960b22b4084057577fc371510864378354ddRob Landley  struct timeval tv;
160860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  int retval, i;
1609415c960b22b4084057577fc371510864378354ddRob Landley  uint8_t *optptr, msgtype = 0;
161060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint16_t optlen = 0;
1611415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t waited = 0, serverid = 0, requested_nip = 0;
161260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  uint8_t transactionid[3] = {0,};
1613415c960b22b4084057577fc371510864378354ddRob Landley  uint32_t reqested_lease = 0, ip_pool_size = 0;
1614415c960b22b4084057577fc371510864378354ddRob Landley  char *hstname = NULL;
1615415c960b22b4084057577fc371510864378354ddRob Landley  fd_set rfds;
1616415c960b22b4084057577fc371510864378354ddRob Landley
1617415c960b22b4084057577fc371510864378354ddRob Landley  infomode = LOG_CONSOLE;
1618547c9167565cf8a2bba8bd79850889101866814aRob Landley  if (!(toys.optflags & FLAG_f)) {
1619c880061f511e85d55afe3966f5eda0df7c3ebb56Rob Landley    daemon(0,0);
1620415c960b22b4084057577fc371510864378354ddRob Landley    infomode = LOG_SILENT;
1621415c960b22b4084057577fc371510864378354ddRob Landley  }
1622547c9167565cf8a2bba8bd79850889101866814aRob Landley  if (toys.optflags & FLAG_S) {
1623415c960b22b4084057577fc371510864378354ddRob Landley        openlog("UDHCPD :", LOG_PID, LOG_DAEMON);
1624415c960b22b4084057577fc371510864378354ddRob Landley        infomode |= LOG_SYSTEM;
1625415c960b22b4084057577fc371510864378354ddRob Landley  }
1626415c960b22b4084057577fc371510864378354ddRob Landley  setlinebuf(stdout);
162760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  //DHCPD_CONF_FILE
162860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  parse_server_config((toys.optc==1)?toys.optargs[0]:"/etc/dhcpd.conf", keywords);
1629415c960b22b4084057577fc371510864378354ddRob Landley  infomsg(infomode, "toybox dhcpd started");
163060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1631547c9167565cf8a2bba8bd79850889101866814aRob Landley  if (toys.optflags & FLAG_6){
163260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    addr_version = AF_INET6;
163360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    gconfig.t1 = ntohl(gconfig.t1);
163460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    gconfig.t2 = ntohl(gconfig.t2);
163560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    gconfig.pref_lifetime = ntohl(gconfig.pref_lifetime);
163660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    gconfig.valid_lifetime = ntohl(gconfig.valid_lifetime);
1637c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    gconfig.port = 547;
163860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    for(i=0;i<4;i++)
163960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      ip_pool_size += (gconfig.end_ip6[i]-gconfig.start_ip6[i])<<((3-i)*8);
164060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  } else {
164160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    gconfig.start_ip = ntohl(gconfig.start_ip);
164260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    gconfig.end_ip = ntohl(gconfig.end_ip);
164360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    ip_pool_size = gconfig.end_ip - gconfig.start_ip + 1;
164460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
164560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1646415c960b22b4084057577fc371510864378354ddRob Landley  if (gconfig.max_leases > ip_pool_size) {
164760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    error_msg("max_leases=%u is too big, setting to %u",
164860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        (unsigned) gconfig.max_leases, ip_pool_size);
1649415c960b22b4084057577fc371510864378354ddRob Landley    gconfig.max_leases = ip_pool_size;
1650415c960b22b4084057577fc371510864378354ddRob Landley  }
1651415c960b22b4084057577fc371510864378354ddRob Landley  write_pid(gconfig.pidfile);
1652415c960b22b4084057577fc371510864378354ddRob Landley  set_maxlease();
165382d8d7cb7eacabd1a498c001dd5618a1302f854bHyejin Kim  if(TT.iface) gconfig.interface = TT.iface;
1654c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh  if(TT.port) gconfig.port = TT.port;
165560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  (addr_version==AF_INET6) ? read_lease6file() : read_leasefile();
165660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1657c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh
165860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (get_interface(gconfig.interface, &gconfig.ifindex,
1659c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        (addr_version==AF_INET6)? (void*)gconfig.server_nip6 :
1660c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        (void*)&gconfig.server_nip, gconfig.server_mac) < 0)
1661415c960b22b4084057577fc371510864378354ddRob Landley    perror_exit("Failed to get interface %s", gconfig.interface);
1662415c960b22b4084057577fc371510864378354ddRob Landley  setup_signal();
166360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  if (addr_version==AF_INET6) {
166460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    open_listensock6();
166560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  } else {
166660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    gconfig.server_nip = htonl(gconfig.server_nip);
166760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh    open_listensock();
166860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh  }
166960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1670415c960b22b4084057577fc371510864378354ddRob Landley  fcntl(gstate.listensock, F_SETFD, FD_CLOEXEC);
1671415c960b22b4084057577fc371510864378354ddRob Landley
1672415c960b22b4084057577fc371510864378354ddRob Landley  for (;;) {
1673415c960b22b4084057577fc371510864378354ddRob Landley    uint32_t timestmp = time(NULL);
1674415c960b22b4084057577fc371510864378354ddRob Landley    FD_ZERO(&rfds);
1675415c960b22b4084057577fc371510864378354ddRob Landley    FD_SET(gstate.listensock, &rfds);
1676415c960b22b4084057577fc371510864378354ddRob Landley    FD_SET(sigfd.rd, &rfds);
1677415c960b22b4084057577fc371510864378354ddRob Landley    tv.tv_sec = gconfig.auto_time - waited;
1678415c960b22b4084057577fc371510864378354ddRob Landley    tv.tv_usec = 0;
1679415c960b22b4084057577fc371510864378354ddRob Landley    retval = 0;
1680415c960b22b4084057577fc371510864378354ddRob Landley    serverid = 0;
1681415c960b22b4084057577fc371510864378354ddRob Landley    msgtype = 0;
1682415c960b22b4084057577fc371510864378354ddRob Landley
1683415c960b22b4084057577fc371510864378354ddRob Landley    int maxfd = (sigfd.rd > gstate.listensock)? sigfd.rd : gstate.listensock;
1684415c960b22b4084057577fc371510864378354ddRob Landley    dbg("select waiting ....\n");
1685415c960b22b4084057577fc371510864378354ddRob Landley    retval = select(maxfd + 1, &rfds, NULL, NULL, (gconfig.auto_time?&tv:NULL));
1686415c960b22b4084057577fc371510864378354ddRob Landley    if (retval < 0) {
1687415c960b22b4084057577fc371510864378354ddRob Landley      if (errno == EINTR) {
1688415c960b22b4084057577fc371510864378354ddRob Landley        waited += (unsigned) time(NULL) - timestmp;
1689415c960b22b4084057577fc371510864378354ddRob Landley        continue;
1690415c960b22b4084057577fc371510864378354ddRob Landley      }
1691415c960b22b4084057577fc371510864378354ddRob Landley      dbg("Error in select wait again...\n");
1692415c960b22b4084057577fc371510864378354ddRob Landley      continue;
1693415c960b22b4084057577fc371510864378354ddRob Landley    }
1694415c960b22b4084057577fc371510864378354ddRob Landley    if (!retval) { // Timed out
1695415c960b22b4084057577fc371510864378354ddRob Landley      dbg("select wait Timed Out...\n");
1696415c960b22b4084057577fc371510864378354ddRob Landley      waited = 0;
1697c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh      (addr_version == AF_INET6)? write_lease6file() : write_leasefile();
169860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if (get_interface(gconfig.interface, &gconfig.ifindex,
1699c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh            (addr_version==AF_INET6)? (void*)gconfig.server_nip6 :
1700c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh            (void*)&gconfig.server_nip, gconfig.server_mac)<0)
170160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        perror_exit("Failed to get interface %s", gconfig.interface);
1702c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh      if(addr_version != AF_INET6) {
1703c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh        gconfig.server_nip = htonl(gconfig.server_nip);
1704c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh      }
1705415c960b22b4084057577fc371510864378354ddRob Landley      continue;
1706415c960b22b4084057577fc371510864378354ddRob Landley    }
1707415c960b22b4084057577fc371510864378354ddRob Landley    if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal
1708415c960b22b4084057577fc371510864378354ddRob Landley      unsigned char sig;
1709415c960b22b4084057577fc371510864378354ddRob Landley      if (read(sigfd.rd, &sig, 1) != 1) {
1710415c960b22b4084057577fc371510864378354ddRob Landley        dbg("signal read failed.\n");
1711415c960b22b4084057577fc371510864378354ddRob Landley        continue;
1712415c960b22b4084057577fc371510864378354ddRob Landley      }
1713415c960b22b4084057577fc371510864378354ddRob Landley      switch (sig) {
171460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        case SIGUSR1:
171560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          infomsg(infomode, "Received SIGUSR1");
171660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          (addr_version==AF_INET6)? write_lease6file() : write_leasefile();
171760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          continue;
171860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        case SIGTERM:
171960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          infomsg(infomode, "received sigterm");
172060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          (addr_version==AF_INET6)? write_lease6file() : write_leasefile();
172160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          unlink(gconfig.pidfile);
172260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          exit(0);
172360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          break;
172460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        default: break;
1725415c960b22b4084057577fc371510864378354ddRob Landley      }
1726415c960b22b4084057577fc371510864378354ddRob Landley    }
1727c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh    if (FD_ISSET(gstate.listensock, &rfds)) { // Some Activity on RDFDs : is socket
1728415c960b22b4084057577fc371510864378354ddRob Landley      dbg("select listen sock read\n");
172960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      if(addr_version==AF_INET6) {
173060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        void *client_duid, *server_duid, *client_ia_na, *server_ia_na,
1731c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh             *client_ia_pd;
173260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        uint8_t client_lla[6] = {0,};
173360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        uint16_t client_duid_len = 0, server_duid_len = 0, server_ia_na_len = 0,
173460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                 client_ia_na_len = 0, client_ia_pd_len = 0;
173560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
173660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        if(read_packet6() < 0) {
173760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          open_listensock6();
173860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          continue;
173960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        }
174060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        waited += time(NULL) - timestmp;
174160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
174260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        memcpy(&gstate.rqcode, &gstate.rcvd.rcvd_pkt6.msgtype, sizeof(uint8_t));
174360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        memcpy(&transactionid, &gstate.rcvd.rcvd_pkt6.transaction_id,
174460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            sizeof(transactionid));
174560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
174660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        if (!gstate.rqcode || gstate.rqcode < DHCP6SOLICIT ||
174760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            gstate.rqcode > DHCP6RELAYREPLY) {
174860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          dbg("no or bad message type option, ignoring packet.\n");
174960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          continue;
175060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        }
175160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        if (!gstate.rcvd.rcvd_pkt6.transaction_id ||
175260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            memcmp(gstate.rcvd.rcvd_pkt6.transaction_id, transactionid, 3)) {
175360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          dbg("no or bad transaction id, ignoring packet.\n");
175460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          continue;
175560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        }
175660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
175760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        waited += time(NULL) - timestmp;
175860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        switch (gstate.rqcode) {
175960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          case DHCP6SOLICIT:
176060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            dbg("Message Type: DHCP6SOLICIT\n");
176160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = prepare_send_pkt6(DHCP6ADVERTISE);
176260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optlen = 0;
176360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
176460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            //TODO policy check
176560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            //TODO Receive: ORO check (e.g. DNS)
176660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1767c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh            //Receive: Client Identifier (DUID)
1768c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh            get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
1769c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh                DHCP6_OPT_CLIENTID, &client_duid_len, &client_duid);
1770c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh
177160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            //Receive: Identity Association for Non-temporary Address
177260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
177360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  DHCP6_OPT_IA_NA, &client_ia_na_len, &client_ia_na)) {
177460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              uint16_t ia_addr_len = sizeof(struct optval_ia_addr);
177560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              void *ia_addr, *status_code;
177660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              char *status_code_msg;
177760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              uint16_t status_code_len = 0;
1778c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh              server_ia_na_len = sizeof(struct optval_ia_na);
177960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
178060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //IA Address
178160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              ia_addr = xzalloc(ia_addr_len);
178260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              struct optval_ia_addr *ia_addr_p = (struct optval_ia_addr*)ia_addr;
178360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*ia_addr_p).pref_lifetime = gconfig.pref_lifetime;
178460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*ia_addr_p).valid_lifetime = gconfig.valid_lifetime;
178560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              memcpy(&(*ia_addr_p).ipv6_addr,
178660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  getip6_from_pool(client_duid, client_duid_len,
178760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                    DHCP6_OPT_IA_NA, (*(struct optval_ia_na*) client_ia_na).iaid,
178860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                    &(*ia_addr_p).pref_lifetime), sizeof(uint32_t)*4);
178960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              server_ia_na_len += (ia_addr_len+4);
179060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
179160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //Status Code
1792c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh              if(memcmp((*ia_addr_p).ipv6_addr, (uint8_t[16]){0}, sizeof(uint32_t)*4)) {
179360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                status_code_msg = xstrdup("Assigned an address.");
179460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                status_code_len = strlen(status_code_msg)+1;
179560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                status_code = xzalloc(status_code_len);
179660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                struct optval_status_code *status_code_p =
179760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  (struct optval_status_code*)status_code;
179860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                (*status_code_p).status_code = htons(DHCP6_STATUS_SUCCESS);
1799c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh                memcpy((*status_code_p).status_msg, status_code_msg,
180060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                    status_code_len);
180160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                server_ia_na_len += (status_code_len+4);
180260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                free(status_code_msg);
180360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              } else {
180460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                status_code_msg = xstrdup("There's no available address.");
180560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                status_code_len = strlen(status_code_msg)+1;
180660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                status_code = xzalloc(status_code_len);
180760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                struct optval_status_code *status_code_p =
180860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  (struct optval_status_code*)status_code;
180960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                (*status_code_p).status_code = htons(DHCP6_STATUS_NOADDRSAVAIL);
1810c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh                memcpy((*status_code_p).status_msg, status_code_msg,
181160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                    status_code_len);
181260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                server_ia_na_len += (status_code_len+4);
181360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                server_ia_na_len -= (ia_addr_len+4);
181460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                ia_addr_len = 0;
181560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                free(ia_addr);
181660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                free(status_code_msg);
181760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                //TODO send failed status code
181860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                break;
181960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              }
182060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
182160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //combine options
182260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              server_ia_na = xzalloc(server_ia_na_len);
182360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              struct optval_ia_na *ia_na_p = (struct optval_ia_na*)server_ia_na;
182460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*ia_na_p).iaid = (*(struct optval_ia_na*)client_ia_na).iaid;
182560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*ia_na_p).t1 = gconfig.t1;
182660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*ia_na_p).t2 = gconfig.t2;
182760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1828c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh              uint8_t* ia_na_optptr = (*ia_na_p).optval;
182960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              if(ia_addr_len) {
183060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                set_optval6(ia_na_optptr, DHCP6_OPT_IA_ADDR, ia_addr, ia_addr_len);
183160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                ia_na_optptr += (ia_addr_len + 4);
183260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                free(ia_addr);
183360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              }
183460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              if(status_code_len) {
183560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                set_optval6(ia_na_optptr, DHCP6_OPT_STATUS_CODE, status_code,
183660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                    status_code_len);
183760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                ia_na_optptr += (status_code_len);
183860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                free(status_code);
183960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              }
184060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
184160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //Response: Identity Association for Non-temporary Address
184260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              optptr = set_optval6(optptr, DHCP6_OPT_IA_NA, server_ia_na,
184360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  server_ia_na_len);
184460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              optlen += (server_ia_na_len + 4);
184560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              free(client_ia_na);free(server_ia_na);
184660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            }
184760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            //Receive: Identity Association for Prefix Delegation
184860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            else if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
184960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  DHCP6_OPT_IA_PD, &client_ia_pd_len, &client_ia_pd)) {
185060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
185160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //TODO
185260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //Response: Identity Association for Prefix Delegation
185360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            }
185460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
185560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            //DUID type: link-layer address plus time
185660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            if(ntohs((*(struct optval_duid_llt*)client_duid).type) ==
185760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP6_DUID_LLT) {
185860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              server_duid_len = 8+sizeof(gconfig.server_mac);
185960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              server_duid = xzalloc(server_duid_len);
186060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              struct optval_duid_llt *server_duid_p =
186160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                (struct optval_duid_llt*)server_duid;
186260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*server_duid_p).type = htons(1);
186360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*server_duid_p).hwtype = htons(1);
186460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*server_duid_p).time = htonl((uint32_t)
186560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  (time(NULL) - 946684800) & 0xffffffff);
1866c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh              memcpy((*server_duid_p).lladdr, gconfig.server_mac,
186760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  sizeof(gconfig.server_mac));
1868c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh              memcpy(&client_lla, (*(struct optval_duid_llt*)client_duid).lladdr,
186960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  sizeof(client_lla));
187060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
187160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //Response: Server Identifier (DUID)
187260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              optptr = set_optval6(optptr, DHCP6_OPT_SERVERID, server_duid,
187360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  server_duid_len);
187460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              optlen += (server_duid_len + 4);
187560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //Response: Client Identifier
187660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              optptr = set_optval6(optptr, DHCP6_OPT_CLIENTID, client_duid,
187760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  client_duid_len);
187860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              optlen += (client_duid_len + 4);
187960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              free(client_duid);free(server_duid);
188060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            }
188160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
188260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            send_packet6(0, client_lla, optlen);
188360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            write_lease6file();
188460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            break;
188560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          case DHCP6REQUEST:
188660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            dbg("Message Type: DHCP6REQUEST\n");
188760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = prepare_send_pkt6(DHCP6REPLY);
188860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optlen = 0;
188960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
189060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            //Receive: Client Identifier (DUID)
189160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
189260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP6_OPT_CLIENTID, &client_duid_len, &client_duid);
189360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = set_optval6(optptr, DHCP6_OPT_CLIENTID, client_duid,
189460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                client_duid_len);
189560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optlen += (client_duid_len + 4);
1896c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh            memcpy(client_lla, (*(struct optval_duid_llt*)client_duid).lladdr,
189760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                sizeof(client_lla));
189860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
189960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            //Receive: Identity Association for Non-temporary Address
190060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            if(get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
190160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  DHCP6_OPT_IA_NA, &client_ia_na_len, &client_ia_na)) {
190260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              uint16_t ia_addr_len = 0, status_code_len = 0;
190360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              void *ia_addr, *status_code;
1904c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh              uint16_t server_ia_na_len = sizeof(struct optval_ia_na);
190560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              char *status_code_msg;
190660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
190760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //Check IA Address
1908c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh              get_optval6((uint8_t*)(*(struct optval_ia_na*)client_ia_na).optval,
190960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  DHCP6_OPT_IA_ADDR, &ia_addr_len, &ia_addr);
191060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              struct optval_ia_addr *ia_addr_p = (struct optval_ia_addr*)ia_addr;
191160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              if(verifyip6_in_lease((*ia_addr_p).ipv6_addr, client_duid,
191260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                    DHCP6_OPT_IA_NA, (*(struct optval_ia_na*)client_ia_na).iaid)
191360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  == -1) {
191460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                server_ia_na_len += (ia_addr_len + 4);
191560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                //Add Status Code
191660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                status_code_msg = xstrdup("Assigned an address.");
191760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                status_code_len = strlen(status_code_msg) + 1;
191860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                status_code = xzalloc(status_code_len);
191960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                struct optval_status_code *status_code_p =
192060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  (struct optval_status_code*)status_code;
192160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                (*status_code_p).status_code = htons(DHCP6_STATUS_SUCCESS);
1922c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh                memcpy((*status_code_p).status_msg, status_code_msg,
192360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                    status_code_len);
192460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                server_ia_na_len += (status_code_len+4);
192560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              } else {
192660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                //TODO send failed status code
192760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                break;
192860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              }
192960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
193060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //combine options
193160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              server_ia_na = xzalloc(server_ia_na_len);
193260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              struct optval_ia_na *ia_na_p = (struct optval_ia_na*)server_ia_na;
193360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*ia_na_p).iaid = (*(struct optval_ia_na*)client_ia_na).iaid;
193460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*ia_na_p).t1 = gconfig.t1;
193560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              (*ia_na_p).t2 = gconfig.t2;
193660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
1937c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh              uint8_t* ia_na_optptr = (*ia_na_p).optval;
193860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              ia_na_optptr = set_optval6(ia_na_optptr, DHCP6_OPT_IA_ADDR,
193960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  ia_addr, ia_addr_len);
194060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              free(ia_addr);
194160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
194260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              if(status_code_len) {
194360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                ia_na_optptr = set_optval6(ia_na_optptr, DHCP6_OPT_STATUS_CODE,
194460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                    status_code, status_code_len);
194560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                free(status_code);
194660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              }
194760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
194860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //Response: Identity Association for Non-temporary Address
194960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              //(Status Code added)
195060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              optptr = set_optval6(optptr, DHCP6_OPT_IA_NA,
195160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                  server_ia_na, server_ia_na_len);
195260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              optlen += (server_ia_na_len + 4);
195360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              free(client_ia_na);free(server_ia_na);
195460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            }
195560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
195660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            //Receive: Server Identifier (DUID)
195760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_optval6((uint8_t*)&gstate.rcvd.rcvd_pkt6.options,
195860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP6_OPT_SERVERID, &server_duid_len, &server_duid);
195960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = set_optval6(optptr, DHCP6_OPT_SERVERID,
196060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                server_duid, server_duid_len);
196160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optlen += (server_duid_len + 4);
196260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
196360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            free(client_duid); free(server_duid);
196460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
196560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            send_packet6(0, client_lla, optlen);
196660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            write_lease6file();
196760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            break;
1968c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh          case DHCP6DECLINE:  //TODO
1969c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh          case DHCP6RENEW:    //TODO
1970c9e2a656c7305fac00a5a8c09201e1e39fea6a1bYeongdeok Suh          case DHCP6REBIND:   //TODO
197160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          case DHCP6RELEASE:
197260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            dbg("Message Type: DHCP6RELEASE\n");
197360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = prepare_send_pkt6(DHCP6REPLY);
197460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            break;
197560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          default:
197660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            dbg("Message Type : %u\n", gstate.rqcode);
197760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            break;
197860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        }
197960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
198060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh      } else {
198160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        if(read_packet() < 0) {
198260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          open_listensock();
198360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          continue;
198460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        }
198560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        waited += time(NULL) - timestmp;
198660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
198760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        get_optval((uint8_t*)&gstate.rcvd.rcvd_pkt.options,
198860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            DHCP_OPT_MESSAGE_TYPE, &gstate.rqcode);
198960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        if (gstate.rqcode == 0 || gstate.rqcode < DHCPDISCOVER
199060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            || gstate.rqcode > DHCPINFORM) {
199160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          dbg("no or bad message type option, ignoring packet.\n");
199260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          continue;
199360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        }
199460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
199560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            DHCP_OPT_SERVER_ID, &serverid);
199660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        if (serverid && (serverid != gconfig.server_nip)) {
199760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          dbg("server ID doesn't match, ignoring packet.\n");
199860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          continue;
199960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        }
200060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh
200160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        waited += time(NULL) - timestmp;
200260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        switch (gstate.rqcode) {
200360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          case DHCPDISCOVER:
200460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            msgtype = DHCPOFFER;
200560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            dbg("Message Type : DHCPDISCOVER\n");
200660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
200760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP_OPT_REQUESTED_IP, &requested_nip);
200860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
200960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP_OPT_HOST_NAME, &hstname);
201060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            reqested_lease = gconfig.offer_time;
201160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_reqparam(&gstate.rqopt);
201260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = prepare_send_pkt();
201360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            gstate.send.send_pkt.yiaddr = getip_from_pool(requested_nip,
201460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                gstate.rcvd.rcvd_pkt.chaddr, &reqested_lease, hstname);
201560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            if(!gstate.send.send_pkt.yiaddr){
201660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              msgtype = DHCPNAK;
201760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
201860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              send_packet(1);
201960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              break;
202060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            }
202160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
202260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP_OPT_LEASE_TIME, &reqested_lease);
202360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            reqested_lease = htonl(get_lease(reqested_lease + time(NULL)));
2024415c960b22b4084057577fc371510864378354ddRob Landley            optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
202560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = set_optval(optptr, DHCP_OPT_SERVER_ID, &gconfig.server_nip, 4);
202660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = set_optval(optptr, DHCP_OPT_LEASE_TIME, &reqested_lease, 4);
202760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = set_reqparam(optptr, gstate.rqopt);
2028415c960b22b4084057577fc371510864378354ddRob Landley            send_packet(1);
2029415c960b22b4084057577fc371510864378354ddRob Landley            break;
203060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          case DHCPREQUEST:
203160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            msgtype = DHCPACK;
203260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            dbg("Message Type : DHCPREQUEST\n");
203360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = prepare_send_pkt();
203460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
203560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP_OPT_REQUESTED_IP, &requested_nip);
203660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
203760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP_OPT_LEASE_TIME, &reqested_lease);
203860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
203960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP_OPT_HOST_NAME, &hstname);
204060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            gstate.send.send_pkt.yiaddr = getip_from_pool(requested_nip,
204160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                gstate.rcvd.rcvd_pkt.chaddr, &reqested_lease, hstname);
204260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            if (!serverid) reqested_lease = gconfig.max_lease_sec;
204360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            if (!gstate.send.send_pkt.yiaddr) {
204460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              msgtype = DHCPNAK;
204560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
204660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              send_packet(1);
204760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh              break;
204860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            }
2049415c960b22b4084057577fc371510864378354ddRob Landley            optptr = set_optval(optptr, DHCP_OPT_MESSAGE_TYPE, &msgtype, 1);
205060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = set_optval(optptr, DHCP_OPT_SERVER_ID, &gconfig.server_nip, 4);
205160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            reqested_lease = htonl(reqested_lease);
205260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            optptr = set_optval(optptr, DHCP_OPT_LEASE_TIME, &reqested_lease, 4);
2053415c960b22b4084057577fc371510864378354ddRob Landley            send_packet(1);
205460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            write_leasefile();
2055415c960b22b4084057577fc371510864378354ddRob Landley            break;
205660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          case DHCPDECLINE:// FALL THROUGH
205760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          case DHCPRELEASE:
205860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            dbg("Message Type : DHCPDECLINE or DHCPRELEASE \n");
205960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
206060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP_OPT_SERVER_ID, &serverid);
206160cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            if (serverid != gconfig.server_nip) break;
206260cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            get_optval((uint8_t*) &gstate.rcvd.rcvd_pkt.options,
206360cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                DHCP_OPT_REQUESTED_IP, &requested_nip);
206460cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            delip_from_lease(requested_nip, gstate.rcvd.rcvd_pkt.chaddr,
206560cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh                (gstate.rqcode==DHCPRELEASE)?0:gconfig.decline_time);
206660cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            break;
206760cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh          default:
206860cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            dbg("Message Type : %u\n", gstate.rqcode);
206960cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh            break;
207060cdc06c4825de7688a3879892bf442e0e2f282aYeongdeok Suh        }
2071415c960b22b4084057577fc371510864378354ddRob Landley      }
2072415c960b22b4084057577fc371510864378354ddRob Landley    }
2073415c960b22b4084057577fc371510864378354ddRob Landley  }
2074415c960b22b4084057577fc371510864378354ddRob Landley}
2075