summaryrefslogtreecommitdiff
path: root/accel-pptpd/ppp/ppp_ccp.c
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pptpd/ppp/ppp_ccp.c')
-rw-r--r--accel-pptpd/ppp/ppp_ccp.c168
1 files changed, 114 insertions, 54 deletions
diff --git a/accel-pptpd/ppp/ppp_ccp.c b/accel-pptpd/ppp/ppp_ccp.c
index 6deaeb18..36db6f9a 100644
--- a/accel-pptpd/ppp/ppp_ccp.c
+++ b/accel-pptpd/ppp/ppp_ccp.c
@@ -1,8 +1,9 @@
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <linux/ppp_defs.h>
#include <linux/if_ppp.h>
-#include <arpa/inet.h>
+#include <sys/ioctl.h>
#include "triton.h"
@@ -22,6 +23,7 @@ struct recv_opt_t
struct ccp_option_t *lopt;
};
+static struct ppp_layer_t ccp_layer;
static LIST_HEAD(option_handlers);
static void ccp_layer_up(struct ppp_fsm_t*);
@@ -65,6 +67,26 @@ static void ccp_options_free(struct ppp_ccp_t *ccp)
}
}
+static int ccp_set_flags(int fd, int isopen, int isup)
+{
+ int flags;
+
+ if (ioctl(fd, PPPIOCGFLAGS, &flags)) {
+ log_ppp_error("ccp: failed to get flags: %s\n", strerror(errno));
+ return -1;
+ }
+
+ flags &= ~(SC_CCP_OPEN | SC_CCP_UP);
+ flags |= (isopen ? SC_CCP_OPEN : 0) | (isup ? SC_CCP_UP : 0);
+
+ if (ioctl(fd, PPPIOCSFLAGS, &flags)) {
+ log_ppp_error("ccp: failed to set flags: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
static struct ppp_layer_data_t *ccp_layer_init(struct ppp_t *ppp)
{
struct ppp_ccp_t *ccp=_malloc(sizeof(*ccp));
@@ -80,6 +102,11 @@ static struct ppp_layer_data_t *ccp_layer_init(struct ppp_t *ppp)
ppp_register_unit_handler(ppp,&ccp->hnd);
+ INIT_LIST_HEAD(&ccp->options);
+ ccp_options_init(ccp);
+
+ ccp->passive = 1;
+
ccp->fsm.proto = PPP_CCP;
ppp_fsm_init(&ccp->fsm);
@@ -92,7 +119,6 @@ static struct ppp_layer_data_t *ccp_layer_init(struct ppp_t *ppp)
ccp->fsm.send_term_req=send_term_req;
ccp->fsm.send_term_ack=send_term_ack;
- INIT_LIST_HEAD(&ccp->options);
INIT_LIST_HEAD(&ccp->ropt_list);
return &ccp->ld;
@@ -104,8 +130,6 @@ int ccp_layer_start(struct ppp_layer_data_t *ld)
log_ppp_debug("ccp_layer_start\n");
- ccp_options_init(ccp);
-
if (list_empty(&ccp->options)) {
ppp_layer_started(ccp->ppp, &ccp->ld);
return 0;
@@ -115,6 +139,11 @@ int ccp_layer_start(struct ppp_layer_data_t *ld)
if (ppp_fsm_open(&ccp->fsm))
return -1;
+ if (ccp_set_flags(ccp->ppp->unit_fd, 1, 0)) {
+ ppp_fsm_close(&ccp->fsm);
+ return -1;
+ }
+
return 0;
}
@@ -123,6 +152,8 @@ void ccp_layer_finish(struct ppp_layer_data_t *ld)
struct ppp_ccp_t *ccp=container_of(ld,typeof(*ccp),ld);
log_ppp_debug("ccp_layer_finish\n");
+
+ ccp_set_flags(ccp->ppp->unit_fd, 0, 0);
ccp->fsm.fsm_state = FSM_Closed;
ppp_layer_finished(ccp->ppp,&ccp->ld);
@@ -146,6 +177,10 @@ static void ccp_layer_up(struct ppp_fsm_t *fsm)
struct ppp_ccp_t *ccp=container_of(fsm,typeof(*ccp),fsm);
log_ppp_debug("ccp_layer_started\n");
ccp->started = 1;
+ if (ccp_set_flags(ccp->ppp->unit_fd, 1, 1)) {
+ ppp_terminate(ccp->ppp, 0);
+ return;
+ }
ppp_layer_started(ccp->ppp,&ccp->ld);
}
@@ -174,38 +209,45 @@ static void print_ropt(struct recv_opt_t *ropt)
static int send_conf_req(struct ppp_fsm_t *fsm)
{
- struct ppp_ccp_t *ccp=container_of(fsm,typeof(*ccp),fsm);
- uint8_t *buf=_malloc(ccp->conf_req_len), *ptr=buf;
- struct ccp_hdr_t *ccp_hdr=(struct ccp_hdr_t*)ptr;
+ struct ppp_ccp_t *ccp = container_of(fsm, typeof(*ccp), fsm);
+ uint8_t *buf, *ptr;
+ struct ccp_hdr_t *ccp_hdr;
struct ccp_option_t *lopt;
int n;
- log_ppp_debug("send [CCP ConfReq");
- ccp_hdr->proto=htons(PPP_CCP);
- ccp_hdr->code=CONFREQ;
- ccp_hdr->id=++ccp->fsm.id;
- ccp_hdr->len=0;
- log_ppp_debug(" id=%x",ccp_hdr->id);
+ ccp->need_req = 0;
+
+ if (ccp->passive)
+ return 0;
+
+ buf = _malloc(ccp->conf_req_len);
+ ccp_hdr = (struct ccp_hdr_t*)buf;
+
+ ccp_hdr->proto = htons(PPP_CCP);
+ ccp_hdr->code = CONFREQ;
+ ccp_hdr->id = ++ccp->fsm.id;
+ ccp_hdr->len = 0;
- ptr+=sizeof(*ccp_hdr);
+ ptr = (uint8_t*)(ccp_hdr + 1);
- list_for_each_entry(lopt,&ccp->options,entry)
- {
- n=lopt->h->send_conf_req(ccp,lopt,ptr);
+ log_ppp_debug("send [CCP ConfReq id=%x", ccp_hdr->id);
+
+ list_for_each_entry(lopt,&ccp->options,entry) {
+ n = lopt->h->send_conf_req(ccp,lopt,ptr);
if (n < 0)
return -1;
- if (n)
- {
+ if (n) {
log_ppp_debug(" ");
- lopt->h->print(log_ppp_debug,lopt,NULL);
- ptr+=n;
+ lopt->h->print(log_ppp_debug, lopt, NULL);
+ lopt->state = CCP_OPT_ACK;
}
+ ptr += n;
}
log_ppp_debug("]\n");
-
- ccp_hdr->len=htons((ptr-buf)-2);
- ppp_unit_send(ccp->ppp,ccp_hdr,ptr-buf);
+
+ ccp_hdr->len = htons((ptr-buf)-2);
+ ppp_unit_send(ccp->ppp, ccp_hdr, ptr-buf);
_free(buf);
@@ -298,9 +340,10 @@ static int ccp_recv_conf_req(struct ppp_ccp_t *ccp,uint8_t *data,int size)
struct ccp_opt_hdr_t *hdr;
struct recv_opt_t *ropt;
struct ccp_option_t *lopt;
- int r,ret=1,ack=0;
+ int r, ret = 1, ack = 0;
- ccp->ropt_len=size;
+ ccp->need_req = 0;
+ ccp->ropt_len = size;
while(size>0)
{
@@ -318,41 +361,37 @@ static int ccp_recv_conf_req(struct ppp_ccp_t *ccp,uint8_t *data,int size)
size-=ropt->len;
}
- list_for_each_entry(lopt,&ccp->options,entry)
- lopt->state=CCP_OPT_NONE;
-
- log_ppp_debug("recv [CCP ConfReq id=%x",ccp->fsm.recv_id);
- list_for_each_entry(ropt,&ccp->ropt_list,entry)
+ log_ppp_debug("recv [CCP ConfReq id=%x", ccp->fsm.recv_id);
+ list_for_each_entry(ropt, &ccp->ropt_list, entry)
{
- list_for_each_entry(lopt,&ccp->options,entry)
+ list_for_each_entry(lopt, &ccp->options, entry)
{
- if (lopt->id==ropt->hdr->id)
- {
+ if (lopt->id == ropt->hdr->id) {
log_ppp_debug(" ");
- lopt->h->print(log_ppp_debug,lopt,(uint8_t*)ropt->hdr);
- r=lopt->h->recv_conf_req(ccp,lopt,(uint8_t*)ropt->hdr);
- if (ack)
- {
- lopt->state=CCP_OPT_REJ;
- ropt->state=CCP_OPT_REJ;
- }else
- {
- lopt->state=r;
- ropt->state=r;
+ lopt->h->print(log_ppp_debug, lopt, (uint8_t*)ropt->hdr);
+ r = lopt->h->recv_conf_req(ccp, lopt, (uint8_t*)ropt->hdr);
+ if (ack) {
+ lopt->state = CCP_OPT_REJ;
+ ropt->state = CCP_OPT_REJ;
+ } else {
+ if (lopt->state == CCP_OPT_NAK && r == CCP_OPT_ACK)
+ ccp->need_req = 1;
+ lopt->state = r;
+ ropt->state = r;
}
- ropt->lopt=lopt;
- if (r<ret) ret=r;
+ ropt->lopt = lopt;
+ if (r < ret)
+ ret = r;
break;
}
}
- if (ropt->state==CCP_OPT_ACK || ropt->state==CCP_OPT_NAK)
- ack=1;
- else if (!ropt->lopt)
- {
+ if (ropt->state == CCP_OPT_ACK || ropt->state == CCP_OPT_NAK)
+ ack = 1;
+ else if (!ropt->lopt) {
log_ppp_debug(" ");
print_ropt(ropt);
- ropt->state=CCP_OPT_REJ;
- ret=CCP_OPT_REJ;
+ ropt->state = CCP_OPT_REJ;
+ ret = CCP_OPT_REJ;
}
}
log_ppp_debug("]\n");
@@ -570,14 +609,22 @@ static void ccp_recv(struct ppp_handler_t*h)
break;
}
ccp_free_conf_req(ccp);
- if (r==CCP_OPT_FAIL)
+
+ if (r == CCP_OPT_ACK && ccp->passive) {
+ ccp->passive = 0;
+ send_conf_req(&ccp->fsm);
+ }
+ if (r == CCP_OPT_FAIL)
ppp_terminate(ccp->ppp, 0);
break;
case CONFACK:
if (ccp_recv_conf_ack(ccp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN))
ppp_terminate(ccp->ppp, 0);
- else
+ else {
ppp_fsm_recv_conf_ack(&ccp->fsm);
+ if (ccp->need_req)
+ send_conf_req(&ccp->fsm);
+ }
break;
case CONFNAK:
ccp_recv_conf_nak(ccp,(uint8_t*)(hdr+1),ntohs(hdr->len)-PPP_HDRLEN);
@@ -625,6 +672,19 @@ int ccp_option_register(struct ccp_option_handler_t *h)
return 0;
}
+struct ccp_option_t *ccp_find_option(struct ppp_t *ppp, struct ccp_option_handler_t *h)
+{
+ struct ppp_ccp_t *ccp = container_of(ppp_find_layer_data(ppp, &ccp_layer), typeof(*ccp), ld);
+ struct ccp_option_t *opt;
+
+ list_for_each_entry(opt, &ccp->options, entry)
+ if (opt->h == h)
+ return opt;
+
+ log_emerg("ccp: BUG: option not found\n");
+ abort();
+}
+
static struct ppp_layer_t ccp_layer=
{
.init=ccp_layer_init,