diff options
Diffstat (limited to 'accel-pptpd/ppp.c')
-rw-r--r-- | accel-pptpd/ppp.c | 368 |
1 files changed, 280 insertions, 88 deletions
diff --git a/accel-pptpd/ppp.c b/accel-pptpd/ppp.c index b032b064..58f99dc9 100644 --- a/accel-pptpd/ppp.c +++ b/accel-pptpd/ppp.c @@ -17,21 +17,33 @@ #include "log.h" #include "events.h" -static void ppp_read(struct triton_md_handler_t*); -static void ppp_write(struct triton_md_handler_t*); -static void ppp_timeout(struct triton_md_handler_t*); +static LIST_HEAD(layers); -struct ppp_t *alloc_ppp(void) +struct layer_node_t +{ + struct list_head entry; + int order; + struct list_head items; +}; + +static void ppp_chan_read(struct triton_md_handler_t*); +static void ppp_unit_read(struct triton_md_handler_t*); +static void init_layers(struct ppp_t *); +static void start_first_layer(struct ppp_t *); + +struct ppp_t *init_ppp(void) { struct ppp_t *ppp=malloc(sizeof(*ppp)); memset(ppp,0,sizeof(*ppp)); - ppp->out_buf=malloc(PPP_MTU+PPP_HDRLEN); - ppp->in_buf=malloc(PPP_MRU+PPP_HDRLEN); - ppp->mtu=PPP_MTU; - ppp->mru=PPP_MRU; return ppp; } +static void free_ppp(struct ppp_t *ppp) +{ + free(ppp->chan_buf); + free(ppp->unit_buf); +} + int establish_ppp(struct ppp_t *ppp) { /* Open an instance of /dev/ppp and connect the channel to it */ @@ -65,42 +77,75 @@ int establish_ppp(struct ppp_t *ppp) if (ioctl(ppp->unit_fd, PPPIOCNEWUNIT, &ppp->unit_idx)<0) { log_error("Couldn't create new ppp unit\n"); - goto exit_clodse_unit; + goto exit_close_unit; } if (ioctl(ppp->chan_fd, PPPIOCCONNECT, &ppp->unit_idx)<0) { log_error("Couldn't attach to PPP unit %d\n", ppp->unit_idx); - goto exit_clodse_unit; + goto exit_close_unit; } log_info("connect: ppp%i <--> pptp(%s)\n",ppp->unit_idx,ppp->chan_name); + + ppp->chan_buf=malloc(PPP_MRU); + ppp->unit_buf=malloc(PPP_MRU); - ppp->h=malloc(sizeof(*ppp->h)); - memset(ppp->h,0,sizeof(*ppp->h)); - ppp->h->pd=ppp; - ppp->h->fd=ppp->chan_fd; - ppp->h->read=ppp_read; - ppp->h->write=ppp_write; - ppp->h->timeout=ppp_timeout; - ppp->h->twait=-1; - triton_md_register_handler(ppp->h); - triton_md_enable_handler(ppp->h,MD_MODE_READ); - INIT_LIST_HEAD(&ppp->handlers); - - ppp->cur_layer=PPP_LAYER_LCP; + INIT_LIST_HEAD(&ppp->chan_handlers); + INIT_LIST_HEAD(&ppp->unit_handlers); - lcp_start(ppp); + init_layers(ppp); + + if (list_empty(&ppp->layers)) + { + log_error("no layers to start\n"); + goto exit_close_unit; + } + + ppp->chan_hnd.fd=ppp->chan_fd; + ppp->chan_hnd.read=ppp_chan_read; + ppp->chan_hnd.twait=-1; + ppp->unit_hnd.fd=ppp->unit_fd; + ppp->unit_hnd.read=ppp_unit_read; + ppp->unit_hnd.twait=-1; + triton_md_register_handler(&ppp->chan_hnd); + triton_md_register_handler(&ppp->unit_hnd); + + triton_md_enable_handler(&ppp->chan_hnd,MD_MODE_READ); + triton_md_enable_handler(&ppp->unit_hnd,MD_MODE_READ); + + log_debug("ppp established\n"); + + start_first_layer(ppp); return 0; -exit_clodse_unit: +exit_close_unit: close(ppp->unit_fd); exit_close_chan: close(ppp->chan_fd); + + free_ppp(ppp); + return -1; } +void destablish_ppp(struct ppp_t *ppp) +{ + triton_md_unregister_handler(&ppp->chan_hnd); + triton_md_unregister_handler(&ppp->unit_hnd); + + close(ppp->unit_fd); + close(ppp->chan_fd); + + free(ppp->unit_buf); + free(ppp->chan_buf); + + log_debug("ppp destablished\n"); + + if (ppp->events.finished) ppp->events.finished(ppp); +} + void print_buf(uint8_t *buf,int size) { int i; @@ -109,41 +154,51 @@ void print_buf(uint8_t *buf,int size) printf("\n"); } -int ppp_send(struct ppp_t *ppp, void *data, int size) +int ppp_chan_send(struct ppp_t *ppp, void *data, int size) { int n; - if (ppp->out_buf_size) return -1; - if (size>PPP_MTU+PPP_HDRLEN) return -1; + printf("ppp_chan_send: "); + print_buf((uint8_t*)data,size); + + n=write(ppp->chan_fd,data,size); + if (n<size) + log_error("ppp_chan_send: short write %i, excpected %i\n",n,size); + return n; +} - printf("ppp: send: "); +int ppp_unit_send(struct ppp_t *ppp, void *data, int size) +{ + int n; + + printf("ppp_unit_send: "); print_buf((uint8_t*)data,size); n=write(ppp->unit_fd,data,size); - /*if (n>=0) - { - if (n!=ppp->out_buf_size-ppp->out_buf_pos) - { - ppp->out_buf_pos+=n; - triton_md_enable_handler(ppp->h,MD_MODE_WRITE); - } - }*/ + if (n<size) + log_error("ppp_unit_send: short write %i, excpected %i\n",n,size); return n; } -static void ppp_read(struct triton_md_handler_t*h) +static void ppp_chan_read(struct triton_md_handler_t*h) { - struct ppp_t *ppp=(struct ppp_t *)h->pd; - struct ppp_handler_t *ppp_h=NULL; + struct ppp_t *ppp=container_of(h,typeof(*ppp),chan_hnd); + struct ppp_handler_t *ppp_h; uint16_t proto; - ppp->in_buf_size=read(h->fd,ppp->in_buf,PPP_MRU+PPP_HDRLEN); + ppp->chan_buf_size=read(h->fd,ppp->chan_buf,PPP_MRU); + + printf("ppp_chan_read: "); + print_buf(ppp->chan_buf,ppp->chan_buf_size); - printf("ppp: recv: "); - print_buf(ppp->in_buf,ppp->in_buf_size); + if (ppp->chan_buf_size<2) + { + log_error("ppp_chan_read: short read %i\n",ppp->chan_buf_size); + return; + } - proto=ntohs(*(uint16_t*)ppp->in_buf); - list_for_each_entry(ppp_h,&ppp->handlers,entry) + proto=ntohs(*(uint16_t*)ppp->chan_buf); + list_for_each_entry(ppp_h,&ppp->chan_handlers,entry) { if (ppp_h->proto==proto) { @@ -152,75 +207,212 @@ static void ppp_read(struct triton_md_handler_t*h) } } - log_warn("discarding unknown packet %x\n",proto); + log_warn("ppp_chan_read: discarding unknown packet %x\n",proto); } -static void ppp_write(struct triton_md_handler_t*h) + +static void ppp_unit_read(struct triton_md_handler_t*h) { - struct ppp_t *ppp=(struct ppp_t *)h->pd; + struct ppp_t *ppp=container_of(h,typeof(*ppp),unit_hnd); + struct ppp_handler_t *ppp_h; + uint16_t proto; - int n=write(ppp->unit_fd,ppp->out_buf+ppp->out_buf_pos,ppp->out_buf_size-ppp->out_buf_pos); - if (n>=0) + ppp->unit_buf_size=read(h->fd,ppp->unit_buf,PPP_MRU); + + printf("ppp_unit_read: "); + print_buf(ppp->unit_buf,ppp->unit_buf_size); + + if (ppp->unit_buf_size<2) { - ppp->out_buf_pos+=n; - if (ppp->out_buf_pos==ppp->out_buf_size) + log_error("ppp_chan_read: short read %i\n",ppp->unit_buf_size); + return; + } + + proto=ntohs(*(uint16_t*)ppp->unit_buf); + list_for_each_entry(ppp_h,&ppp->unit_handlers,entry) + { + if (ppp_h->proto==proto) { - triton_md_disable_handler(ppp->h,MD_MODE_WRITE); - ppp->out_buf_pos=0; - ppp->out_buf_size=0; + ppp_h->recv(ppp_h); + return; } } + + log_warn("ppp_chan_read: discarding unknown packet %x\n",proto); } -static void ppp_timeout(struct triton_md_handler_t*h) + +void ppp_layer_started(struct ppp_t *ppp, struct ppp_layer_data_t *d) { + struct layer_node_t *n=d->node; + + d->started=1; + + list_for_each_entry(d,&n->items,entry) + if (!d->started) return; + if (n->entry.next==&ppp->layers) + { + if (ppp->events.started) ppp->events.started(ppp); + }else + { + n=list_entry(n->entry.next,typeof(*n),entry); + list_for_each_entry(d,&n->items,entry) + d->layer->start(d); + } } -void ppp_layer_started(struct ppp_t *ppp) +void ppp_layer_finished(struct ppp_t *ppp, struct ppp_layer_data_t *d) { - switch(ppp->cur_layer) + struct layer_node_t *n=d->node; + + d->started=0; + + list_for_each_entry(d,&n->items,entry) + if (d->started) return; + + if (n->entry.prev==&ppp->layers) destablish_ppp(ppp); + else { - case PPP_LAYER_LCP: - ppp->cur_layer++; - if (auth_start(ppp)) - break; - case PPP_LAYER_AUTH: - ppp->cur_layer++; - if (ccp_start(ppp)) - break; - case PPP_LAYER_CCP: - ppp->cur_layer++; - if (ipcp_start(ppp)) - break; - case PPP_LAYER_IPCP: - break; + n=list_entry(n->entry.prev,typeof(*n),entry); + list_for_each_entry(d,&n->items,entry) + if (d->started) d->layer->finish(d); } } + void ppp_terminate(struct ppp_t *ppp) { - switch(ppp->cur_layer) + struct layer_node_t *n; + struct list_head *p; + struct ppp_layer_data_t *d; + int s=0; + + log_debug("ppp_terminate\n"); + + list_for_each_prev(p,&ppp->layers) { - case PPP_LAYER_IPCP: - ppp->cur_layer--; - ipcp_finish(ppp); - case PPP_LAYER_CCP: - ppp->cur_layer--; - ccp_finish(ppp); - case PPP_LAYER_AUTH: - ppp->cur_layer--; - auth_finish(ppp); - case PPP_LAYER_LCP: - ppp->cur_layer--; - lcp_finish(ppp); + list_for_each_entry(d,&n->items,entry) + { + if (d->started) + { + s=1; + d->layer->finish(d); + } + } + if (s) return; } + destablish_ppp(ppp); } - -void ppp_register_handler(struct ppp_t *ppp,struct ppp_handler_t *h) +void ppp_register_chan_handler(struct ppp_t *ppp,struct ppp_handler_t *h) +{ + list_add_tail(&h->entry,&ppp->chan_handlers); +} +void ppp_register_unit_handler(struct ppp_t *ppp,struct ppp_handler_t *h) { - list_add_tail(&h->entry,&ppp->handlers); + list_add_tail(&h->entry,&ppp->unit_handlers); } void ppp_unregister_handler(struct ppp_t *ppp,struct ppp_handler_t *h) { list_del(&h->entry); } +static int get_layer_order(const char *name) +{ + if (!strcmp(name,"lcp")) return 0; + if (!strcmp(name,"auth")) return 1; + if (!strcmp(name,"ipcp")) return 2; + if (!strcmp(name,"ccp")) return 2; + return -1; +} + +int ppp_register_layer(const char *name, struct ppp_layer_t *layer) +{ + int order; + struct layer_node_t *n,*n1; + + order=get_layer_order(name); + + if (order<0) + return order; + + list_for_each_entry(n,&layers,entry) + { + if (order>n->order) + continue; + if (order<n->order) + { + n1=malloc(sizeof(*n1)); + memset(n1,0,sizeof(*n1)); + n1->order=order; + INIT_LIST_HEAD(&n1->items); + list_add_tail(&n1->entry,&n->entry); + n=n1; + } + goto insert; + } + n1=malloc(sizeof(*n1)); + memset(n1,0,sizeof(*n1)); + n1->order=order; + INIT_LIST_HEAD(&n1->items); + list_add_tail(&n1->entry,&layers); + n=n1; +insert: + list_add_tail(&layer->entry,&n->items); + + return 0; +} +void ppp_unregister_layer(struct ppp_layer_t *layer) +{ + list_del(&layer->entry); +} + +static void init_layers(struct ppp_t *ppp) +{ + struct layer_node_t *n,*n1; + struct ppp_layer_t *l; + struct ppp_layer_data_t *d; + + INIT_LIST_HEAD(&ppp->layers); + + list_for_each_entry(n,&layers,entry) + { + n1=(struct layer_node_t*)malloc(sizeof(*n1)); + memset(n1,0,sizeof(*n1)); + INIT_LIST_HEAD(&n1->items); + list_add_tail(&n1->entry,&ppp->layers); + list_for_each_entry(l,&n->items,entry) + { + d=l->init(ppp); + d->layer=l; + d->started=0; + d->node=n1; + list_add_tail(&d->entry,&n1->items); + } + } +} + +static void start_first_layer(struct ppp_t *ppp) +{ + struct layer_node_t *n; + struct ppp_layer_data_t *d; + + n=list_entry(ppp->layers.next,typeof(*n),entry); + list_for_each_entry(d,&n->items,entry) + d->layer->start(d); +} + +struct ppp_layer_data_t *ppp_find_layer_data(struct ppp_t *ppp, struct ppp_layer_t *layer) +{ + struct layer_node_t *n; + struct ppp_layer_data_t *d; + + list_for_each_entry(n,&ppp->layers,entry) + { + list_for_each_entry(d,&n->items,entry) + { + if (d->layer==layer) + return d; + } + } + + return NULL; +} |