?? mp.c
字號:
/* * Multilink PPP example code. * * Assumptions: * * Input data is in linear buffers, which probably * isn't the case for many implementations, and input * buffers have sufficient leading and trailing padding * to allow for any expansion necessary. * * Strict adherence to RFC 1661 is desired, which may not * necessarily be the case for the protocol field. * * Underlying machine has 8-bit bytes and a fairly modern * architecture. * * This code may be used for any purpose as long as the author's * copyright is cited in any source code distributed. This code * is also available electronically from the author's web site. * * http://people.ne.mediaone.net/carlson/ppp * * http://www.workingcode.com/ppp * * Copyright 1997 by James Carlson and Working Code */#include <stdlib.h>#include <syslog.h>#include "sysdep.h"#include "mp.h"/* Contains information for a single fragment awaiting reassembly. */struct mp_fragment { struct mp_fragment *next; /* Next fragment in sequence */ int length; /* Length of this fragment */ uint32 seq; /* Sequence number */ octet flags; /* Begin/end flags */ octet data[1]; /* Data */};/* State data needed for MP level between bundle and links */struct mp_state { struct mp_state *next; /* Next MP bundle in system */ struct ppp_link *lptr; /* Pointer to bundle-level session */ struct ppp_link *links; /* Pointer to member links */ struct ppp_link *in_on; /* Link over which last packet arrived */ struct ppp_link *next_out_link; /* Next output link to use */ int numlinks; /* Number member links */ BOOLEAN snd_short_seq; /* Send short sequence numbers */ BOOLEAN rcv_short_seq; /* Accept short sequence numbers */ uint32 send_seq; /* Next sequence number to send */ struct mp_fragment *frags; /* List of received fragments */};/* List of all MP sessions in system */static struct mp_state *global_mp_list = NULL;/* * Locate a given NCP handler by PPP protocol ID. */static struct xcp_state *find_xcp(struct ppp_link *lptr, uint16 proto){ struct xcp_state *xcp; for (xcp = lptr->xcp_list; xcp != NULL; xcp = xcp->next) if (xcp->proto == proto) break; return xcp;}/* * Send an LCP reject for an unknown protocol. */static voidsend_lcp_protocol_reject(struct ppp_link *lptr, uint16 proto, octet *indata, int inlen){ struct xcp_state *xcp; xcp = find_xcp(lptr,PPP_PROTO_LCP); if (xcp == NULL || xcp->state != Opened) return; syslog(LOG_DEBUG,"Unknown protocol %04X; rejecting.",proto); /* Add LCP protocol reject header */ indata -= 6; indata[0] = PROTO_REJ; indata[1] = ++xcp->id_number; indata[2] = inlen >> 8; indata[3] = inlen & 0xFF; indata[4] = proto >> 8; indata[5] = proto & 0xFF; inlen += 6; (*xcp->send_data)(xcp,indata,inlen);}/* * Next level handler above HDLC or AHDLC. Assumes that CRC has been * verified and removed, and that all escaping (transparency) * characters have been handled. The PPP processing continues here by * decoding the address and control fields, then by demultiplexing * based on the PPP protocol number. */voidlink_receive(struct ppp_link *lptr, octet *indata, int inlen){ uint16 proto; struct xcp_state *xcp; if (inlen < 2) return; /* Handle address and control field compression */ if (lptr->acfc_in) { if (indata[0] == 0xFF && indata[1] == 0x03) { indata += 2; inlen -= 2; } } else { if (indata[0] != 0xFF || indata[1] != 0x03) { lptr->frame_drops++; return; } indata += 2; inlen -= 2; } /* Handle protocol field compression */ if (lptr->pfc_in) { if (inlen < 1) return; proto = *indata++; inlen--; if (!(proto & 1)) { if (inlen < 1) return; proto = (proto << 8) | *indata++; inlen--; } } else { if (inlen < 2) return; proto = (indata[0] << 8) | indata[1]; inlen -= 2; indata += 2; } /* Discard frames with illegal protocol fields. */ if ((proto & 0x101) != 1) { lptr->frame_drops++; return; } /* * If per-link ECP is used, then we have to do this first. This * must be done here because demultiplexing when MP is in use is * done at the MP bundle level, not at the link level. * * For better security, it may be desirable to discard any non-LCP, * non-ECP packets when ECP is in open state. This provides some * protection against attackers who are able to insert data on the * line. */ if (lptr->ecp_in_use && proto == PPP_PROTO_EP_LINK) { xcp = find_xcp(lptr,proto); indata = ecp_decrypt(xcp,indata,&inlen); if (indata == NULL) return; if (inlen < 1) return; proto = *indata++; inlen--; if (!(proto & 1)) { if (inlen < 1) return; proto = (proto << 8) | *indata++; inlen--; } } /* * If we're doing per-link CCP, then we have to do it before normal * demultiplexing because CCP usually needs to inspect all data and * because demultiplexing on an MP system is done at the bundle * level. */ if (lptr->ccp_in_use) { xcp = find_xcp(lptr,PPP_PROTO_CP_LINK); if (proto == PPP_PROTO_CP_LINK) { indata = ccp_uncompress(xcp,indata,&inlen); if (indata == NULL) return; if (inlen < 1) return; proto = *indata++; inlen--; if (!(proto & 1)) { if (inlen < 1) return; proto = (proto << 8) | *indata++; inlen--; } } else ccp_uncompressed(xcp,proto,indata,inlen); } /* * If we're a link in an MP bundle, then send to NCP at bundle level * when necessary. Most LCP messages should be handled at the link * level. Protocol-Reject (code 8), though, should go to the bundle * level, since it is used to shut down NCPs. One might consider * sending the Time-Remaining message to the bundle level as well, * depending on system architecture. * * Note that LCP should disconnect this link from the bundle if it * leaves the Open state. */ if (lptr->mp != NULL && (proto != PPP_PROTO_LCP || indata[0] == 8)) { lptr->mp->in_on = lptr; xcp = find_xcp(lptr->mp->lptr,proto); } else xcp = find_xcp(lptr,proto); /* Dispatch to appropriate handler now. */ if (xcp != NULL) (*xcp->handler)(xcp,indata,inlen); else { /* No handler for this protocol, log it and reject it. */ send_lcp_protocol_reject(lptr,proto,indata,inlen); }}/* * Add address, control, and protocol fields. */static intadd_acf_and_pf(struct ppp_link *lptr, octet *outdata, uint16 proto){ octet *ood = outdata; if (lptr->pfc_out && (proto & 0xFF00) == 0) *--outdata = proto & 0xFF; else { *--outdata = proto & 0xFF; *--outdata = proto >> 8; } if (!lptr->acfc_out && proto != PPP_PROTO_LCP) { *--outdata = 0x03; *--outdata = 0xFF; } return ood-outdata;}/* * Standard (non-MP) PPP output routine. */static voidnormal_output(struct ppp_link *link, octet *outdata, int outlen, uint16 proto){ int i; i = add_acf_and_pf(link,outdata,proto); outdata -= i; outlen += i; (*link->user_output)(link->handle,outdata,outlen);}/* * This routine replaces the normal link_output routine for the bundle * level PPP link. */static voidmp_output(struct ppp_link *lptr, octet *outdata, int outlen, uint16 proto){ struct mp_state *mp = lptr->mp; struct ppp_link *ind_lptr; int fragsize,len,hdrsize; octet flags; /* Prepend a compressed protocol ID field */ if (proto <= 0xFF) { *--outdata = proto; outlen++; } else { *--outdata = proto & 0xFF; *--outdata = proto >> 8; outlen += 2; } /* Figure output fragment size */ if (outlen < MIN_FRAG_SIZE) fragsize = outlen; else fragsize = (outlen+mp->numlinks-1)/mp->numlinks; if (mp->snd_short_seq) hdrsize = 2; else hdrsize = 4; /* Loop over packet and transmit fragments. */ flags = MP_BEGIN; ind_lptr = mp->next_out_link; while (outlen > 0) { if (ind_lptr == NULL) { ind_lptr = mp->links; if (ind_lptr == NULL) break; } len = outlen; if (len > fragsize) len = fragsize; if (len > ind_lptr->mtu-hdrsize) len = ind_lptr->mtu-hdrsize; if ((outlen -= len) == 0) flags |= MP_END; /* * Add an MP header. WARNING: Corrupts previous output data! * The link_output routine has to block until all data have been * copied into a local buffer or transmitted. (Scatter/gather * is the usual way to handle this, but not in this simple * example.) */ *--outdata = mp->send_seq & 0xFF; if (mp->snd_short_seq) *--outdata = ((mp->send_seq>>8) & 0xF) | flags; else { *--outdata = (mp->send_seq>>8) & 0xFF; *--outdata = (mp->send_seq>>16) & 0xFF; *--outdata = flags; len += 2; } len += 2; (*ind_lptr->link_output)(ind_lptr,outdata,len,PPP_PROTO_MP); flags = 0; outdata += len; mp->send_seq++; ind_lptr = ind_lptr->next; } mp->next_out_link = ind_lptr;}/* * MP input handler. Does reassembly and demultiplexing. * * The modular arithmetic tests done are a little tricky, so they're * commented with the equivalent regular arithmetic test. * * Comments indicating where the PPP system can be notified of lost * packets are also included, as are notes identifying peer * misbehavior. * * "link" is bundle level state pointer. "lptr" is link level for * received data. */static voidmp_handler(struct xcp_state *mpxcp, octet *indata, int inlen){ struct ppp_link *lptr,*link = mpxcp->link, *ltmp; struct mp_state *mp = link->mp; struct mp_fragment *frag,*newfrag,*start,*nextf; int flags; uint32 newseq,thisseq,sbit,smask,minseq; static char buffer[MAX_MRRU]; char *bp; uint16 proto; struct xcp_state *xcp; /* Get pointer to link on which this message came in. */ lptr = mp->in_on; /* Decode MP flags and sequence number. */ flags = indata[0]; if (mp->rcv_short_seq) { if (inlen < 2 || (indata[0] & 0x30) != 0) { syslog(LOG_NOTICE,"corrupted MP header"); return; } newseq = ((indata[0] & 0xF) << 8) | indata[1]; indata += 2; inlen -= 2; sbit = 0x800; } else { if (inlen < 4 || (indata[0] & 0x3F) != 0) { syslog(LOG_NOTICE,"corrupted MP header"); return; } newseq = (indata[1] << 16) | (indata[2] << 8) | indata[3]; indata += 4; inlen -= 4; sbit = 0x800000; } smask = (sbit << 1) - 1; /* if newseq < lptr->seq */ if (((newseq-lptr->seq) & sbit) != 0) { syslog(LOG_DEBUG,"out-of-order packet %lu on link %p",newseq,lptr); return; } /* Find minimum sequence number over all links and save at bundle level. */ minseq = lptr->seq = newseq; for (ltmp = mp->links; ltmp != NULL; ltmp = ltmp->next) /* if ltmp->seq < minseq */ if (((ltmp->seq-minseq) & sbit) != 0) minseq = ltmp->seq; link->seq = minseq; /* syslog(LOG_DEBUG,"handling sequence %lu; minimum is %lu",newseq, minseq);*/ /* Create fragment record for this new message. */ newfrag = (struct mp_fragment *)malloc(sizeof(*newfrag)+inlen); if (newfrag == NULL) { syslog(LOG_ERR,"MP storage allocation failure; fragment dropped."); if (flags & MP_END) /* Packet has been dropped. */ link->frame_drops++; return; } newfrag->flags = flags; newfrag->seq = newseq; newfrag->length = inlen; memcpy(newfrag->data,indata,inlen); /* If this new fragment is before the first one, then enqueue it now. */ if ((frag = mp->frags) == NULL || /* newseq < frag->seq */ ((newseq-frag->seq) & sbit) != 0) { newfrag->next = frag; mp->frags = newfrag; newfrag = NULL; } /* Loop over fragments and update the list */ start = NULL; frag = mp->frags; if (frag->flags & MP_BEGIN) start = frag; mp->frags = NULL; while (start != NULL || newfrag != NULL) { nextfrag: thisseq = frag->seq; nextf = frag->next; /* Drop any duplicate fragments */ if (newfrag != NULL && thisseq == newseq) { syslog(LOG_DEBUG,"dropped duplicate sequence %lu",thisseq); free(newfrag); newfrag = NULL;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -