/*
* Copyright: 2005 Axis Communications AB
*
* This file is part of Mini DHCP6.
*
* mdhcp6 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* mdhcp6 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with mdhcp6. If not, see .
*
* dhcpv6 lease handling.
*
* Authors: Edgar E. Iglesias
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "msgbuf.h"
#include "dhcpv6.h"
#include "optionmap.h"
#include "lease.h"
#undef D
#define D(x)
static inline FILE *lease_open_file(char *filename) {
FILE *fp;
if (!filename)
return NULL;
if ((fp = fopen(filename, "rb+")) == NULL) {
if ((fp = fopen(filename, "wb+")) == NULL) {
perror(filename);
return NULL;
}
}
return fp;
}
void lease_set_server(struct lease_t *lz,
struct dhcpv6_nodeid_t *server) {
dhcpv6_free_nodeid(lz->server);
lz->server = server;
}
void lease_set_ia(struct lease_t *lz,
struct dhcpv6_option_ia_t *ia) {
dhcpv6_free_ia(lz->ia);
lz->ia = ia;
}
/* returns non-zero if any options where dropped. This is useful for the caller
to know if it needs to let notify config changes. */
int lease_drop(struct lease_t *lease) {
int r = 0;
char *p;
char *end;
lease_set_ia(lease, NULL);
lease_set_server(lease, NULL);
/* Clear and count addr. */
p = (char *) &lease->addr;
end = p + sizeof lease->addr;
while (p < end) {
if (*p)
r = 1;
*p = 0;
p++;
}
r |= optionmap_drop(lease->omap,
sizeof lease->omap
/ sizeof lease->omap[0]);
lease->aquired = 0;
memset(&lease->addr, 0, sizeof lease->addr);
return r;
}
void lease_cleanup(struct lease_t *lease) {
lease_set_ia(lease, NULL);
lease_set_server(lease, NULL);
memset(&lease->addr, 0, sizeof lease->addr);
memset(&lease->oldaddr, 0, sizeof lease->oldaddr);
optionmap_cleanup(lease->omap,
sizeof lease->omap
/ sizeof lease->omap[0]);
}
/*
* read lease info from file
*/
void lease_readfile(char *filename, struct lease_t *lease) {
char addrstr[INET6_ADDRSTRLEN];
size_t r;
FILE *fp;
assert(lease);
if ((fp = lease_open_file(filename)) == NULL)
return;
/* sync from file */
if (fgets(addrstr, sizeof addrstr, fp)) {
unsigned char duidbuf[128];
size_t len = strlen(addrstr);
addrstr[len - 1] = 0; /* chop the newline */
r = inet_pton(AF_INET6, addrstr, &lease->addr);
if (r != -1) {
inet_ntop(AF_INET6, &lease->addr,
addrstr, INET6_ADDRSTRLEN);
D(printf("synccore %s\n", addrstr));
}
r = fread(duidbuf, 1, sizeof duidbuf, fp);
if (r > 0)
lease->server = dhcpv6_parse_nodeid(duidbuf, r);
lease->needsreconfig = 1;
}
memcpy(&lease->syncedaddr, &lease->addr, sizeof lease->addr);
fclose(fp);
}
/*
* synchronize the current lease with the one on the leasefile
*/
void lease_sync(char *filename, struct lease_t *lease) {
char addrstr[INET6_ADDRSTRLEN];
int insync;
FILE *fp;
if (!lease->ia || !lease->server)
return;
insync = !memcmp(&lease->syncedaddr, &lease->addr, sizeof lease->addr);
inet_ntop(AF_INET6, &lease->addr,
addrstr, INET6_ADDRSTRLEN);
if (!insync) {
struct msgbuf_t *msg;
if ((fp = lease_open_file(filename)) == NULL) {
D(printf("%s: no leasefile\n", __func__));
return;
}
/* update file */
D(printf("syncfile - %s\n", addrstr));
rewind(fp);
fprintf(fp, "%s\n", addrstr);
msg = msgbuf_new(lease->server->duidlen);
dhcpv6_append_node_id_opt(&msg, DH6OPT_SERVERID,
lease->server);
fwrite(msg->buf + 4, 1, msg->pos - 4, fp);
msgbuf_free(msg);
fflush(fp);
lease->needsreconfig = 1;
/* synced */
memcpy(&lease->syncedaddr, &lease->addr, sizeof lease->addr);
fclose(fp);
}
}
int lease_test_and_clear_reconfig(struct lease_t *lease) {
int needsreconfig = lease->needsreconfig;
lease->needsreconfig = 0;
needsreconfig |=optionmap_test_and_clear_reconfig(lease->omap,
sizeof lease->omap /
sizeof *lease->omap);
return needsreconfig;
}
void lease_update_oldvalues(struct lease_t *lease) {
if (lease->aquired)
memcpy(&lease->oldaddr, &lease->addr, sizeof lease->addr);
else
memset(&lease->oldaddr, 0, sizeof lease->oldaddr);
memset(&lease->addr, 0, sizeof lease->addr);
optionmap_update_oldvalues(lease->omap,
sizeof lease->omap
/ sizeof lease->omap[0]);
}
/*
* fabricate an environment for the configuration scripts process.
* Tipically called from a separate process.
*/
#undef ADDRENVNAME
#define ADDRENVNAME "dh6_addr="
#undef OLDADDRENVNAME
#define OLDADDRENVNAME "dh6_addr_old="
void lease_create_environ(struct lease_t *lease) {
/*
* this mess makes it possible for the compiler to optimze the strlen..
*/
static char addrstr[INET6_ADDRSTRLEN + 20] = ADDRENVNAME;
static char oldaddrstr[INET6_ADDRSTRLEN + 20] = OLDADDRENVNAME;
char *str = addrstr + strlen(ADDRENVNAME);
char *oldstr = oldaddrstr + strlen(OLDADDRENVNAME);
assert((strlen(OLDADDRENVNAME) + INET6_ADDRSTRLEN + 1)
< sizeof(oldaddrstr));
assert((strlen(ADDRENVNAME) + INET6_ADDRSTRLEN+1) < sizeof(addrstr));
inet_ntop(AF_INET6, &lease->addr, str, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &lease->oldaddr, oldstr, INET6_ADDRSTRLEN);
D(printf("%s str=%s oldstr=%s ia=%x server=%x\n",
__func__, str, oldstr, lease->ia, lease->server));
if (lease->ia
&& lease->server
&& (memcmp(&in6addr_any, &lease->addr, sizeof lease->addr) != 0))
putenv(addrstr);
if (memcmp(&in6addr_any, &lease->oldaddr, sizeof lease->addr) != 0)
putenv(oldaddrstr);
{
static char raflags[32];
static char state[32];
snprintf(raflags, sizeof raflags,
"dh6_raflags=%x", lease->raflags);
putenv(raflags);
snprintf(state, sizeof state,
"dh6_state=%x", lease->state);
putenv(state);
}
optionmap_create_environ(lease->omap,
sizeof lease->omap
/ sizeof lease->omap[0]);
}