+/*
+ * Handle a CCP packet.
+ *
+ * The CCP packet is passed along to the pppd process just like any
+ * other PPP frame. The difference is that some processing needs to be
+ * immediate or the compressors will become confused on the peer.
+ */
+
+static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
+{
+ int slen = CCP_LENGTH(dp);
+ __u8 *opt = dp + CCP_HDRLEN;
+ int opt_len = slen - CCP_HDRLEN;
+ unsigned long flags;
+
+ if (slen > len)
+ return;
+
+ save_flags(flags);
+ switch (CCP_CODE(dp)) {
+ case CCP_CONFREQ:
+ case CCP_TERMREQ:
+ case CCP_TERMACK:
+/*
+ * CCP must be going down - disable compression
+ */
+ if (ppp->flags & SC_CCP_UP) {
+ cli();
+ ppp->flags &= ~(SC_CCP_UP |
+ SC_COMP_RUN |
+ SC_DECOMP_RUN);
+ }
+ break;
+
+ case CCP_CONFACK:
+ if ((ppp->flags & SC_CCP_OPEN) == 0)
+ break;
+ if (ppp->flags & SC_CCP_UP)
+ break;
+ if (slen < (CCP_HDRLEN + CCP_OPT_MINLEN))
+ break;
+ if (slen < (CCP_OPT_LENGTH (opt) + CCP_HDRLEN))
+ break;
+/*
+ * we're agreeing to send compressed packets.
+ */
+ if (!rcvd) {
+ if (ppp->sc_xc_state == NULL)
+ break;
+
+ if ((*ppp->sc_xcomp->comp_init)
+ (ppp->sc_xc_state,
+ opt,
+ opt_len,
+ ppp2dev (ppp)->base_addr,
+ 0,
+ ppp->flags & SC_DEBUG)) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: comp running\n",
+ ppp->name);
+ cli();
+ ppp->flags |= SC_COMP_RUN;
+ }
+ break;
+ }
+/*
+ * peer is agreeing to send compressed packets.
+ */
+ if (ppp->sc_rc_state == NULL)
+ break;
+
+ if ((*ppp->sc_rcomp->decomp_init)
+ (ppp->sc_rc_state,
+ opt,
+ opt_len,
+ ppp2dev (ppp)->base_addr,
+ 0,
+ ppp->mru,
+ ppp->flags & SC_DEBUG)) {
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: decomp running\n",
+ ppp->name);
+ cli();
+ ppp->flags |= SC_DECOMP_RUN;
+ ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
+ }
+ break;
+/*
+ * CCP Reset-ack resets compressors and decompressors as it passes through.
+ */
+ case CCP_RESETACK:
+ if ((ppp->flags & SC_CCP_UP) == 0)
+ break;
+
+ if (!rcvd) {
+ if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN)) {
+ (*ppp->sc_xcomp->comp_reset)(ppp->sc_xc_state);
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: comp reset\n",
+ ppp->name);
+ }
+ } else {
+ if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) {
+ (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state);
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "%s: decomp reset\n",
+ ppp->name);
+ cli();
+ ppp->flags &= ~SC_DC_ERROR;
+ }
+ }
+ break;
+ }
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "ppp_proto_ccp: %s code %d, flags=%x\n",
+ (rcvd? "rcvd": "sent"), CCP_CODE(dp), ppp->flags);
+ restore_flags(flags);
+}
+
+static int
+rcv_proto_ccp (struct ppp *ppp, __u16 proto, __u8 *dp, int len)
+{
+ CHECK_PPP(0);
+ ppp_proto_ccp (ppp, dp, len, 1);
+ return rcv_proto_unknown (ppp, proto, dp, len);
+}
+
+/*
+ * Handle a LQR packet.
+ */
+
+static int
+rcv_proto_lqr (struct ppp *ppp, __u16 proto, __u8 * data, int len)
+{
+ return rcv_proto_unknown (ppp, proto, data, len);
+}
+