📄 mp.c
字号:
} /* Insert new fragment before next element if possible. */ if (newfrag != NULL && (nextf == NULL || /* newseq < nextf->seq */ ((newseq-nextf->seq) & sbit) != 0)) { newfrag->next = nextf; frag->next = nextf = newfrag; newfrag = NULL; } /* Check for start */ if (start != NULL) { if (start != frag && (frag->flags & MP_BEGIN)) { syslog(LOG_NOTICE,"new BEGIN flag with no prior END"); while (start != frag) { nextf = start->next; free(start); start = nextf; } nextf = frag->next; /* Packet has been dropped. */ link->frame_drops++; } /* If thisseq <= minseq */ } else if (((minseq-thisseq) & sbit) == 0) { if (frag->flags & MP_BEGIN) start = frag; else { syslog(LOG_NOTICE,"missing BEGIN; dropping %lu",thisseq); if (frag->flags & MP_END) /* Packet has been dropped. */ link->frame_drops++; free(frag); if ((frag = nextf) == NULL) break; /* special case; have to allow for gaps here. */ goto nextfrag; } } if (start != NULL && (frag->flags & MP_END)) { /* * This next statement is not actually necessary, but can be * helpful in multitasking systems where delivery of a packet * may cause a task switch. */ mp->frags = nextf; /* Reassemble packet into local buffer */ bp = buffer; minseq = link->seq = (thisseq+1)&smask; while (start != nextf) { frag = start->next; if (bp != NULL && (bp-buffer)+start->length <= MAX_MRRU) { if (start->length > 0) { memcpy(bp,start->data,start->length); bp += start->length; } } else bp = NULL; free(start); start = frag; } start = NULL; frag = NULL; /* * "bp" is used as a flag -- it's set to NULL when packet * is dropped. At this point, it's null if the packet was * dropped due to MRRU. * * All reassembled and unfragmented data gets dispatched. */ if (bp != NULL && bp > buffer+1) { inlen = bp-buffer; bp = buffer; proto = *bp++; inlen--; if (!(proto & 1)) { proto = (proto << 8) | *bp++; inlen--; } /* Discard frames with illegal protocol fields or missing data. */ if (inlen <= 0 || (proto & 0x101) != 1) bp = NULL; /* * If we're doing bundle level ECP, then we process it * first. This is done to make the ECP code symmetric * with respect to the link level handling. */ if (bp != NULL && link->ecp_in_use && proto == PPP_PROTO_EP) { xcp = find_xcp(link,PPP_PROTO_EP); bp = ecp_decrypt(xcp,bp,&inlen); if (inlen < 1) bp = NULL; if (bp != NULL) { proto = *bp++; inlen--; if (!(proto & 1)) { if (inlen < 1) bp = NULL; else { proto = (proto << 8) | *bp++; inlen--; } } } } /* * If we're doing bundle level CCP, then we have to do it * before demultiplexing because CCP usually needs to inspect * all data. */ if (bp != NULL && link->ccp_in_use) { xcp = find_xcp(link,PPP_PROTO_CP); if (proto == PPP_PROTO_CP) { bp = ccp_uncompress(xcp,bp,&inlen); if (inlen < 1) bp = NULL; if (bp != NULL) { proto = *bp++; inlen--; if (!(proto & 1)) { if (inlen < 1) bp = NULL; else { proto = (proto << 8) | *bp++; inlen--; } } } } else ccp_uncompressed(xcp,proto,bp,inlen); } if (bp != NULL) { /* Dispatch to appropriate handler now. */ xcp = find_xcp(link,proto); if (xcp != NULL) (*xcp->handler)(xcp,bp,inlen); else { /* No handler for this protocol, log it and reject it. */ send_lcp_protocol_reject(lptr,proto,bp,inlen); } } } if (bp == NULL) link->frame_drops++; mp->frags = NULL; } /* * If the next one is not contiguous then we don't have a complete * packet. */ if (nextf == NULL || ((thisseq+1)&smask) != nextf->seq) { if (frag == NULL) ; /* if thisseq < minseq */ else if (((thisseq-minseq) & sbit) != 0) { /* Packet has been dropped. */ syslog(LOG_DEBUG,"sequence %lu less than %lu",thisseq,minseq); link->frame_drops++; if (start != NULL) while (start != nextf) { frag = start->next; free(start); start = frag; } frag = NULL; } else if (mp->frags == NULL) mp->frags = start; start = NULL; } else { /* If we just reassembled and the next one is here, then do it. */ if (frag == NULL) { if (nextf->flags & MP_BEGIN) start = nextf; else syslog(LOG_NOTICE, "END flag with no following BEGIN on %lu", nextf->seq); } } if (start == NULL && frag != NULL && mp->frags == NULL) mp->frags = frag; frag = nextf; } if (mp->frags == NULL) mp->frags = frag;}/* * This is called after a link goes through LCP and authentication, * but before any NCPs begin running. If the link is part of a bundle, * then it is joined, otherwise a new bundle is created. Assumes that * PPP MRRU has been negotiated. * * Returns pointer to link for bundle head. */struct ppp_link *find_bundle_head(struct ppp_link *newlink){ struct mp_state *mp; struct xcp_state *xcp,*xcpp,*xcpn; /* Search for matching bundle based on peer name and ED. */ for (mp = global_mp_list; mp != NULL; mp = mp->next) if (((newlink->peername == NULL && mp->links->peername == NULL) || (newlink->peername != NULL && mp->links->peername != NULL && newlink->pn_size == mp->links->pn_size && memcmp(newlink->peername,mp->links->peername,newlink->pn_size) == 0)) && ((newlink->endpoint == NULL && mp->links->endpoint == NULL) || (newlink->endpoint != NULL && mp->links->endpoint != NULL && newlink->ep_size == mp->links->ep_size && memcmp(newlink->endpoint,mp->links->endpoint,newlink->ep_size) == 0))) break; /* If no such bundle exists, then create it now. */ if (mp == NULL) { struct ppp_link *lptr; mp = malloc(sizeof(*mp)); if (mp == NULL) return NULL; memset(mp,'\0',sizeof(*mp)); mp->links = NULL; mp->frags = NULL; mp->next = global_mp_list; global_mp_list = mp; lptr = mp->lptr = create_ppp_link(NULL,NULL); /* Everything but LCP and authentication moves to bundle level. */ xcpp = NULL; for (xcp = newlink->xcp_list; xcp != NULL; xcpp = xcp, xcp = xcpn) { xcpn = xcp->next; if (xcp->proto < 0xC000 && xcp->proto != PPP_PROTO_ECP_LINK && xcp->proto != PPP_PROTO_CCP_LINK) { if (xcpp != NULL) xcpp->next = xcp->next; else newlink->xcp_list = xcp->next; xcp->next = lptr->xcp_list; lptr->xcp_list = xcp; xcp->link = lptr; xcp = xcpp; } } lptr->mp = mp; /* * The MP defragmenter actually lives at the bundle level, since * all links actually demultiplex at the bundle level. */ lptr->handle = add_xcp(lptr,PPP_PROTO_MP,mp_handler,NULL); lptr->link_output = mp_output; } else { /* Remove unwanted XCPs */ for (xcp = newlink->xcp_list; xcp != NULL; xcp = xcpn) { xcpn = xcp->next; if (xcp->proto < 0xC000 && xcp->proto != PPP_PROTO_ECP_LINK && xcp->proto != PPP_PROTO_CCP_LINK) destroy_xcp(xcp); } } /* Next output link must not be this new one unless it's the only one. */ if (mp->next_out_link == NULL) mp->next_out_link = mp->links; /* Attach the link to the bundle. */ newlink->seq = mp->lptr->seq; newlink->next = mp->links; mp->links = newlink; mp->numlinks++; newlink->mp = mp; return mp->lptr;}/* * Add an XCP to a PPP link. */void *add_xcp(struct ppp_link *lptr, uint16 proto, void (*handler)(struct xcp_state *xcp, octet *indata, int inlen), void (*sender)(struct xcp_state *xcp, octet *indata, int inlen)){ struct xcp_state *xcp; xcp = (struct xcp_state *)malloc(sizeof(*xcp)); if (xcp == NULL) return NULL; memset(xcp,'\0',sizeof(*xcp)); xcp->state = Initial; xcp->proto = proto; xcp->handler = handler; xcp->send_data = sender; xcp->link = lptr; xcp->next = lptr->xcp_list; lptr->xcp_list = xcp; return (void *)xcp;}/* * Normal data sender for most NCP protocols. */voidgeneric_sender(struct xcp_state *xcp, octet *outdata, int outlen){ struct ppp_link *lptr = xcp->link; (*lptr->link_output)(lptr,outdata,outlen,xcp->proto);}/* * This function creates a new PPP state structure for a single PPP * link. The outhandler function will be called with the user's handle * (a blind pointer), a pointer to the data to send, and the length * of the data. */void *create_ppp_link(void *handle, void (*outhandler)(void *handle, octet *data, int datalen)){ struct ppp_link *lptr; lptr = (struct ppp_link *)malloc(sizeof(*lptr)); if (lptr == NULL) return NULL; memset(lptr,'\0',sizeof(*lptr)); lptr->xcp_list = NULL; lptr->handle = handle; lptr->link_output = normal_output; lptr->user_output = outhandler; lptr->mtu = 1500; lptr->mp = NULL; if (add_xcp(lptr,PPP_PROTO_LCP,lcp_handler,generic_sender) == NULL) { destroy_ppp_link((void *)lptr); return NULL; } /* Other NCPs may be initialized here with add_xcp or added later. */ return (void *)lptr;}/* * Remove storage associated with an XCP. */voiddestroy_xcp(struct xcp_state *xcp){ struct ppp_link *lptr = xcp->link; struct xcp_state *xcprev; if (xcp == lptr->xcp_list) lptr->xcp_list = xcp->next; else { for (xcprev = lptr->xcp_list; xcprev != NULL; xcprev = xcprev->next) if (xcprev->next == xcp) { xcprev->next = xcp->next; break; } } free(xcp);}/* * Delete an MP session. */static voiddestroy_mp(struct mp_state *mp){ struct mp_state *mlp; struct mp_fragment *frag,*fragn; if (global_mp_list == mp) global_mp_list = mp->next; else { for (mlp = global_mp_list; mlp != NULL; mlp = mlp->next) if (mlp->next == mp) { mlp->next = mp->next; break; } } fragn = mp->frags; while ((frag = fragn) != NULL) { fragn = frag->next; free(frag); } free(mp);}/* * Detach a link from an MP bundle and tear down the bundle if no * more links are active. */static voidmp_detach(struct ppp_link *link){ struct mp_state *mp = link->mp; struct ppp_link *lp; link->mp = NULL; if (--mp->numlinks <= 0) { destroy_mp(mp); return; } if (mp->links == link) mp->links = link->next; else { for (lp = mp->links; lp != NULL; lp = lp->next) if (lp->next == link) { lp->next = link->next; break; } } if (mp->next_out_link == link) mp->next_out_link = NULL;}/* * Tear down a PPP link. */voiddestroy_ppp_link(void *link){ struct ppp_link *lptr = (struct ppp_link *)link; struct xcp_state *xcp; if (lptr->mp != NULL) mp_detach(lptr); while ((xcp = lptr->xcp_list) != NULL) destroy_xcp(xcp); free(lptr);}/* Only for testing purposes. */voidset_link_mtu(void *handle, int mtu){ struct ppp_link *lptr = (struct ppp_link *)handle; lptr->mtu = mtu;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -