Separate event state gathering from action dispatch in main epoll loop.
This is the first step towards using coroutines.
This commit is contained in:
parent
658d2954b8
commit
61387408d0
84
src/arp.c
84
src/arp.c
@ -62,52 +62,7 @@ int arp_probe_max = 2000; // maximum delay until repeated probe (ms)
|
|||||||
#define RATE_LIMIT_INTERVAL 60000 // delay between successive attempts
|
#define RATE_LIMIT_INTERVAL 60000 // delay between successive attempts
|
||||||
#define DEFEND_INTERVAL 10000 // minimum interval between defensive ARPs
|
#define DEFEND_INTERVAL 10000 // minimum interval between defensive ARPs
|
||||||
|
|
||||||
typedef enum {
|
struct arp_data garp = {
|
||||||
AS_NONE = 0, // Nothing to react to wrt ARP
|
|
||||||
AS_COLLISION_CHECK, // Checking to see if another host has our IP before
|
|
||||||
// accepting a new lease.
|
|
||||||
AS_GW_CHECK, // Seeing if the default GW still exists on the local
|
|
||||||
// segment after the hardware link was lost.
|
|
||||||
AS_GW_QUERY, // Finding the default GW MAC address.
|
|
||||||
AS_DEFENSE, // Defending our IP address (RFC5227)
|
|
||||||
AS_MAX,
|
|
||||||
} arp_state_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ASEND_COLLISION_CHECK,
|
|
||||||
ASEND_GW_PING,
|
|
||||||
ASEND_ANNOUNCE,
|
|
||||||
ASEND_MAX,
|
|
||||||
} arp_send_t;
|
|
||||||
|
|
||||||
struct arp_stats {
|
|
||||||
long long ts;
|
|
||||||
int count;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct arp_data {
|
|
||||||
struct dhcpmsg dhcp_packet; // Used only for AS_COLLISION_CHECK
|
|
||||||
struct arpMsg reply;
|
|
||||||
struct arp_stats send_stats[ASEND_MAX];
|
|
||||||
long long wake_ts[AS_MAX];
|
|
||||||
long long last_conflict_ts; // TS of the last conflicting ARP seen.
|
|
||||||
long long arp_check_start_ts; // TS of when we started the
|
|
||||||
// AS_COLLISION_CHECK state.
|
|
||||||
size_t reply_offset;
|
|
||||||
arp_state_t state;
|
|
||||||
unsigned int total_conflicts; // Total number of address conflicts on
|
|
||||||
// the interface. Never decreases.
|
|
||||||
int gw_check_initpings; // Initial count of ASEND_GW_PING when
|
|
||||||
// AS_GW_CHECK was entered.
|
|
||||||
uint16_t probe_wait_time; // Time to wait for a COLLISION_CHECK reply
|
|
||||||
// (in ms?).
|
|
||||||
bool using_bpf:1; // Is a BPF installed on the ARP socket?
|
|
||||||
bool relentless_def:1; // Don't give up defense no matter what.
|
|
||||||
bool router_replied:1;
|
|
||||||
bool server_replied:1;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct arp_data garp = {
|
|
||||||
.state = AS_NONE,
|
.state = AS_NONE,
|
||||||
.wake_ts = { -1, -1, -1, -1, -1 },
|
.wake_ts = { -1, -1, -1, -1, -1 },
|
||||||
.send_stats = {{0,0},{0,0},{0,0}},
|
.send_stats = {{0,0},{0,0},{0,0}},
|
||||||
@ -237,7 +192,7 @@ void arp_close_fd(struct client_state_t cs[static 1])
|
|||||||
garp.wake_ts[i] = -1;
|
garp.wake_ts[i] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_reopen_fd(struct client_state_t cs[static 1])
|
void arp_reopen_fd(struct client_state_t cs[static 1])
|
||||||
{
|
{
|
||||||
arp_state_t prev_state = garp.state;
|
arp_state_t prev_state = garp.state;
|
||||||
arp_min_close_fd(cs);
|
arp_min_close_fd(cs);
|
||||||
@ -406,7 +361,7 @@ static int arp_get_gw_hwaddr(struct client_state_t cs[static 1])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_failed(struct client_state_t cs[static 1])
|
void arp_failed(struct client_state_t cs[static 1])
|
||||||
{
|
{
|
||||||
log_line("%s: arp: Offered address is in use. Declining.",
|
log_line("%s: arp: Offered address is in use. Declining.",
|
||||||
client_config.interface);
|
client_config.interface);
|
||||||
@ -427,7 +382,7 @@ static void arp_failed(struct client_state_t cs[static 1])
|
|||||||
0 : RATE_LIMIT_INTERVAL);
|
0 : RATE_LIMIT_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arp_gw_failed(struct client_state_t cs[static 1])
|
void arp_gw_failed(struct client_state_t cs[static 1])
|
||||||
{
|
{
|
||||||
garp.wake_ts[AS_GW_CHECK] = -1;
|
garp.wake_ts[AS_GW_CHECK] = -1;
|
||||||
reinit_selecting(cs, 0);
|
reinit_selecting(cs, 0);
|
||||||
@ -794,31 +749,31 @@ static const arp_state_fn_t arp_states[] = {
|
|||||||
{ arp_do_invalid, 0 }, // AS_MAX
|
{ arp_do_invalid, 0 }, // AS_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
void handle_arp_response(struct client_state_t cs[static 1])
|
void arp_packet_action(struct client_state_t cs[static 1])
|
||||||
|
{
|
||||||
|
if (arp_states[garp.state].packet_fn)
|
||||||
|
arp_states[garp.state].packet_fn(cs);
|
||||||
|
arp_reply_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int arp_packet_get(struct client_state_t cs[static 1])
|
||||||
{
|
{
|
||||||
ssize_t r = 0;
|
ssize_t r = 0;
|
||||||
if (garp.reply_offset < sizeof garp.reply) {
|
if (garp.reply_offset < sizeof garp.reply) {
|
||||||
r = safe_read(cs->arpFd, (char *)&garp.reply + garp.reply_offset,
|
r = safe_read(cs->arpFd, (char *)&garp.reply + garp.reply_offset,
|
||||||
sizeof garp.reply - garp.reply_offset);
|
sizeof garp.reply - garp.reply_offset);
|
||||||
|
if (r == 0)
|
||||||
|
return ARPR_CLOSED;
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error("%s: (%s) ARP response read failed: %s",
|
log_error("%s: (%s) ARP response read failed: %s",
|
||||||
client_config.interface, __func__, strerror(errno));
|
client_config.interface, __func__, strerror(errno));
|
||||||
switch (garp.state) {
|
return ARPR_ERROR;
|
||||||
case AS_COLLISION_CHECK: arp_failed(cs); break;
|
|
||||||
case AS_GW_CHECK: arp_gw_failed(cs); break;
|
|
||||||
default: arp_reopen_fd(cs); break;
|
|
||||||
}
|
}
|
||||||
} else
|
|
||||||
garp.reply_offset += (size_t)r;
|
garp.reply_offset += (size_t)r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r <= 0) {
|
|
||||||
handle_arp_timeout(cs, curms());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (garp.reply_offset < ARP_MSG_SIZE)
|
if (garp.reply_offset < ARP_MSG_SIZE)
|
||||||
return;
|
return ARPR_NONE;
|
||||||
|
|
||||||
// Emulate the BPF filters if they are not in use.
|
// Emulate the BPF filters if they are not in use.
|
||||||
if (!garp.using_bpf &&
|
if (!garp.using_bpf &&
|
||||||
@ -826,12 +781,9 @@ void handle_arp_response(struct client_state_t cs[static 1])
|
|||||||
(garp.state == AS_DEFENSE &&
|
(garp.state == AS_DEFENSE &&
|
||||||
!arp_validate_bpf_defense(cs, &garp.reply)))) {
|
!arp_validate_bpf_defense(cs, &garp.reply)))) {
|
||||||
arp_reply_clear();
|
arp_reply_clear();
|
||||||
return;
|
return ARPR_NONE;
|
||||||
}
|
}
|
||||||
|
return ARPR_PENDING;
|
||||||
if (arp_states[garp.state].packet_fn)
|
|
||||||
arp_states[garp.state].packet_fn(cs);
|
|
||||||
arp_reply_clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform retransmission if necessary.
|
// Perform retransmission if necessary.
|
||||||
|
61
src/arp.h
61
src/arp.h
@ -58,6 +58,53 @@ extern int arp_probe_num;
|
|||||||
extern int arp_probe_min;
|
extern int arp_probe_min;
|
||||||
extern int arp_probe_max;
|
extern int arp_probe_max;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AS_NONE = 0, // Nothing to react to wrt ARP
|
||||||
|
AS_COLLISION_CHECK, // Checking to see if another host has our IP before
|
||||||
|
// accepting a new lease.
|
||||||
|
AS_GW_CHECK, // Seeing if the default GW still exists on the local
|
||||||
|
// segment after the hardware link was lost.
|
||||||
|
AS_GW_QUERY, // Finding the default GW MAC address.
|
||||||
|
AS_DEFENSE, // Defending our IP address (RFC5227)
|
||||||
|
AS_MAX,
|
||||||
|
} arp_state_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ASEND_COLLISION_CHECK,
|
||||||
|
ASEND_GW_PING,
|
||||||
|
ASEND_ANNOUNCE,
|
||||||
|
ASEND_MAX,
|
||||||
|
} arp_send_t;
|
||||||
|
|
||||||
|
struct arp_stats {
|
||||||
|
long long ts;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct arp_data {
|
||||||
|
struct dhcpmsg dhcp_packet; // Used only for AS_COLLISION_CHECK
|
||||||
|
struct arpMsg reply;
|
||||||
|
struct arp_stats send_stats[ASEND_MAX];
|
||||||
|
long long wake_ts[AS_MAX];
|
||||||
|
long long last_conflict_ts; // TS of the last conflicting ARP seen.
|
||||||
|
long long arp_check_start_ts; // TS of when we started the
|
||||||
|
// AS_COLLISION_CHECK state.
|
||||||
|
size_t reply_offset;
|
||||||
|
arp_state_t state;
|
||||||
|
unsigned int total_conflicts; // Total number of address conflicts on
|
||||||
|
// the interface. Never decreases.
|
||||||
|
int gw_check_initpings; // Initial count of ASEND_GW_PING when
|
||||||
|
// AS_GW_CHECK was entered.
|
||||||
|
uint16_t probe_wait_time; // Time to wait for a COLLISION_CHECK reply
|
||||||
|
// (in ms?).
|
||||||
|
bool using_bpf:1; // Is a BPF installed on the ARP socket?
|
||||||
|
bool relentless_def:1; // Don't give up defense no matter what.
|
||||||
|
bool router_replied:1;
|
||||||
|
bool server_replied:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct arp_data garp;
|
||||||
|
|
||||||
void set_arp_relentless_def(bool v);
|
void set_arp_relentless_def(bool v);
|
||||||
void arp_reset_send_stats(void);
|
void arp_reset_send_stats(void);
|
||||||
void arp_close_fd(struct client_state_t cs[static 1]);
|
void arp_close_fd(struct client_state_t cs[static 1]);
|
||||||
@ -66,7 +113,19 @@ int arp_check(struct client_state_t cs[static 1],
|
|||||||
int arp_gw_check(struct client_state_t cs[static 1]);
|
int arp_gw_check(struct client_state_t cs[static 1]);
|
||||||
void arp_set_defense_mode(struct client_state_t cs[static 1]);
|
void arp_set_defense_mode(struct client_state_t cs[static 1]);
|
||||||
void arp_success(struct client_state_t cs[static 1]);
|
void arp_success(struct client_state_t cs[static 1]);
|
||||||
void handle_arp_response(struct client_state_t cs[static 1]);
|
void arp_failed(struct client_state_t cs[static 1]);
|
||||||
|
void arp_gw_failed(struct client_state_t cs[static 1]);
|
||||||
|
void arp_reopen_fd(struct client_state_t cs[static 1]);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARPR_NONE = 0,
|
||||||
|
ARPR_ERROR,
|
||||||
|
ARPR_PENDING,
|
||||||
|
ARPR_CLOSED,
|
||||||
|
};
|
||||||
|
void arp_packet_action(struct client_state_t cs[static 1]);
|
||||||
|
int arp_packet_get(struct client_state_t cs[static 1]);
|
||||||
|
|
||||||
void handle_arp_timeout(struct client_state_t cs[static 1], long long nowts);
|
void handle_arp_timeout(struct client_state_t cs[static 1], long long nowts);
|
||||||
long long arp_get_wake_ts(void);
|
long long arp_get_wake_ts(void);
|
||||||
|
|
||||||
|
181
src/coroutine.h
Normal file
181
src/coroutine.h
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/* coroutine.h
|
||||||
|
*
|
||||||
|
* Coroutine mechanics, implemented on top of standard ANSI C. See
|
||||||
|
* http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html for
|
||||||
|
* a full discussion of the theory behind this.
|
||||||
|
*
|
||||||
|
* To use these macros to define a coroutine, you need to write a
|
||||||
|
* function that looks something like this.
|
||||||
|
*
|
||||||
|
* [Simple version using static variables (scr macros)]
|
||||||
|
* int ascending (void) {
|
||||||
|
* static int i;
|
||||||
|
*
|
||||||
|
* scrBegin;
|
||||||
|
* for (i=0; i<10; i++) {
|
||||||
|
* scrReturn(i);
|
||||||
|
* }
|
||||||
|
* scrFinish(-1);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* [Re-entrant version using an explicit context structure (ccr macros)]
|
||||||
|
* int ascending (ccrContParam) {
|
||||||
|
* ccrBeginContext;
|
||||||
|
* int i;
|
||||||
|
* ccrEndContext(foo);
|
||||||
|
*
|
||||||
|
* ccrBegin(foo);
|
||||||
|
* for (foo->i=0; foo->i<10; foo->i++) {
|
||||||
|
* ccrReturn(foo->i);
|
||||||
|
* }
|
||||||
|
* ccrFinish(-1);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* In the static version, you need only surround the function body
|
||||||
|
* with `scrBegin' and `scrFinish', and then you can do `scrReturn'
|
||||||
|
* within the function and on the next call control will resume
|
||||||
|
* just after the scrReturn statement. Any local variables you need
|
||||||
|
* to be persistent across an `scrReturn' must be declared static.
|
||||||
|
*
|
||||||
|
* In the re-entrant version, you need to declare your persistent
|
||||||
|
* variables between `ccrBeginContext' and `ccrEndContext'. These
|
||||||
|
* will be members of a structure whose name you specify in the
|
||||||
|
* parameter to `ccrEndContext'.
|
||||||
|
*
|
||||||
|
* The re-entrant macros will malloc() the state structure on first
|
||||||
|
* call, and free() it when `ccrFinish' is reached. If you want to
|
||||||
|
* abort in the middle, you can use `ccrStop' to free the state
|
||||||
|
* structure immediately (equivalent to an explicit return() in a
|
||||||
|
* caller-type routine).
|
||||||
|
*
|
||||||
|
* A coroutine returning void type may call `ccrReturnV',
|
||||||
|
* `ccrFinishV' and `ccrStopV', or `scrReturnV', to avoid having to
|
||||||
|
* specify an empty parameter to the ordinary return macros.
|
||||||
|
*
|
||||||
|
* Ground rules:
|
||||||
|
* - never put `ccrReturn' or `scrReturn' within an explicit `switch'.
|
||||||
|
* - never put two `ccrReturn' or `scrReturn' statements on the same
|
||||||
|
* source line.
|
||||||
|
*
|
||||||
|
* The caller of a static coroutine calls it just as if it were an
|
||||||
|
* ordinary function:
|
||||||
|
*
|
||||||
|
* void main(void) {
|
||||||
|
* int i;
|
||||||
|
* do {
|
||||||
|
* i = ascending();
|
||||||
|
* printf("got number %d\n", i);
|
||||||
|
* } while (i != -1);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* The caller of a re-entrant coroutine must provide a context
|
||||||
|
* variable:
|
||||||
|
*
|
||||||
|
* void main(void) {
|
||||||
|
* ccrContext z = 0;
|
||||||
|
* do {
|
||||||
|
* printf("got number %d\n", ascending (&z));
|
||||||
|
* } while (z);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Note that the context variable is set back to zero when the
|
||||||
|
* coroutine terminates (by crStop, or by control reaching
|
||||||
|
* crFinish). This can make the re-entrant coroutines more useful
|
||||||
|
* than the static ones, because you can tell when they have
|
||||||
|
* finished.
|
||||||
|
*
|
||||||
|
* If you need to dispose of a crContext when it is non-zero (that
|
||||||
|
* is, if you want to stop calling a coroutine without suffering a
|
||||||
|
* memory leak), the caller should call `ccrAbort(ctx)' where `ctx'
|
||||||
|
* is the context variable.
|
||||||
|
*
|
||||||
|
* This mechanism could have been better implemented using GNU C
|
||||||
|
* and its ability to store pointers to labels, but sadly this is
|
||||||
|
* not part of the ANSI C standard and so the mechanism is done by
|
||||||
|
* case statements instead. That's why you can't put a crReturn()
|
||||||
|
* inside a switch() statement.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* coroutine.h is copyright 1995,2000 Simon Tatham.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation
|
||||||
|
* files (the "Software"), to deal in the Software without
|
||||||
|
* restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following
|
||||||
|
* conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR
|
||||||
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COROUTINE_H
|
||||||
|
#define COROUTINE_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* `scr' macros for static coroutines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define scrBegin static int scrLine = 0; switch(scrLine) { case 0:;
|
||||||
|
#define scrFinish(z) } return (z)
|
||||||
|
#define scrFinishV } return
|
||||||
|
|
||||||
|
#define scrReturn(z) \
|
||||||
|
do {\
|
||||||
|
scrLine=__LINE__;\
|
||||||
|
return (z); case __LINE__:;\
|
||||||
|
} while (0)
|
||||||
|
#define scrReturnV \
|
||||||
|
do {\
|
||||||
|
scrLine=__LINE__;\
|
||||||
|
return; case __LINE__:;\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* `ccr' macros for re-entrant coroutines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ccrContParam void **ccrParam
|
||||||
|
|
||||||
|
#define ccrBeginContext struct ccrContextTag { int ccrLine
|
||||||
|
#define ccrEndContext(x) } *x = (struct ccrContextTag *)*ccrParam
|
||||||
|
|
||||||
|
#define ccrBegin(x) if(!x) {x= *ccrParam=malloc(sizeof(*x)); x->ccrLine=0;}\
|
||||||
|
if (x) switch(x->ccrLine) { case 0:;
|
||||||
|
#define ccrFinish(z) } free(*ccrParam); *ccrParam=0; return (z)
|
||||||
|
#define ccrFinishV } free(*ccrParam); *ccrParam=0; return
|
||||||
|
|
||||||
|
#define ccrReturn(z) \
|
||||||
|
do {\
|
||||||
|
((struct ccrContextTag *)*ccrParam)->ccrLine=__LINE__;\
|
||||||
|
return (z); case __LINE__:;\
|
||||||
|
} while (0)
|
||||||
|
#define ccrReturnV \
|
||||||
|
do {\
|
||||||
|
((struct ccrContextTag *)*ccrParam)->ccrLine=__LINE__;\
|
||||||
|
return; case __LINE__:;\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ccrStop(z) do{ free(*ccrParam); *ccrParam=0; return (z); }while(0)
|
||||||
|
#define ccrStopV do{ free(*ccrParam); *ccrParam=0; return; }while(0)
|
||||||
|
|
||||||
|
#define ccrContext void *
|
||||||
|
#define ccrAbort(ctx) do { free (ctx); ctx = 0; } while (0)
|
||||||
|
|
||||||
|
#endif /* COROUTINE_H */
|
20
src/dhcp.c
20
src/dhcp.c
@ -380,13 +380,14 @@ static int validate_dhcp_packet(struct client_state_t cs[static 1],
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_packet(struct client_state_t cs[static 1])
|
int dhcp_packet_get(struct client_state_t cs[static 1],
|
||||||
|
struct dhcpmsg packet[static 1],
|
||||||
|
uint8_t msgtype[static 1],
|
||||||
|
uint32_t srcaddr[static 1])
|
||||||
{
|
{
|
||||||
if (cs->listenFd < 0)
|
if (cs->listenFd < 0)
|
||||||
return;
|
return -1;
|
||||||
struct dhcpmsg packet;
|
ssize_t r = get_raw_packet(cs, packet, srcaddr);
|
||||||
uint32_t srcaddr;
|
|
||||||
ssize_t r = get_raw_packet(cs, &packet, &srcaddr);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
// Not a transient issue handled by packet collection functions.
|
// Not a transient issue handled by packet collection functions.
|
||||||
if (r != -2) {
|
if (r != -2) {
|
||||||
@ -395,12 +396,11 @@ void handle_packet(struct client_state_t cs[static 1])
|
|||||||
stop_dhcp_listen(cs);
|
stop_dhcp_listen(cs);
|
||||||
start_dhcp_listen(cs);
|
start_dhcp_listen(cs);
|
||||||
}
|
}
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
uint8_t msgtype;
|
if (!validate_dhcp_packet(cs, (size_t)r, packet, msgtype))
|
||||||
if (!validate_dhcp_packet(cs, (size_t)r, &packet, &msgtype))
|
return -1;
|
||||||
return;
|
return 0;
|
||||||
packet_action(cs, &packet, msgtype, srcaddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a DHCP client packet that will be sent to a server
|
// Initialize a DHCP client packet that will be sent to a server
|
||||||
|
@ -83,7 +83,10 @@ struct udp_dhcp_packet {
|
|||||||
|
|
||||||
void start_dhcp_listen(struct client_state_t cs[static 1]);
|
void start_dhcp_listen(struct client_state_t cs[static 1]);
|
||||||
void stop_dhcp_listen(struct client_state_t cs[static 1]);
|
void stop_dhcp_listen(struct client_state_t cs[static 1]);
|
||||||
void handle_packet(struct client_state_t cs[static 1]);
|
int dhcp_packet_get(struct client_state_t cs[static 1],
|
||||||
|
struct dhcpmsg packet[static 1],
|
||||||
|
uint8_t msgtype[static 1],
|
||||||
|
uint32_t srcaddr[static 1]);
|
||||||
ssize_t send_discover(struct client_state_t cs[static 1]);
|
ssize_t send_discover(struct client_state_t cs[static 1]);
|
||||||
ssize_t send_selecting(struct client_state_t cs[static 1]);
|
ssize_t send_selecting(struct client_state_t cs[static 1]);
|
||||||
ssize_t send_renew(struct client_state_t cs[static 1]);
|
ssize_t send_renew(struct client_state_t cs[static 1]);
|
||||||
|
115
src/ndhc.c
115
src/ndhc.c
@ -182,7 +182,13 @@ static void setup_signals_ndhc(void)
|
|||||||
epoll_add(cs.epollFd, cs.signalFd);
|
epoll_add(cs.epollFd, cs.signalFd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signal_dispatch(void)
|
enum {
|
||||||
|
SIGNAL_NONE = 0,
|
||||||
|
SIGNAL_RENEW,
|
||||||
|
SIGNAL_RELEASE
|
||||||
|
};
|
||||||
|
|
||||||
|
static int signal_dispatch(void)
|
||||||
{
|
{
|
||||||
struct signalfd_siginfo si;
|
struct signalfd_siginfo si;
|
||||||
memset(&si, 0, sizeof si);
|
memset(&si, 0, sizeof si);
|
||||||
@ -190,24 +196,22 @@ static void signal_dispatch(void)
|
|||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error("%s: ndhc: error reading from signalfd: %s",
|
log_error("%s: ndhc: error reading from signalfd: %s",
|
||||||
client_config.interface, strerror(errno));
|
client_config.interface, strerror(errno));
|
||||||
return;
|
return SIGNAL_NONE;
|
||||||
}
|
}
|
||||||
if ((size_t)r < sizeof si) {
|
if ((size_t)r < sizeof si) {
|
||||||
log_error("%s: ndhc: short read from signalfd: %zd < %zu",
|
log_error("%s: ndhc: short read from signalfd: %zd < %zu",
|
||||||
client_config.interface, r, sizeof si);
|
client_config.interface, r, sizeof si);
|
||||||
return;
|
return SIGNAL_NONE;
|
||||||
}
|
}
|
||||||
switch (si.ssi_signo) {
|
switch (si.ssi_signo) {
|
||||||
case SIGUSR1: force_renew_action(&cs); break;
|
case SIGUSR1: return SIGNAL_RENEW;
|
||||||
case SIGUSR2: force_release_action(&cs); break;
|
case SIGUSR2: return SIGNAL_RELEASE;
|
||||||
case SIGCHLD:
|
case SIGCHLD:
|
||||||
suicide("ndhc-master: Subprocess terminated unexpectedly. Exiting.");
|
suicide("ndhc-master: Subprocess terminated unexpectedly. Exiting.");
|
||||||
break;
|
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
log_line("Received SIGTERM. Exiting gracefully.");
|
log_line("Received SIGTERM. Exiting gracefully.");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
break;
|
default: return SIGNAL_NONE;
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,6 +265,7 @@ static void fail_if_state_dir_dne(void)
|
|||||||
#define NDHC_NUM_EP_FDS 7
|
#define NDHC_NUM_EP_FDS 7
|
||||||
static void do_ndhc_work(void)
|
static void do_ndhc_work(void)
|
||||||
{
|
{
|
||||||
|
struct dhcpmsg dhcp_packet;
|
||||||
struct epoll_event events[NDHC_NUM_EP_FDS];
|
struct epoll_event events[NDHC_NUM_EP_FDS];
|
||||||
long long nowts;
|
long long nowts;
|
||||||
int timeout;
|
int timeout;
|
||||||
@ -284,27 +289,53 @@ static void do_ndhc_work(void)
|
|||||||
goto jumpstart;
|
goto jumpstart;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int r = epoll_wait(cs.epollFd, events, NDHC_NUM_EP_FDS, timeout);
|
int maxi = epoll_wait(cs.epollFd, events, NDHC_NUM_EP_FDS, timeout);
|
||||||
if (r < 0) {
|
if (maxi < 0) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
suicide("epoll_wait failed");
|
suicide("epoll_wait failed");
|
||||||
}
|
}
|
||||||
for (int i = 0; i < r; ++i) {
|
for (int i = 0; i < maxi; ++i) {
|
||||||
int fd = events[i].data.fd;
|
int fd = events[i].data.fd;
|
||||||
if (fd == cs.signalFd) {
|
if (fd == cs.signalFd) {
|
||||||
if (events[i].events & EPOLLIN)
|
if (!(events[i].events & EPOLLIN))
|
||||||
signal_dispatch();
|
return;
|
||||||
|
int sigv = signal_dispatch();
|
||||||
|
if (sigv == SIGNAL_RENEW)
|
||||||
|
force_renew_action(&cs);
|
||||||
|
else if (sigv == SIGNAL_RELEASE)
|
||||||
|
force_release_action(&cs);
|
||||||
} else if (fd == cs.listenFd) {
|
} else if (fd == cs.listenFd) {
|
||||||
if (events[i].events & EPOLLIN)
|
if (!(events[i].events & EPOLLIN))
|
||||||
handle_packet(&cs);
|
return;
|
||||||
|
uint32_t srcaddr;
|
||||||
|
uint8_t msgtype;
|
||||||
|
int r = dhcp_packet_get(&cs, &dhcp_packet, &msgtype, &srcaddr);
|
||||||
|
if (!r)
|
||||||
|
packet_action(&cs, &dhcp_packet, msgtype, srcaddr);
|
||||||
} else if (fd == cs.arpFd) {
|
} else if (fd == cs.arpFd) {
|
||||||
if (events[i].events & EPOLLIN)
|
if (!(events[i].events & EPOLLIN))
|
||||||
handle_arp_response(&cs);
|
return;
|
||||||
|
int r = arp_packet_get(&cs);
|
||||||
|
if (r == ARPR_PENDING) {
|
||||||
|
arp_packet_action(&cs);
|
||||||
|
} else if (r == ARPR_ERROR) {
|
||||||
|
if (garp.state == AS_COLLISION_CHECK)
|
||||||
|
arp_failed(&cs);
|
||||||
|
else if (garp.state == AS_GW_CHECK)
|
||||||
|
arp_gw_failed(&cs);
|
||||||
|
else
|
||||||
|
arp_reopen_fd(&cs);
|
||||||
|
handle_arp_timeout(&cs, curms());
|
||||||
|
} else if (r == ARPR_CLOSED)
|
||||||
|
handle_arp_timeout(&cs, curms());
|
||||||
} else if (fd == cs.nlFd) {
|
} else if (fd == cs.nlFd) {
|
||||||
if (events[i].events & EPOLLIN)
|
if (!(events[i].events & EPOLLIN))
|
||||||
handle_nl_message(&cs);
|
return;
|
||||||
|
int nl_event = nl_event_get(&cs);
|
||||||
|
if (nl_event != IFS_NONE)
|
||||||
|
nl_event_react(&cs, nl_event);
|
||||||
} else if (fd == ifchStream[0]) {
|
} else if (fd == ifchStream[0]) {
|
||||||
if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP))
|
if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP))
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -312,8 +343,30 @@ static void do_ndhc_work(void)
|
|||||||
if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP))
|
if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP))
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
} else if (fd == cs.rfkillFd && client_config.enable_rfkill) {
|
} else if (fd == cs.rfkillFd && client_config.enable_rfkill) {
|
||||||
if (events[i].events & EPOLLIN)
|
if (!(events[i].events & EPOLLIN))
|
||||||
handle_rfkill_notice(&cs, client_config.rfkillIdx);
|
return;
|
||||||
|
int rfk = rfkill_get(&cs, 1, client_config.rfkillIdx);
|
||||||
|
if (rfk == RFK_ENABLED) {
|
||||||
|
cs.rfkill_set = 1;
|
||||||
|
if (cs.ifsPrevState == IFS_UP) {
|
||||||
|
log_line("rfkill: radio now blocked; bringing interface down");
|
||||||
|
cs.ifsPrevState = IFS_DOWN;
|
||||||
|
ifnocarrier_action(&cs);
|
||||||
|
} else
|
||||||
|
log_line("rfkill: radio now blocked, but interface isn't up");
|
||||||
|
} else if (rfk == RFK_DISABLED) {
|
||||||
|
cs.rfkill_set = 0;
|
||||||
|
if (cs.ifsPrevState == IFS_DOWN) {
|
||||||
|
log_line("rfkill: radio now unblocked; bringing interface up");
|
||||||
|
cs.ifsPrevState = IFS_UP;
|
||||||
|
ifup_action(&cs);
|
||||||
|
} else {
|
||||||
|
if (cs.ifsPrevState == IFS_SHUT)
|
||||||
|
log_line("rfkill: radio now unblocked, but interface was shut down by user");
|
||||||
|
else
|
||||||
|
log_line("rfkill: radio now unblocked, but interface is removed");
|
||||||
|
}
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
suicide("epoll_wait: unknown fd");
|
suicide("epoll_wait: unknown fd");
|
||||||
}
|
}
|
||||||
@ -461,7 +514,6 @@ void background(void)
|
|||||||
|
|
||||||
static void wait_for_rfkill()
|
static void wait_for_rfkill()
|
||||||
{
|
{
|
||||||
cs.rfkill_set = 1;
|
|
||||||
struct epoll_event events[2];
|
struct epoll_event events[2];
|
||||||
cs.rfkillFd = rfkill_open(&client_config.enable_rfkill);
|
cs.rfkillFd = rfkill_open(&client_config.enable_rfkill);
|
||||||
if (cs.rfkillFd < 0)
|
if (cs.rfkillFd < 0)
|
||||||
@ -480,13 +532,20 @@ static void wait_for_rfkill()
|
|||||||
}
|
}
|
||||||
for (int i = 0; i < r; ++i) {
|
for (int i = 0; i < r; ++i) {
|
||||||
int fd = events[i].data.fd;
|
int fd = events[i].data.fd;
|
||||||
if (fd == cs.rfkillFd) {
|
if (fd != cs.rfkillFd)
|
||||||
if (events[i].events & EPOLLIN) {
|
|
||||||
if (!rfkill_wait_for_end(&cs))
|
|
||||||
goto rfkill_gone;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
suicide("epoll_wait: unknown fd");
|
suicide("epoll_wait: unknown fd");
|
||||||
|
if (events[i].events & EPOLLIN) {
|
||||||
|
int rfk = rfkill_get(&cs, 0, 0);
|
||||||
|
if (rfk == RFK_DISABLED) {
|
||||||
|
switch (perform_ifup()) {
|
||||||
|
case 1: case 0: goto rfkill_gone;
|
||||||
|
case -3:
|
||||||
|
log_line("rfkill: radio immediately blocked again; spurious?");
|
||||||
|
break;
|
||||||
|
default: suicide("failed to set the interface to up state");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rfkill_gone:
|
rfkill_gone:
|
||||||
|
@ -43,67 +43,81 @@
|
|||||||
#include "nl.h"
|
#include "nl.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
|
||||||
static void nl_process_msgs(const struct nlmsghdr *nlh, void *data)
|
int nl_event_react(struct client_state_t cs[static 1], int state)
|
||||||
{
|
{
|
||||||
struct ifinfomsg *ifm = NLMSG_DATA(nlh);
|
if (state == cs->ifsPrevState)
|
||||||
struct client_state_t *cs = data;
|
return -1;
|
||||||
|
|
||||||
// If the rfkill switch is set, a lot of netlink state change
|
// If the rfkill switch is set, a lot of netlink state change
|
||||||
// commands will fail outright, so just ignore events until
|
// commands will fail outright, so just ignore events until
|
||||||
// it is gone.
|
// it is gone.
|
||||||
if (cs->rfkill_set)
|
if (cs->rfkill_set)
|
||||||
return;
|
return -1;
|
||||||
|
|
||||||
switch(nlh->nlmsg_type) {
|
switch (state) {
|
||||||
case RTM_NEWLINK:
|
case IFS_UP:
|
||||||
if (ifm->ifi_index != client_config.ifindex)
|
|
||||||
break;
|
|
||||||
// IFF_UP corresponds to ifconfig down or ifconfig up.
|
|
||||||
if (ifm->ifi_flags & IFF_UP) {
|
|
||||||
// IFF_RUNNING is the hardware carrier.
|
|
||||||
if (ifm->ifi_flags & IFF_RUNNING) {
|
|
||||||
if (cs->ifsPrevState != IFS_UP) {
|
|
||||||
cs->ifsPrevState = IFS_UP;
|
cs->ifsPrevState = IFS_UP;
|
||||||
ifup_action(cs);
|
ifup_action(cs);
|
||||||
}
|
break;
|
||||||
} else if (cs->ifsPrevState != IFS_DOWN) {
|
case IFS_DOWN:
|
||||||
// Interface configured, but no hardware carrier.
|
// Interface configured, but no hardware carrier.
|
||||||
cs->ifsPrevState = IFS_DOWN;
|
cs->ifsPrevState = IFS_DOWN;
|
||||||
ifnocarrier_action(cs);
|
ifnocarrier_action(cs);
|
||||||
}
|
break;
|
||||||
} else if (cs->ifsPrevState != IFS_SHUT) {
|
case IFS_SHUT:
|
||||||
// User shut down the interface.
|
// User shut down the interface.
|
||||||
cs->ifsPrevState = IFS_SHUT;
|
cs->ifsPrevState = IFS_SHUT;
|
||||||
ifdown_action(cs);
|
ifdown_action(cs);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case RTM_DELLINK:
|
case IFS_REMOVED:
|
||||||
if (ifm->ifi_index != client_config.ifindex)
|
|
||||||
break;
|
|
||||||
if (cs->ifsPrevState != IFS_REMOVED) {
|
|
||||||
cs->ifsPrevState = IFS_REMOVED;
|
cs->ifsPrevState = IFS_REMOVED;
|
||||||
log_line("Interface removed. Exiting.");
|
log_line("Interface removed. Exiting.");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_nl_message(struct client_state_t cs[static 1])
|
static int nl_process_msgs_return;
|
||||||
|
static void nl_process_msgs(const struct nlmsghdr *nlh, void *data)
|
||||||
|
{
|
||||||
|
(void)data;
|
||||||
|
struct ifinfomsg *ifm = NLMSG_DATA(nlh);
|
||||||
|
|
||||||
|
if (ifm->ifi_index != client_config.ifindex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (nlh->nlmsg_type == RTM_NEWLINK) {
|
||||||
|
// IFF_UP corresponds to ifconfig down or ifconfig up.
|
||||||
|
// IFF_RUNNING is the hardware carrier.
|
||||||
|
if (ifm->ifi_flags & IFF_UP) {
|
||||||
|
if (ifm->ifi_flags & IFF_RUNNING)
|
||||||
|
nl_process_msgs_return = IFS_UP;
|
||||||
|
else
|
||||||
|
nl_process_msgs_return = IFS_DOWN;
|
||||||
|
} else {
|
||||||
|
nl_process_msgs_return = IFS_SHUT;
|
||||||
|
}
|
||||||
|
} else if (nlh->nlmsg_type == RTM_DELLINK)
|
||||||
|
nl_process_msgs_return = IFS_REMOVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nl_event_get(struct client_state_t cs[static 1])
|
||||||
{
|
{
|
||||||
char nlbuf[8192];
|
char nlbuf[8192];
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
assert(cs->nlFd != -1);
|
assert(cs->nlFd != -1);
|
||||||
|
nl_process_msgs_return = IFS_NONE;
|
||||||
do {
|
do {
|
||||||
ret = nl_recv_buf(cs->nlFd, nlbuf, sizeof nlbuf);
|
ret = nl_recv_buf(cs->nlFd, nlbuf, sizeof nlbuf);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
if (nl_foreach_nlmsg(nlbuf, ret, 0, cs->nlPortId, nl_process_msgs, cs)
|
if (nl_foreach_nlmsg(nlbuf, ret, 0, cs->nlPortId, nl_process_msgs, 0)
|
||||||
< 0)
|
< 0)
|
||||||
break;
|
break;
|
||||||
} while (ret > 0);
|
} while (ret > 0);
|
||||||
|
return nl_process_msgs_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_if_index_and_mac(const struct nlmsghdr *nlh,
|
static int get_if_index_and_mac(const struct nlmsghdr *nlh,
|
||||||
|
@ -40,7 +40,8 @@ enum {
|
|||||||
IFS_REMOVED
|
IFS_REMOVED
|
||||||
};
|
};
|
||||||
|
|
||||||
void handle_nl_message(struct client_state_t cs[static 1]);
|
int nl_event_react(struct client_state_t cs[static 1], int state);
|
||||||
|
int nl_event_get(struct client_state_t cs[static 1]);
|
||||||
int nl_getifdata(void);
|
int nl_getifdata(void);
|
||||||
|
|
||||||
#endif /* NK_NETLINK_H_ */
|
#endif /* NK_NETLINK_H_ */
|
||||||
|
82
src/rfkill.c
82
src/rfkill.c
@ -26,7 +26,6 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -36,8 +35,6 @@
|
|||||||
#include "nk/log.h"
|
#include "nk/log.h"
|
||||||
#include "nk/io.h"
|
#include "nk/io.h"
|
||||||
#include "ndhc.h"
|
#include "ndhc.h"
|
||||||
#include "netlink.h"
|
|
||||||
#include "ifset.h"
|
|
||||||
#include "rfkill.h"
|
#include "rfkill.h"
|
||||||
|
|
||||||
int rfkill_open(char enable_rfkill[static 1])
|
int rfkill_open(char enable_rfkill[static 1])
|
||||||
@ -53,90 +50,31 @@ int rfkill_open(char enable_rfkill[static 1])
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rfkill_check(struct client_state_t cs[static 1],
|
// check_idx: Does rfkidx have any meaning?
|
||||||
int (*rfenable)(struct client_state_t[static 1]),
|
// rfkidx: Pay attention only to this radio kill switch number.
|
||||||
int (*rfdisable)(struct client_state_t[static 1]),
|
int rfkill_get(struct client_state_t cs[static 1],
|
||||||
bool check_idx, uint32_t rfkidx)
|
int check_idx, uint32_t rfkidx)
|
||||||
{
|
{
|
||||||
struct rfkill_event event;
|
struct rfkill_event event;
|
||||||
ssize_t len = safe_read(cs->rfkillFd, (char *)&event, sizeof event);
|
ssize_t len = safe_read(cs->rfkillFd, (char *)&event, sizeof event);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
log_error("rfkill: safe_read failed: %s", strerror(errno));
|
log_error("rfkill: safe_read failed: %s", strerror(errno));
|
||||||
return -1;
|
return RFK_FAIL;
|
||||||
}
|
}
|
||||||
if (len != RFKILL_EVENT_SIZE_V1) {
|
if (len != RFKILL_EVENT_SIZE_V1) {
|
||||||
log_error("rfkill: event has unexpected size: %d", len);
|
log_error("rfkill: event has unexpected size: %d", len);
|
||||||
return -1;
|
return RFK_FAIL;
|
||||||
}
|
}
|
||||||
log_line("rfkill: idx[%u] type[%u] op[%u] soft[%u] hard[%u]",
|
log_line("rfkill: idx[%u] type[%u] op[%u] soft[%u] hard[%u]",
|
||||||
event.idx, event.type, event.op, event.soft, event.hard);
|
event.idx, event.type, event.op, event.soft, event.hard);
|
||||||
if (check_idx && event.idx != rfkidx)
|
if (check_idx && event.idx != rfkidx)
|
||||||
return 0;
|
return RFK_NONE;
|
||||||
if (event.op != RFKILL_OP_CHANGE && event.op != RFKILL_OP_CHANGE_ALL)
|
if (event.op != RFKILL_OP_CHANGE && event.op != RFKILL_OP_CHANGE_ALL)
|
||||||
return 0;
|
return RFK_NONE;
|
||||||
if (event.soft || event.hard) {
|
if (event.soft || event.hard) {
|
||||||
return rfenable(cs);
|
return RFK_ENABLED;
|
||||||
} else {
|
} else {
|
||||||
return rfdisable(cs);
|
return RFK_DISABLED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_rfkill_notice_enable(struct client_state_t cs[static 1])
|
|
||||||
{
|
|
||||||
cs->rfkill_set = 1;
|
|
||||||
if (cs->ifsPrevState == IFS_UP) {
|
|
||||||
log_line("rfkill: radio now blocked; bringing interface down");
|
|
||||||
cs->ifsPrevState = IFS_DOWN;
|
|
||||||
ifnocarrier_action(cs);
|
|
||||||
} else
|
|
||||||
log_line("rfkill: radio now blocked, but interface isn't up");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int handle_rfkill_notice_disable(struct client_state_t cs[static 1])
|
|
||||||
{
|
|
||||||
cs->rfkill_set = 0;
|
|
||||||
if (cs->ifsPrevState == IFS_DOWN) {
|
|
||||||
log_line("rfkill: radio now unblocked; bringing interface up");
|
|
||||||
cs->ifsPrevState = IFS_UP;
|
|
||||||
ifup_action(cs);
|
|
||||||
} else {
|
|
||||||
if (cs->ifsPrevState == IFS_SHUT)
|
|
||||||
log_line("rfkill: radio now unblocked, but interface was shut down by user");
|
|
||||||
else
|
|
||||||
log_line("rfkill: radio now unblocked, but interface is removed");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rfkill_wait_for_end_enable(struct client_state_t cs[static 1])
|
|
||||||
{
|
|
||||||
(void)cs;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rfkill_wait_for_end_disable(struct client_state_t cs[static 1])
|
|
||||||
{
|
|
||||||
switch (perform_ifup()) {
|
|
||||||
case 1: case 0:
|
|
||||||
cs->rfkill_set = 0;
|
|
||||||
return 0;
|
|
||||||
case -3:
|
|
||||||
log_line("rfkill: radio immediately blocked again; spurious?");
|
|
||||||
return -1;
|
|
||||||
default: suicide("failed to set the interface to up state");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int handle_rfkill_notice(struct client_state_t cs[static 1], uint32_t rfkidx)
|
|
||||||
{
|
|
||||||
return rfkill_check(cs, handle_rfkill_notice_enable,
|
|
||||||
handle_rfkill_notice_disable, true, rfkidx);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rfkill_wait_for_end(struct client_state_t cs[static 1])
|
|
||||||
{
|
|
||||||
return rfkill_check(cs, rfkill_wait_for_end_enable,
|
|
||||||
rfkill_wait_for_end_disable, false, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
11
src/rfkill.h
11
src/rfkill.h
@ -28,9 +28,16 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RFK_NONE = 0,
|
||||||
|
RFK_FAIL,
|
||||||
|
RFK_ENABLED,
|
||||||
|
RFK_DISABLED,
|
||||||
|
};
|
||||||
|
|
||||||
int rfkill_open(char enable_rfkill[static 1]);
|
int rfkill_open(char enable_rfkill[static 1]);
|
||||||
int handle_rfkill_notice(struct client_state_t cs[static 1], uint32_t rfkidx);
|
int rfkill_get(struct client_state_t cs[static 1],
|
||||||
int rfkill_wait_for_end(struct client_state_t cs[static 1]);
|
int check_idx, uint32_t rfkidx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user