summaryrefslogtreecommitdiff
path: root/accel-pppd/ppp/ppp_ipv6cp.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/ppp/ppp_ipv6cp.c')
-rw-r--r--accel-pppd/ppp/ppp_ipv6cp.c226
1 files changed, 168 insertions, 58 deletions
diff --git a/accel-pppd/ppp/ppp_ipv6cp.c b/accel-pppd/ppp/ppp_ipv6cp.c
index a7d2ad2b..4ad1cfbf 100644
--- a/accel-pppd/ppp/ppp_ipv6cp.c
+++ b/accel-pppd/ppp/ppp_ipv6cp.c
@@ -7,6 +7,7 @@
#include "triton.h"
#include "log.h"
+#include "events.h"
#include "ppp.h"
#include "ppp_ipv6cp.h"
@@ -22,17 +23,25 @@ struct recv_opt_t
struct ipv6cp_option_t *lopt;
};
-static int conf_ipv6 = 2; // 0 - disables, 1 - allow, 2 - require
+#define IPV6_DENY 0
+#define IPV6_ALLOW 1
+#define IPV6_PREFERE 2
+#define IPV6_REQUIRE 3
+
+static int conf_ipv6 = IPV6_ALLOW;
static LIST_HEAD(option_handlers);
+static struct ppp_layer_t ipv6cp_layer;
static void ipv6cp_layer_up(struct ppp_fsm_t*);
static void ipv6cp_layer_down(struct ppp_fsm_t*);
+static void ipv6cp_layer_finished(struct ppp_fsm_t*);
static int send_conf_req(struct ppp_fsm_t*);
static void send_conf_ack(struct ppp_fsm_t*);
static void send_conf_nak(struct ppp_fsm_t*);
static void send_conf_rej(struct ppp_fsm_t*);
static void ipv6cp_recv(struct ppp_handler_t*);
+static void ipv6cp_recv_proto_rej(struct ppp_handler_t*);
static void send_term_req(struct ppp_fsm_t *fsm);
static void send_term_ack(struct ppp_fsm_t *fsm);
@@ -76,6 +85,7 @@ static struct ppp_layer_data_t *ipv6cp_layer_init(struct ppp_t *ppp)
ipv6cp->hnd.proto = PPP_IPV6CP;
ipv6cp->hnd.recv = ipv6cp_recv;
+ ipv6cp->hnd.recv_proto_rej = ipv6cp_recv_proto_rej;
ppp_register_unit_handler(ppp, &ipv6cp->hnd);
@@ -83,7 +93,8 @@ static struct ppp_layer_data_t *ipv6cp_layer_init(struct ppp_t *ppp)
ppp_fsm_init(&ipv6cp->fsm);
ipv6cp->fsm.layer_up = ipv6cp_layer_up;
- ipv6cp->fsm.layer_finished = ipv6cp_layer_down;
+ ipv6cp->fsm.layer_finished = ipv6cp_layer_finished;
+ ipv6cp->fsm.layer_down = ipv6cp_layer_down;
ipv6cp->fsm.send_conf_req = send_conf_req;
ipv6cp->fsm.send_conf_ack = send_conf_ack;
ipv6cp->fsm.send_conf_nak = send_conf_nak;
@@ -94,10 +105,8 @@ static struct ppp_layer_data_t *ipv6cp_layer_init(struct ppp_t *ppp)
INIT_LIST_HEAD(&ipv6cp->options);
INIT_LIST_HEAD(&ipv6cp->ropt_list);
- ipv6cp->passive = conf_ipv6 == 1;
+ ipv6cp->ld.passive = conf_ipv6 == IPV6_ALLOW;
- ipv6cp_options_init(ipv6cp);
-
return &ipv6cp->ld;
}
@@ -106,15 +115,16 @@ int ipv6cp_layer_start(struct ppp_layer_data_t *ld)
struct ppp_ipv6cp_t *ipv6cp = container_of(ld, typeof(*ipv6cp), ld);
log_ppp_debug("ipv6cp_layer_start\n");
-
- if (!conf_ipv6) {
- ppp_layer_started(ipv6cp->ppp, &ipv6cp->ld);
- return 0;
- }
- ppp_fsm_lower_up(&ipv6cp->fsm);
- if (ppp_fsm_open(&ipv6cp->fsm))
- return -1;
+ ipv6cp_options_init(ipv6cp);
+
+ ipv6cp->starting = 1;
+
+ if (!ipv6cp->ld.passive && conf_ipv6 != IPV6_DENY) {
+ ppp_fsm_lower_up(&ipv6cp->fsm);
+ if (ppp_fsm_open(&ipv6cp->fsm))
+ return -1;
+ }
return 0;
}
@@ -144,10 +154,8 @@ void ipv6cp_layer_free(struct ppp_layer_data_t *ld)
_free(ipv6cp);
}
-static void ipv6cp_layer_up(struct ppp_fsm_t *fsm)
+static void __ipv6cp_layer_up(struct ppp_ipv6cp_t *ipv6cp)
{
- struct ppp_ipv6cp_t *ipv6cp = container_of(fsm, typeof(*ipv6cp), fsm);
-
log_ppp_debug("ipv6cp_layer_started\n");
if (!ipv6cp->started) {
@@ -156,17 +164,36 @@ static void ipv6cp_layer_up(struct ppp_fsm_t *fsm)
}
}
-static void ipv6cp_layer_down(struct ppp_fsm_t *fsm)
+static void ipv6cp_layer_up(struct ppp_fsm_t *fsm)
+{
+ struct ppp_ipv6cp_t *ipv6cp = container_of(fsm, typeof(*ipv6cp), fsm);
+
+ if (!ipv6cp->delay_ack)
+ __ipv6cp_layer_up(ipv6cp);
+}
+
+static void ipv6cp_layer_finished(struct ppp_fsm_t *fsm)
{
struct ppp_ipv6cp_t *ipv6cp = container_of(fsm, typeof(*ipv6cp), fsm);
log_ppp_debug("ipv6cp_layer_finished\n");
- if (ipv6cp->started) {
- ipv6cp->started = 0;
- ppp_layer_finished(ipv6cp->ppp, &ipv6cp->ld);
- } else
- ppp_terminate(ipv6cp->ppp, TERM_NAS_ERROR, 0);
+ if (!ipv6cp->started) {
+ if (conf_ipv6 == IPV6_REQUIRE)
+ ppp_terminate(ipv6cp->ppp, TERM_USER_ERROR, 0);
+ else
+ ipv6cp->ld.passive = 1;
+ } else if (!ipv6cp->ppp->terminating)
+ ppp_terminate(ipv6cp->ppp, TERM_USER_ERROR, 0);
+}
+
+static void ipv6cp_layer_down(struct ppp_fsm_t *fsm)
+{
+ struct ppp_ipv6cp_t *ipv6cp = container_of(fsm, typeof(*ipv6cp), fsm);
+
+ log_ppp_debug("ipv6cp_layer_down\n");
+
+ ppp_fsm_close(fsm);
}
static void print_ropt(struct recv_opt_t *ropt)
@@ -189,20 +216,25 @@ static int send_conf_req(struct ppp_fsm_t *fsm)
struct ipv6cp_option_t *lopt;
int n;
- if (ipv6cp->passive)
- return 0;
-
ipv6cp_hdr->proto = htons(PPP_IPV6CP);
ipv6cp_hdr->code = CONFREQ;
- ipv6cp_hdr->id = ++ipv6cp->fsm.id;
+ ipv6cp_hdr->id = ipv6cp->fsm.id;
ipv6cp_hdr->len = 0;
ptr += sizeof(*ipv6cp_hdr);
list_for_each_entry(lopt, &ipv6cp->options, entry) {
n = lopt->h->send_conf_req(ipv6cp, lopt, ptr);
- if (n < 0)
+ if (n < 0) {
+ if (n == IPV6CP_OPT_TERMACK)
+ goto out;
+ if (n == IPV6CP_OPT_CLOSE && conf_ipv6 != IPV6_REQUIRE) {
+ ppp_fsm_close2(fsm);
+ goto out;
+ }
+ _free(buf);
return -1;
+ }
if (n) {
ptr += n;
lopt->print = 1;
@@ -224,6 +256,7 @@ static int send_conf_req(struct ppp_fsm_t *fsm)
ipv6cp_hdr->len = htons(ptr - buf - 2);
ppp_unit_send(ipv6cp->ppp, ipv6cp_hdr, ptr - buf);
+out:
_free(buf);
return 0;
@@ -234,6 +267,11 @@ static void send_conf_ack(struct ppp_fsm_t *fsm)
struct ppp_ipv6cp_t *ipv6cp = container_of(fsm, typeof(*ipv6cp), fsm);
struct ipv6cp_hdr_t *hdr = (struct ipv6cp_hdr_t*)ipv6cp->ppp->buf;
+ if (ipv6cp->delay_ack) {
+ send_term_ack(fsm);
+ return;
+ }
+
hdr->code = CONFACK;
if (conf_ppp_verbose)
@@ -263,10 +301,10 @@ static void send_conf_nak(struct ppp_fsm_t *fsm)
if (ropt->state == IPV6CP_OPT_NAK) {
ptr1 = ptr;
ptr += ropt->lopt->h->send_conf_nak(ipv6cp, ropt->lopt, ptr);
- if (conf_ppp_verbose) {
- log_ppp_info2(" ");
- ropt->lopt->h->print(log_ppp_info2, ropt->lopt, ptr1);
- }
+ }
+ if (conf_ppp_verbose) {
+ log_ppp_info2(" ");
+ ropt->lopt->h->print(log_ppp_info2, ropt->lopt, ptr1);
}
}
@@ -373,6 +411,17 @@ static int ipv6cp_recv_conf_req(struct ppp_ipv6cp_t *ipv6cp, uint8_t *data, int
list_for_each_entry(lopt, &ipv6cp->options, entry) {
if (lopt->id == ropt->hdr->id) {
r = lopt->h->recv_conf_req(ipv6cp, lopt, (uint8_t*)ropt->hdr);
+ if (r == IPV6CP_OPT_TERMACK) {
+ send_term_ack(&ipv6cp->fsm);
+ return 0;
+ }
+ if (r == IPV6CP_OPT_CLOSE) {
+ if (conf_ipv6 == IPV6_REQUIRE)
+ ppp_terminate(ipv6cp->ppp, TERM_NAS_ERROR, 0);
+ else
+ lcp_send_proto_rej(ipv6cp->ppp, PPP_IPV6CP);
+ return 0;
+ }
if (ipv6cp->ppp->stop_time)
return -1;
lopt->state = r;
@@ -423,11 +472,11 @@ static int ipv6cp_recv_conf_rej(struct ppp_ipv6cp_t *ipv6cp, uint8_t *data, int
if (conf_ppp_verbose)
log_ppp_info2("recv [IPV6CP ConfRej id=%x", ipv6cp->fsm.recv_id);
- if (ipv6cp->fsm.recv_id != ipv6cp->fsm.id) {
+ /*if (ipv6cp->fsm.recv_id != ipv6cp->fsm.id) {
if (conf_ppp_verbose)
log_ppp_info2(": id mismatch ]\n");
return 0;
- }
+ }*/
while (size > 0) {
hdr = (struct ipv6cp_opt_hdr_t *)data;
@@ -461,11 +510,11 @@ static int ipv6cp_recv_conf_nak(struct ppp_ipv6cp_t *ipv6cp, uint8_t *data, int
if (conf_ppp_verbose)
log_ppp_info2("recv [IPV6CP ConfNak id=%x", ipv6cp->fsm.recv_id);
- if (ipv6cp->fsm.recv_id != ipv6cp->fsm.id) {
+ /*if (ipv6cp->fsm.recv_id != ipv6cp->fsm.id) {
if (conf_ppp_verbose)
log_ppp_info2(": id mismatch ]\n");
return 0;
- }
+ }*/
while (size > 0) {
hdr = (struct ipv6cp_opt_hdr_t *)data;
@@ -501,11 +550,11 @@ static int ipv6cp_recv_conf_ack(struct ppp_ipv6cp_t *ipv6cp, uint8_t *data, int
if (conf_ppp_verbose)
log_ppp_info2("recv [IPV6CP ConfAck id=%x", ipv6cp->fsm.recv_id);
- if (ipv6cp->fsm.recv_id != ipv6cp->fsm.id) {
+ /*if (ipv6cp->fsm.recv_id != ipv6cp->fsm.id) {
if (conf_ppp_verbose)
log_ppp_info2(": id mismatch ]\n");
return 0;
- }
+ }*/
while (size > 0) {
hdr = (struct ipv6cp_opt_hdr_t *)data;
@@ -571,15 +620,15 @@ static void ipv6cp_recv(struct ppp_handler_t*h)
struct ipv6cp_hdr_t *hdr;
struct ppp_ipv6cp_t *ipv6cp = container_of(h, typeof(*ipv6cp), hnd);
int r;
+ int delay_ack = ipv6cp->delay_ack;
- if (!conf_ipv6) {
- lcp_send_proto_rej(ipv6cp->ppp, PPP_IPV6CP);
- return;
- }
-
- if (ipv6cp->fsm.fsm_state == FSM_Initial || ipv6cp->fsm.fsm_state == FSM_Closed || ipv6cp->ppp->terminating) {
+ if (!ipv6cp->starting || ipv6cp->fsm.fsm_state == FSM_Closed || ipv6cp->ppp->terminating || conf_ipv6 == IPV6_DENY) {
if (conf_ppp_verbose)
log_ppp_warn("IPV6CP: discarding packet\n");
+ if (ipv6cp->ppp->terminating)
+ return;
+ if (ipv6cp->fsm.fsm_state == FSM_Closed || conf_ipv6 == IPV6_DENY)
+ lcp_send_proto_rej(ipv6cp->ppp, PPP_IPV6CP);
return;
}
@@ -593,8 +642,12 @@ static void ipv6cp_recv(struct ppp_handler_t*h)
log_ppp_warn("IPV6CP: short packet received\n");
return;
}
+
+ if ((hdr->code == CONFACK || hdr->code == CONFNAK || hdr->code == CONFREJ) && hdr->id != ipv6cp->fsm.id)
+ return;
ipv6cp->fsm.recv_id = hdr->id;
+
switch(hdr->code) {
case CONFREQ:
r = ipv6cp_recv_conf_req(ipv6cp,(uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN);
@@ -602,24 +655,34 @@ static void ipv6cp_recv(struct ppp_handler_t*h)
ipv6cp_free_conf_req(ipv6cp);
return;
}
- switch(r) {
- case IPV6CP_OPT_ACK:
- ppp_fsm_recv_conf_req_ack(&ipv6cp->fsm);
- break;
- case IPV6CP_OPT_NAK:
- ppp_fsm_recv_conf_req_nak(&ipv6cp->fsm);
- break;
- case IPV6CP_OPT_REJ:
- ppp_fsm_recv_conf_req_rej(&ipv6cp->fsm);
- break;
+ if (r && ipv6cp->ld.passive) {
+ ipv6cp->ld.passive = 0;
+ ppp_fsm_lower_up(&ipv6cp->fsm);
+ ppp_fsm_open(&ipv6cp->fsm);
+ }
+ if (delay_ack && !ipv6cp->delay_ack)
+ __ipv6cp_layer_up(ipv6cp);
+ if (ipv6cp->started || delay_ack) {
+ if (r == IPV6CP_OPT_ACK)
+ send_conf_ack(&ipv6cp->fsm);
+ else
+ r = IPV6CP_OPT_FAIL;
+ } else {
+ switch(r) {
+ case IPV6CP_OPT_ACK:
+ ppp_fsm_recv_conf_req_ack(&ipv6cp->fsm);
+ break;
+ case IPV6CP_OPT_NAK:
+ ppp_fsm_recv_conf_req_nak(&ipv6cp->fsm);
+ break;
+ case IPV6CP_OPT_REJ:
+ ppp_fsm_recv_conf_req_rej(&ipv6cp->fsm);
+ break;
+ }
}
ipv6cp_free_conf_req(ipv6cp);
if (r == IPV6CP_OPT_FAIL)
ppp_terminate(ipv6cp->ppp, TERM_USER_ERROR, 0);
- else if (ipv6cp->passive) {
- ipv6cp->passive = 0;
- send_conf_req(&ipv6cp->fsm);
- }
break;
case CONFACK:
if (ipv6cp_recv_conf_ack(ipv6cp,(uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN))
@@ -641,6 +704,7 @@ static void ipv6cp_recv(struct ppp_handler_t*h)
if (conf_ppp_verbose)
log_ppp_info2("recv [IPV6CP TermReq id=%x]\n", hdr->id);
ppp_fsm_recv_term_req(&ipv6cp->fsm);
+ ppp_terminate(ipv6cp->ppp, TERM_USER_REQUEST, 0);
break;
case TERMACK:
if (conf_ppp_verbose)
@@ -659,6 +723,17 @@ static void ipv6cp_recv(struct ppp_handler_t*h)
}
}
+static void ipv6cp_recv_proto_rej(struct ppp_handler_t*h)
+{
+ struct ppp_ipv6cp_t *ipv6cp = container_of(h, typeof(*ipv6cp), hnd);
+
+ if (ipv6cp->fsm.fsm_state == FSM_Initial || ipv6cp->fsm.fsm_state == FSM_Closed)
+ return;
+
+ ppp_fsm_lower_down(&ipv6cp->fsm);
+ ppp_fsm_close(&ipv6cp->fsm);
+}
+
int ipv6cp_option_register(struct ipv6cp_option_handler_t *h)
{
/*struct ipv6cp_option_drv_t *p;
@@ -672,6 +747,19 @@ int ipv6cp_option_register(struct ipv6cp_option_handler_t *h)
return 0;
}
+struct ipv6cp_option_t *ipv6cp_find_option(struct ppp_t *ppp, struct ipv6cp_option_handler_t *h)
+{
+ struct ppp_ipv6cp_t *ipv6cp = container_of(ppp_find_layer_data(ppp, &ipv6cp_layer), typeof(*ipv6cp), ld);
+ struct ipv6cp_option_t *opt;
+
+ list_for_each_entry(opt, &ipv6cp->options, entry)
+ if (opt->h == h)
+ return opt;
+
+ log_emerg("ipv6cp: BUG: option not found\n");
+ abort();
+}
+
static struct ppp_layer_t ipv6cp_layer =
{
.init = ipv6cp_layer_init,
@@ -680,10 +768,32 @@ static struct ppp_layer_t ipv6cp_layer =
.free = ipv6cp_layer_free,
};
+static void load_config(void)
+{
+ const char *opt;
+
+ opt = conf_get_opt("ppp", "ipv6");
+ if (opt) {
+ if (!strcmp(opt, "deny"))
+ conf_ipv6 = IPV6_DENY;
+ else if (!strcmp(opt, "allow"))
+ conf_ipv6 = IPV6_ALLOW;
+ else if (!strcmp(opt, "prefere"))
+ conf_ipv6 = IPV6_PREFERE;
+ else if (!strcmp(opt, "require"))
+ conf_ipv6 = IPV6_REQUIRE;
+ else
+ conf_ipv6 = atoi(opt);
+ }
+}
+
static void ipv6cp_init(void)
{
+ load_config();
+
+ triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
+
ppp_register_layer("ipv6cp", &ipv6cp_layer);
}
DEFINE_INIT(4, ipv6cp_init);
-