2011-03-30 21:06:27 +05:30
|
|
|
/* ifchange.c - functions to call the interface change daemon
|
2010-11-12 14:32:18 +05:30
|
|
|
*
|
2014-03-10 10:22:56 +05:30
|
|
|
* Copyright (c) 2004-2014 Nicholas J. Kain <njkain at gmail dot com>
|
2011-07-25 12:00:57 +05:30
|
|
|
* All rights reserved.
|
2010-11-12 14:32:18 +05:30
|
|
|
*
|
2011-07-25 12:00:57 +05:30
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
2010-11-12 14:32:18 +05:30
|
|
|
*
|
2011-07-25 12:00:57 +05:30
|
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer.
|
2010-11-12 14:32:18 +05:30
|
|
|
*
|
2011-07-25 12:00:57 +05:30
|
|
|
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
|
|
* and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
2010-11-12 14:32:18 +05:30
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
2014-03-19 16:12:39 +05:30
|
|
|
#include <stdbool.h>
|
2010-11-12 14:32:18 +05:30
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <errno.h>
|
2014-03-19 15:37:01 +05:30
|
|
|
#include <limits.h>
|
2014-03-31 02:32:48 +05:30
|
|
|
#include "nk/log.h"
|
|
|
|
#include "nk/io.h"
|
2010-11-12 14:32:18 +05:30
|
|
|
|
|
|
|
#include "options.h"
|
2014-03-13 01:54:02 +05:30
|
|
|
#include "ndhc.h"
|
2011-07-02 13:21:44 +05:30
|
|
|
#include "dhcp.h"
|
2010-11-12 14:32:18 +05:30
|
|
|
#include "options.h"
|
2011-03-31 08:47:27 +05:30
|
|
|
#include "arp.h"
|
2010-12-24 20:42:41 +05:30
|
|
|
#include "ifchange.h"
|
2010-11-12 14:32:18 +05:30
|
|
|
|
2011-07-05 07:40:14 +05:30
|
|
|
static struct dhcpmsg cfg_packet; // Copy of the current configuration packet.
|
2011-07-05 07:10:32 +05:30
|
|
|
|
2014-03-19 15:37:01 +05:30
|
|
|
static int ifcmd_raw(char *buf, size_t buflen, char *optname,
|
|
|
|
char *optdata, ssize_t optlen)
|
|
|
|
{
|
2014-03-21 09:20:58 +05:30
|
|
|
if (!optdata) {
|
|
|
|
log_warning("%s: (%s) '%s' option has no data",
|
|
|
|
client_config.interface, __func__, optname);
|
2014-03-19 15:37:01 +05:30
|
|
|
return -1;
|
2014-03-21 09:20:58 +05:30
|
|
|
}
|
|
|
|
if (optlen > INT_MAX || optlen < 0) {
|
|
|
|
log_warning("%s: (%s) '%s' option optlen out of bounds",
|
|
|
|
client_config.interface, __func__, optname);
|
2014-03-19 15:37:01 +05:30
|
|
|
return -1;
|
2014-03-21 09:20:58 +05:30
|
|
|
}
|
|
|
|
if (buflen < strlen(optname) + optlen + 3) {
|
|
|
|
log_warning("%s: (%s) '%s' option buf too short",
|
|
|
|
client_config.interface, __func__, optname);
|
2014-03-19 15:37:01 +05:30
|
|
|
return -1;
|
2014-03-21 09:20:58 +05:30
|
|
|
}
|
2014-03-19 15:37:01 +05:30
|
|
|
int ioptlen = (int)optlen;
|
|
|
|
ssize_t olen = snprintf(buf, buflen, "%s:%.*s;",
|
|
|
|
optname, ioptlen, optdata);
|
2014-03-19 15:44:50 +05:30
|
|
|
if (olen < 0 || (size_t)olen >= buflen) {
|
|
|
|
log_warning("%s: (%s) '%s' option would truncate, so it was dropped.",
|
|
|
|
client_config.interface, __func__, optname);
|
|
|
|
memset(buf, 0, buflen);
|
|
|
|
return -1;
|
|
|
|
}
|
2014-03-19 15:37:01 +05:30
|
|
|
return olen;
|
|
|
|
}
|
|
|
|
|
2014-03-19 16:04:29 +05:30
|
|
|
static int ifcmd_bytes(char *buf, size_t buflen, char *optname,
|
|
|
|
uint8_t *optdata, ssize_t optlen)
|
2014-03-19 15:37:01 +05:30
|
|
|
{
|
|
|
|
return ifcmd_raw(buf, buflen, optname, (char *)optdata, optlen);
|
|
|
|
}
|
|
|
|
|
2014-03-19 16:04:29 +05:30
|
|
|
static int ifcmd_u8(char *buf, size_t buflen, char *optname,
|
|
|
|
uint8_t *optdata, ssize_t optlen)
|
2010-11-12 14:32:18 +05:30
|
|
|
{
|
2011-07-26 15:45:21 +05:30
|
|
|
if (!optdata || optlen < 1)
|
|
|
|
return -1;
|
2014-03-19 15:37:01 +05:30
|
|
|
char numbuf[16];
|
|
|
|
uint8_t c = optdata[0];
|
|
|
|
ssize_t olen = snprintf(numbuf, sizeof numbuf, "%c", c);
|
|
|
|
if (olen < 0 || (size_t)olen >= sizeof numbuf)
|
|
|
|
return -1;
|
|
|
|
return ifcmd_raw(buf, buflen, optname, numbuf, strlen(numbuf));
|
2011-07-26 15:45:21 +05:30
|
|
|
}
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2014-03-19 16:04:29 +05:30
|
|
|
static int ifcmd_u16(char *buf, size_t buflen, char *optname,
|
|
|
|
uint8_t *optdata, ssize_t optlen)
|
2011-07-26 15:45:21 +05:30
|
|
|
{
|
|
|
|
if (!optdata || optlen < 2)
|
2010-11-13 06:13:16 +05:30
|
|
|
return -1;
|
2014-03-19 15:37:01 +05:30
|
|
|
char numbuf[16];
|
2011-07-26 15:45:21 +05:30
|
|
|
uint16_t v;
|
|
|
|
memcpy(&v, optdata, 2);
|
|
|
|
v = ntohs(v);
|
2014-03-19 15:37:01 +05:30
|
|
|
ssize_t olen = snprintf(numbuf, sizeof numbuf, "%hu", v);
|
|
|
|
if (olen < 0 || (size_t)olen >= sizeof numbuf)
|
|
|
|
return -1;
|
|
|
|
return ifcmd_raw(buf, buflen, optname, numbuf, strlen(numbuf));
|
2011-07-26 15:45:21 +05:30
|
|
|
}
|
2011-03-30 20:09:11 +05:30
|
|
|
|
2014-03-19 16:04:29 +05:30
|
|
|
static int ifcmd_s32(char *buf, size_t buflen, char *optname,
|
|
|
|
uint8_t *optdata, ssize_t optlen)
|
2011-07-26 15:45:21 +05:30
|
|
|
{
|
|
|
|
if (!optdata || optlen < 4)
|
|
|
|
return -1;
|
2014-03-19 15:37:01 +05:30
|
|
|
char numbuf[16];
|
2011-07-26 15:45:21 +05:30
|
|
|
int32_t v;
|
|
|
|
memcpy(&v, optdata, 4);
|
|
|
|
v = ntohl(v);
|
2014-03-19 15:37:01 +05:30
|
|
|
ssize_t olen = snprintf(numbuf, sizeof numbuf, "%d", v);
|
|
|
|
if (olen < 0 || (size_t)olen >= sizeof numbuf)
|
|
|
|
return -1;
|
|
|
|
return ifcmd_raw(buf, buflen, optname, numbuf, strlen(numbuf));
|
2011-07-26 15:45:21 +05:30
|
|
|
}
|
|
|
|
|
2014-03-19 16:04:29 +05:30
|
|
|
static int ifcmd_ip(char *buf, size_t buflen, char *optname,
|
|
|
|
uint8_t *optdata, ssize_t optlen)
|
2011-07-26 15:45:21 +05:30
|
|
|
{
|
|
|
|
if (!optdata || optlen < 4)
|
|
|
|
return -1;
|
2014-03-19 15:37:01 +05:30
|
|
|
char ipbuf[INET_ADDRSTRLEN];
|
2014-03-20 04:44:38 +05:30
|
|
|
inet_ntop(AF_INET, optdata, ipbuf, sizeof ipbuf);
|
2014-03-19 15:37:01 +05:30
|
|
|
return ifcmd_raw(buf, buflen, optname, ipbuf, strlen(ipbuf));
|
2011-07-26 15:45:21 +05:30
|
|
|
}
|
2011-03-30 20:09:11 +05:30
|
|
|
|
2014-03-19 16:04:29 +05:30
|
|
|
static int ifcmd_iplist(char *out, size_t outlen, char *optname,
|
|
|
|
uint8_t *optdata, ssize_t optlen)
|
2011-07-26 15:45:21 +05:30
|
|
|
{
|
2014-03-19 15:37:01 +05:30
|
|
|
char buf[2048];
|
2011-07-26 15:45:21 +05:30
|
|
|
char ipbuf[INET_ADDRSTRLEN];
|
2014-03-19 15:37:01 +05:30
|
|
|
size_t bufoff = 0;
|
|
|
|
size_t optoff = 0;
|
|
|
|
|
2013-05-10 23:16:58 +05:30
|
|
|
if (!optdata || optlen < 4)
|
2011-07-26 15:45:21 +05:30
|
|
|
return -1;
|
2014-03-19 15:37:01 +05:30
|
|
|
|
2014-03-20 04:44:38 +05:30
|
|
|
inet_ntop(AF_INET, optdata + optoff, ipbuf, sizeof ipbuf);
|
2014-03-21 09:20:58 +05:30
|
|
|
ssize_t wc = snprintf(buf + bufoff, sizeof buf, "%s", ipbuf);
|
2014-03-19 15:37:01 +05:30
|
|
|
if (wc < 0 || (size_t)wc >= sizeof buf)
|
|
|
|
return -1;
|
|
|
|
optoff += 4;
|
|
|
|
bufoff += wc;
|
|
|
|
while (optlen - optoff >= 4) {
|
2014-03-20 04:44:38 +05:30
|
|
|
inet_ntop(AF_INET, optdata + optoff, ipbuf, sizeof ipbuf);
|
2014-03-19 15:37:01 +05:30
|
|
|
wc = snprintf(buf + bufoff, sizeof buf, ",%s", ipbuf);
|
|
|
|
if (wc < 0 || (size_t)wc >= sizeof buf)
|
|
|
|
return -1;
|
|
|
|
optoff += 4;
|
|
|
|
bufoff += wc;
|
|
|
|
}
|
|
|
|
return ifcmd_raw(out, outlen, optname, buf, strlen(buf));
|
2011-07-26 15:45:21 +05:30
|
|
|
}
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2014-03-19 16:10:42 +05:30
|
|
|
static int ifchd_cmd(char *b, size_t bl, uint8_t *od, ssize_t ol, uint8_t code)
|
2011-07-26 15:45:21 +05:30
|
|
|
{
|
|
|
|
switch (code) {
|
2014-03-19 16:10:42 +05:30
|
|
|
case DCODE_ROUTER: return ifcmd_ip(b, bl, "routr", od, ol);
|
|
|
|
case DCODE_DNS: return ifcmd_iplist(b, bl, "dns", od, ol);
|
|
|
|
case DCODE_LPRSVR: return ifcmd_iplist(b, bl, "lpr", od, ol);
|
|
|
|
case DCODE_NTPSVR: return ifcmd_iplist(b, bl, "ntp", od, ol);
|
|
|
|
case DCODE_WINS: return ifcmd_iplist(b, bl, "wins", od, ol);
|
|
|
|
case DCODE_HOSTNAME: return ifcmd_bytes(b, bl, "host", od, ol);
|
|
|
|
case DCODE_DOMAIN: return ifcmd_bytes(b, bl, "dom", od, ol);
|
|
|
|
case DCODE_TIMEZONE: return ifcmd_s32(b, bl, "tzone", od, ol);
|
|
|
|
case DCODE_MTU: return ifcmd_u16(b, bl, "mtu", od, ol);
|
|
|
|
case DCODE_IPTTL: return ifcmd_u8(b, bl, "ipttl", od, ol);
|
|
|
|
default: break;
|
2010-11-13 01:03:17 +05:30
|
|
|
}
|
2014-04-04 13:31:49 +05:30
|
|
|
log_warning("%s: Invalid option code (%c) for ifchd cmd.",
|
|
|
|
client_config.interface, code);
|
2014-03-19 16:10:42 +05:30
|
|
|
return -1;
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|
|
|
|
|
2014-03-17 12:25:47 +05:30
|
|
|
static void pipewrite(struct client_state_t *cs, const char *buf, size_t count)
|
2010-11-12 14:32:18 +05:30
|
|
|
{
|
2014-03-17 12:25:47 +05:30
|
|
|
cs->ifchWorking = 1;
|
2014-04-06 15:54:13 +05:30
|
|
|
ssize_t r = safe_write(pToIfchW, buf, count);
|
2014-04-04 13:31:49 +05:30
|
|
|
if (r < 0 || (size_t)r != count) {
|
|
|
|
log_error("%s: (%s) write failed: %d", client_config.interface);
|
2014-03-15 14:02:44 +05:30
|
|
|
return;
|
|
|
|
}
|
2014-04-04 13:31:49 +05:30
|
|
|
log_line("%s: Sent to ifchd: '%s'", client_config.interface, buf);
|
2010-11-13 01:03:17 +05:30
|
|
|
}
|
2010-11-12 14:32:18 +05:30
|
|
|
|
2014-03-17 12:25:47 +05:30
|
|
|
void ifchange_deconfig(struct client_state_t *cs)
|
2010-11-12 14:32:18 +05:30
|
|
|
{
|
2010-11-13 01:03:17 +05:30
|
|
|
char buf[256];
|
|
|
|
|
2014-03-17 12:25:47 +05:30
|
|
|
if (cs->ifDeconfig)
|
2011-07-05 07:40:14 +05:30
|
|
|
return;
|
2014-03-17 12:25:47 +05:30
|
|
|
cs->ifDeconfig = 1;
|
2011-07-05 07:40:14 +05:30
|
|
|
|
2014-03-10 10:22:56 +05:30
|
|
|
snprintf(buf, sizeof buf, "ip4:0.0.0.0,255.255.255.255;");
|
2014-04-04 13:31:49 +05:30
|
|
|
log_line("%s: Resetting IP configuration.", client_config.interface);
|
2014-03-17 12:25:47 +05:30
|
|
|
pipewrite(cs, buf, strlen(buf));
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2011-07-05 07:10:32 +05:30
|
|
|
memset(&cfg_packet, 0, sizeof cfg_packet);
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|
|
|
|
|
2011-07-06 04:55:19 +05:30
|
|
|
static size_t send_client_ip(char *out, size_t olen, struct dhcpmsg *packet)
|
|
|
|
{
|
2014-03-09 23:27:37 +05:30
|
|
|
uint8_t optdata[MAX_DOPT_SIZE], olddata[MAX_DOPT_SIZE];
|
2014-03-19 16:02:13 +05:30
|
|
|
char ip[INET_ADDRSTRLEN], sn[INET_ADDRSTRLEN], bc[INET_ADDRSTRLEN];
|
2014-03-09 23:27:37 +05:30
|
|
|
ssize_t optlen, oldlen;
|
|
|
|
bool change_ipaddr = false;
|
|
|
|
bool have_subnet = false;
|
|
|
|
bool change_subnet = false;
|
|
|
|
bool have_bcast = false;
|
|
|
|
bool change_bcast = false;
|
|
|
|
|
|
|
|
if (memcmp(&packet->yiaddr, &cfg_packet.yiaddr, sizeof packet->yiaddr))
|
|
|
|
change_ipaddr = true;
|
2014-03-20 04:44:38 +05:30
|
|
|
inet_ntop(AF_INET, &packet->yiaddr, ip, sizeof ip);
|
2014-03-09 23:27:37 +05:30
|
|
|
|
|
|
|
optlen = get_dhcp_opt(packet, DCODE_SUBNET, optdata, sizeof optdata);
|
|
|
|
if (optlen >= 4) {
|
|
|
|
have_subnet = true;
|
2014-03-20 04:44:38 +05:30
|
|
|
inet_ntop(AF_INET, optdata, sn, sizeof sn);
|
2014-03-09 23:27:37 +05:30
|
|
|
oldlen = get_dhcp_opt(&cfg_packet, DCODE_SUBNET, olddata,
|
|
|
|
sizeof olddata);
|
|
|
|
if (oldlen != optlen || memcmp(optdata, olddata, optlen))
|
|
|
|
change_subnet = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
optlen = get_dhcp_opt(packet, DCODE_BROADCAST, optdata, sizeof optdata);
|
|
|
|
if (optlen >= 4) {
|
|
|
|
have_bcast = true;
|
2014-03-20 04:44:38 +05:30
|
|
|
inet_ntop(AF_INET, optdata, bc, sizeof bc);
|
2014-03-09 23:27:37 +05:30
|
|
|
oldlen = get_dhcp_opt(&cfg_packet, DCODE_BROADCAST, olddata,
|
|
|
|
sizeof olddata);
|
|
|
|
if (oldlen != optlen || memcmp(optdata, olddata, optlen))
|
|
|
|
change_bcast = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nothing to change.
|
|
|
|
if (!change_ipaddr && !change_subnet && !change_bcast)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!have_subnet) {
|
2014-03-19 15:30:08 +05:30
|
|
|
static char snClassC[] = "255.255.255.0";
|
2014-04-04 13:31:49 +05:30
|
|
|
log_line("%s: Server did not send a subnet mask. Assuming 255.255.255.0.",
|
|
|
|
client_config.interface);
|
2014-03-09 23:27:37 +05:30
|
|
|
memcpy(sn, snClassC, sizeof snClassC);
|
|
|
|
}
|
|
|
|
|
2014-03-19 16:02:13 +05:30
|
|
|
int snlen;
|
2014-03-09 23:27:37 +05:30
|
|
|
if (have_bcast) {
|
2014-03-19 16:02:13 +05:30
|
|
|
snlen = snprintf(out, olen, "ip4:%s,%s,%s;", ip, sn, bc);
|
2014-03-09 23:27:37 +05:30
|
|
|
} else {
|
2014-03-19 16:02:13 +05:30
|
|
|
snlen = snprintf(out, olen, "ip4:%s,%s;", ip, sn);
|
2014-03-09 23:27:37 +05:30
|
|
|
}
|
2014-03-19 16:02:13 +05:30
|
|
|
if (snlen < 0 || (size_t)snlen >= olen) {
|
|
|
|
log_warning("%s: (%s) ip4 command would truncate so it was dropped.",
|
|
|
|
client_config.interface, __func__);
|
|
|
|
memset(out, 0, olen);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return snlen;
|
2011-07-06 04:55:19 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
static size_t send_cmd(char *out, size_t olen, struct dhcpmsg *packet,
|
|
|
|
uint8_t code)
|
2010-11-13 01:03:17 +05:30
|
|
|
{
|
2011-07-27 17:09:45 +05:30
|
|
|
uint8_t optdata[MAX_DOPT_SIZE], olddata[MAX_DOPT_SIZE];
|
2011-07-05 07:10:32 +05:30
|
|
|
ssize_t optlen, oldlen;
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2010-11-13 06:13:16 +05:30
|
|
|
if (!packet)
|
2011-07-06 04:55:19 +05:30
|
|
|
return 0;
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2011-07-27 17:09:45 +05:30
|
|
|
optlen = get_dhcp_opt(packet, code, optdata, sizeof optdata);
|
2011-07-05 05:37:16 +05:30
|
|
|
if (!optlen)
|
2011-07-06 04:55:19 +05:30
|
|
|
return 0;
|
2011-07-27 17:09:45 +05:30
|
|
|
oldlen = get_dhcp_opt(&cfg_packet, code, olddata, sizeof olddata);
|
2011-07-05 07:10:32 +05:30
|
|
|
if (oldlen == optlen && !memcmp(optdata, olddata, optlen))
|
2011-07-06 04:55:19 +05:30
|
|
|
return 0;
|
2014-03-19 16:02:13 +05:30
|
|
|
int r = ifchd_cmd(out, olen, optdata, optlen, code);
|
|
|
|
return r > 0 ? r : 0;
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|
|
|
|
|
2014-03-17 12:25:47 +05:30
|
|
|
void ifchange_bind(struct client_state_t *cs, struct dhcpmsg *packet)
|
2010-11-12 14:32:18 +05:30
|
|
|
{
|
2011-07-06 04:55:19 +05:30
|
|
|
char buf[2048];
|
2014-03-19 16:02:13 +05:30
|
|
|
size_t bo;
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2010-11-14 05:37:00 +05:30
|
|
|
if (!packet)
|
|
|
|
return;
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2014-03-15 14:02:44 +05:30
|
|
|
memset(buf, 0, sizeof buf);
|
2014-03-19 16:02:13 +05:30
|
|
|
bo = send_client_ip(buf, sizeof buf, packet);
|
|
|
|
bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_ROUTER);
|
|
|
|
bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_DNS);
|
|
|
|
bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_HOSTNAME);
|
|
|
|
bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_DOMAIN);
|
|
|
|
bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_MTU);
|
|
|
|
bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_WINS);
|
|
|
|
if (bo)
|
|
|
|
pipewrite(cs, buf, bo);
|
2010-11-13 01:03:17 +05:30
|
|
|
|
2014-03-17 12:25:47 +05:30
|
|
|
cs->ifDeconfig = 0;
|
2011-07-05 07:10:32 +05:30
|
|
|
memcpy(&cfg_packet, packet, sizeof cfg_packet);
|
2010-11-12 14:32:18 +05:30
|
|
|
}
|