📄 ppp.c
字号:
/* * Copyright (c) 2003 EISLAB, Lulea University of Technology. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * This file is part of the lwBT Bluetooth stack. * * Author: Conny Ohult <conny@sm.luth.se> * *//*-----------------------------------------------------------------------------------*//* ppp.c * * Implementation of the PPP protocol. * Used to carry packets from the higher IP layer across the RFCOMM serial port * emulation layer. *//*-----------------------------------------------------------------------------------*/#include "netif/lwbt/rfcomm.h"#include "netif/lwbt/ppp.h"#include "netif/lwbt/lwbt_memp.h"#include "netif/lwbt/fcs.h"#include "lwbtopts.h"#include "lwip/debug.h"struct ppp_pcb *ppp_listen_pcbs; /* List of all PPP PCBs listening for a connection */struct ppp_pcb *ppp_active_pcbs; /* List of all active PPP PCBs */struct ppp_pcb *ppp_tmp_pcb;struct ppp_req *ppp_tmp_req;u8_t id_nxt; /* Next Identifier to be sent *//* Forward declarations */err_t ppp_output(struct ppp_pcb *pcb, struct pbuf *p);err_t ppp_cp_output(struct ppp_pcb *pcb, u16_t proto, u8_t code, u8_t id, struct pbuf *q);u8_t ppp_next_id(void);struct pbuf *lcp_cfg_req(struct ppp_pcb *pcb, struct pbuf *options);err_t ipcp_cfg_req(struct ppp_pcb *pcb);void ppp_pbuf_ref_chain(struct pbuf *p);/*-----------------------------------------------------------------------------------*//* * ppp_init(): * * Initializes the PPP layer. *//*-----------------------------------------------------------------------------------*/voidppp_init(void){ /* Clear globals */ ppp_active_pcbs = NULL; ppp_tmp_pcb = NULL; /* Initialize the lcp and ipcp identifier */ id_nxt = 0;}/*-----------------------------------------------------------------------------------*//* * ppp_tmr(): * * Called every 1s and implements the command timer that * removes a DLC if it has been waiting for a response enough * time. *//*-----------------------------------------------------------------------------------*/voidppp_tmr(void){ struct ppp_pcb *pcb; struct ppp_req *req; err_t ret; /* Step through all of the active pcbs */ for(pcb = ppp_active_pcbs; pcb != NULL; pcb = pcb->next) { /* Step through any unresponded requests */ for(req = pcb->reqs; req != NULL; req = req->next) { --req->rto; /* Adjust rto timer */ LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_tmr: req->rto = %d\n", req->rto)); /* Check if restart timer has expired */ if(req->rto == 0) { /* Check if max number of retransmissions have been reached */ if(req->nrtx == 0) { LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_tmr: Max number of retransmissions have been reached\n")); PPP_REQ_RMV(&(pcb->reqs), req); pbuf_free(req->p); LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_tmr: Free memory for request with ID 0x%x***********\n", req->id)); lwbt_memp_free(MEMP_PPP_REQ, req); pcb->state = PPP_LCP_CLOSED; PPP_EVENT_DISCONNECTED(pcb,ERR_CLSD,req->proto,ret); } else { --req->nrtx; /* Retransmitt request with timeout doubled. It may not exceed the configured timeout value */ req->rto = PPP_RTO/(req->nrtx + 1); LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_tmr: Retransmitt\n")); ppp_output(pcb, req->p); } } } }}/*-----------------------------------------------------------------------------------*//* * ppp_lp_disconnected(): * * Called by the application to indicate that the lower protocol disconnected. *//*-----------------------------------------------------------------------------------*/err_tppp_lp_disconnected(struct rfcomm_pcb *rfcommpcb){ struct ppp_pcb *pcb; err_t ret = ERR_OK; LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_lp_disconnected\n")); for(pcb = ppp_active_pcbs; pcb != NULL; pcb = pcb->next) { if(pcb->rfcommpcb == rfcommpcb) { pcb->state = PPP_LCP_CLOSED; PPP_EVENT_DISCONNECTED(pcb, ERR_OK, PPP_LCP, ret); return ret; /* Since there should be only one PPP connection */ } } for(pcb = ppp_listen_pcbs; pcb != NULL; pcb = pcb->next) { if(pcb->rfcommpcb == rfcommpcb) { pcb->state = PPP_LCP_CLOSED; PPP_EVENT_DISCONNECTED(pcb, ERR_OK, PPP_LCP, ret); return ret; /* Since there should be only one PPP connection */ } } return ret;}/*-----------------------------------------------------------------------------------*//* * ppp_process_lcp(): * * Parses the received LCP packet and handles it. *//*-----------------------------------------------------------------------------------*/voidppp_process_lcp(struct ppp_pcb *pcb, struct pbuf *p){ struct ppp_cp_hdr *cphdr; struct ppp_cfg_hdr *cfghdr; struct ppp_req *req; struct pbuf *r, *s; u8_t rspstate = LCP_CFG_ACK; u16_t len; err_t ret; cphdr = p->payload; pbuf_header(p, -PPP_CPHDR_LEN); cphdr->len = ntohs(cphdr->len); len = cphdr->len - PPP_CPHDR_LEN; if(cphdr->code == LCP_CFG_ACK || cphdr->code == LCP_CFG_NAK || cphdr->code == LCP_CFG_REJ || cphdr->code == LCP_CODE_REJ || cphdr->code == LCP_TERM_ACK) { for(req = pcb->reqs; req != NULL; req = req->next) { /* Remove any matching request */ if(cphdr->id == req->id) { PPP_REQ_RMV(&(pcb->reqs), req); pbuf_free(req->p); LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_process_lcp: Free memory for request with id 0x%x***********\n", req->id)); lwbt_memp_free(MEMP_PPP_REQ, req); } } } LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_process_lcp: cphdr->code = 0x%x\n", cphdr->code)); /* { struct pbuf *q; for(q = p; q != NULL; q = q->next) { u16_t i; for(i = 0; i < q->len; ++i) { LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_process_lcp: 0x%x\n", ((u8_t *)q->payload)[i])); } LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_process_lcp: q->len == %d q->tot_len == %d\n", q->len, q->tot_len)); }} */ r = NULL; switch(cphdr->code) { case LCP_CFG_REQ: LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_process_lcp: LCP_CFG_REQ\n")); if(pcb->state == PPP_LCP_CLOSED) { /* A terminate-ack is sent to indicate that we are in a closed state */ ppp_cp_output(pcb, PPP_LCP, LCP_TERM_ACK, ppp_next_id(), NULL); break; } else if(pcb->state == PPP_LCP_LISTEN) { /* If pcb in LISTEN state we move it to the active list */ PPP_RMV(&(ppp_listen_pcbs), pcb); PPP_REG(&ppp_active_pcbs, pcb); } pcb->state = PPP_LCP_CFG; while(len > 0) { cfghdr = p->payload; switch(cfghdr->type) { case LCP_CFG_MRU: /* ACK - Parameter accepted */ pcb->mru = ntohs(((u16_t *)p->payload)[1]); if(rspstate == LCP_CFG_ACK) { s = pbuf_alloc(PBUF_RAW, cfghdr->len, PBUF_RAM); memcpy((u8_t *)s->payload, (u8_t *)p->payload, cfghdr->len); if(r == NULL) { r = s; } else { pbuf_chain(r, s); pbuf_free(s); } } /* if rspstate == LCP_CFG_NAK or LCP_CFG_REJ do not add packet to outgoing pbuf */ case LCP_CFG_ACCM: /* ACK - Parameter accepted */ /* Since we will handle all characters that are escaped we do not need to save the ACCM for incoming data */ if(rspstate == LCP_CFG_ACK) { s = pbuf_alloc(PBUF_RAW, cfghdr->len, PBUF_RAM); memcpy((u8_t *)s->payload, (u8_t *)p->payload, cfghdr->len); if(r == NULL) { r = s; } else { pbuf_chain(r, s); pbuf_free(s); } } /* if rspstate == LCP_CFG_NAK or LCP_CFG_REJ do not add packet to outgoing pbuf */ break;#if PPP_AUTH case LCP_CFG_AUTH: //TODO: NOT IMPLEMENTDED break;#endif#if PPP_PHDR_COMP case LCP_CFG_P_COMP: pcb->lcpcfg |= LCP_CFG_IN_PCOMP; if(rspstate == LCP_CFG_ACK) { s = pbuf_alloc(PBUF_RAW, cfghdr->len, PBUF_RAM); memcpy((u8_t *)s->payload, (u8_t *)p->payload, cfghdr->len); if(r == NULL) { r = s; } else { pbuf_chain(r, s); pbuf_free(s); } } break;#endif /* PPP_PHDR_COMP */#if PPP_ACHDR_COMP case LCP_CFG_AC_COMP: pcb->lcpcfg |= LCP_CFG_IN_ACCOMP; if(rspstate == LCP_CFG_ACK) { s = pbuf_alloc(PBUF_RAW, cfghdr->len, PBUF_RAM); memcpy((u8_t *)s->payload, (u8_t *)p->payload, cfghdr->len); if(r == NULL) { r = s; } else { pbuf_chain(r, s); pbuf_free(s); } } break;#endif /* PPP_ACHDR_COMP */ default: /* Reject parameter */ if(rspstate != LCP_CFG_REJ) { rspstate = LCP_CFG_REJ; if(r != NULL) { pbuf_free(r); r = NULL; } } s = pbuf_alloc(PBUF_RAW, cfghdr->len, PBUF_RAM); memcpy((u8_t *)s->payload, (u8_t *)p->payload, cfghdr->len); if(r == NULL) { r = s; } else { pbuf_chain(r, s); pbuf_free(s); } break; } /* switch */ //pbuf_header(p, -(cfghdr->len - PPP_CFGHDR_LEN)); //len -= cfghdr->len - PPP_CFGHDR_LEN; pbuf_header(p, -(cfghdr->len)); len -= cfghdr->len; } /* while */ if(!(pcb->pppcfg & PPP_IR) && !(pcb->lcpcfg2 & LCP_CFG_OUT_REQ)) { /* Send a LCP configure request for outgoing link if it hasnt been configured */ p = lcp_cfg_req(pcb, NULL); ppp_cp_output(pcb, PPP_LCP, LCP_CFG_REQ, ppp_next_id(), p); pcb->lcpcfg2 |= LCP_CFG_OUT_REQ; } /* Send response to configuration request */ ppp_cp_output(pcb, PPP_LCP, rspstate, cphdr->id, r); if(rspstate == LCP_CFG_ACK) { pcb->lcpcfg |= LCP_CFG_OUT_ACK; /* LCP connection established if a configuration a ack has been received */ if(pcb->lcpcfg & LCP_CFG_IN_ACK) { if(pcb->lcpcfg & LCP_CFG_PAP && pcb->pppcfg & PPP_IR) { //TODO: CALL AUTHENTICATE FUNCTION IN UPPER LAYER /* Authenticate if we are the initiator */ } else { pcb->state = PPP_IPCP_CFG; if(pcb->pppcfg & PPP_IR) { /* Configure IPCP connection if we are the initiator */ if(ipcp_cfg_req(pcb) != ERR_OK) { LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_process_lcp: ipcp config request failed\n")); ppp_disconnect(pcb); } } } } } break; case LCP_CFG_ACK: LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_process_lcp: LCP_CFG_ACK\n")); if(pcb->state == PPP_LCP_CLOSED || pcb->state == PPP_LCP_LISTEN) { /* A terminate-ack is sent to indicate that we are in a closed state */ ppp_cp_output(pcb, PPP_LCP, LCP_TERM_ACK, ppp_next_id(), NULL); break; } pcb->lcpcfg |= LCP_CFG_IN_ACK; pcb->naks = 0; while(len > 0) { cfghdr = p->payload; //pbuf_header(p, -PPP_CFGHDR_LEN); //len -= PPP_CFGHDR_LEN; switch(cfghdr->type) { case LCP_CFG_MRU: /* Maximum receive unit that the implementation can receive. Doesnt need to be stored */ break; case LCP_CFG_ACCM: pcb->outaccm = ntohl(*((u32_t *)(((u16_t *)p->payload) + 1))); break;#if PPP_PHDR_COMP case LCP_CFG_P_COMP: pcb->lcpcfg |= LCP_CFG_OUT_PCOMP; break;#endif /* PPP_PHDR_COMP */#if PPP_ACHDR_COMP case LCP_CFG_AC_COMP: pcb->lcpcfg |= LCP_CFG_OUT_ACCOMP; break;#endif /* PPP_ACHDR_COMP */ default: /* Silently discard configuration option */ break; } /* switch */ pbuf_header(p, -cfghdr->len); len -= cfghdr->len; } /* while */ /* LCP connection established if a configuration a ack has been sent */ if(pcb->lcpcfg & LCP_CFG_OUT_ACK) { /* LCP connection established */ pcb->state = PPP_IPCP_CFG; if(pcb->pppcfg & PPP_IR) { /* Configure IPCP connection if we are the initiator */ if(ipcp_cfg_req(pcb) != ERR_OK) { LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_process_lcp: ipcp config request failed\n")); ppp_disconnect(pcb); } } } break; case LCP_CFG_NAK: LWIP_DEBUGF(LWBT_PPP_DEBUG, ("ppp_process_lcp: LCP_CFG_NAK\n")); if(pcb->state == PPP_LCP_CLOSED || pcb->state == PPP_LCP_LISTEN) { /* A terminate-ack is sent to indicate that we are in a closed state */ ppp_cp_output(pcb, PPP_LCP, LCP_TERM_ACK, ppp_next_id(), NULL); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -