/* process received packets */ while ((skb = skb_dequeue(&ap->rqueue)) != NULL) { if (skb->cb[0])
ppp_input_error(&ap->chan, 0);
ppp_input(&ap->chan, skb);
}
/* try to push more stuff out */ if (test_bit(XMIT_WAKEUP, &ap->xmit_flags) && ppp_async_push(ap))
ppp_output_wakeup(&ap->chan);
}
/* *Wecangetcalledrecursivelyhereifthettywrite *functioncallsourwakeupfunction.Thiscanhappen *forexampleonaptywithboththemasterandslave *settoPPPlinediscipline. *WeusetheXMIT_BUSYbittodetectthisandgetout, *leavingtheXMIT_WAKEUPbitsettotelltheother *instancethatitmaynowbeabletowritemorenow.
*/ if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags)) return0;
spin_lock_bh(&ap->xmit_lock); for (;;) { if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags))
tty_stuffed = 0; if (!tty_stuffed && ap->optr < ap->olim) {
avail = ap->olim - ap->optr;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sent = tty->ops->write(tty, ap->optr, avail); if (sent < 0) goto flush; /* error, e.g. loss of CD */
ap->optr += sent; if (sent < avail)
tty_stuffed = 1; continue;
} if (ap->optr >= ap->olim && ap->tpkt) { if (ppp_async_encode(ap)) { /* finished processing ap->tpkt */
clear_bit(XMIT_FULL, &ap->xmit_flags);
done = 1;
} continue;
} /* *Wehaven'tmadeanyprogressthistimearound. *ClearXMIT_BUSYtoletothercallersin,but *afterdoingsowehavetocheckifanyoneset *XMIT_WAKEUPsincewelastcheckedit.Ifthey *did,weshouldtryagaintosetXMIT_BUSYandgo *aroundagainincaseXMIT_BUSYwasstillsetwhen *theothercallertried.
*/
clear_bit(XMIT_BUSY, &ap->xmit_flags); /* any more work to do? if not, exit the loop */ if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) ||
(!tty_stuffed && ap->tpkt))) break; /* more work to do, see if we can do it now */ if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags)) break;
}
spin_unlock_bh(&ap->xmit_lock); return done;
/* see how many ordinary chars there are at the start of buf */ staticinlineint
scan_ordinary(struct asyncppp *ap, constunsignedchar *buf, int count)
{ int i, c;
for (i = 0; i < count; ++i) {
c = buf[i]; if (c == PPP_ESCAPE || c == PPP_FLAG ||
(c < 0x20 && (ap->raccm & (1 << c)) != 0)) break;
} return i;
}
/* called when a flag is seen - do end-of-packet processing */ staticvoid
process_input_packet(struct asyncppp *ap)
{ struct sk_buff *skb; unsignedchar *p; unsignedint len, fcs;
/* check the FCS */
p = skb->data;
len = skb->len; if (len < 3) goto err; /* too short */
fcs = PPP_INITFCS; for (; len > 0; --len)
fcs = PPP_FCS(fcs, *p++); if (fcs != PPP_GOODFCS) goto err; /* bad FCS */
skb_trim(skb, skb->len - 2);
/* check for address/control and protocol compression */
p = skb->data; if (p[0] == PPP_ALLSTATIONS) { /* chop off address/control */ if (p[1] != PPP_UI || skb->len < 3) goto err;
p = skb_pull(skb, 2);
}
/* If protocol field is not compressed, it can be LCP packet */ if (!(p[0] & 0x01)) { unsignedint proto;
if (skb->len < 2) goto err;
proto = (p[0] << 8) + p[1]; if (proto == PPP_LCP)
async_lcp_peek(ap, p, skb->len, 1);
}
/* queue the frame to be processed */
skb->cb[0] = ap->state;
skb_queue_tail(&ap->rqueue, skb);
ap->rpkt = NULL;
ap->state = 0; return;
err: /* frame had an error, remember that, reset SC_TOSS & SC_ESCAPE */
ap->state = SC_PREV_ERROR; if (skb) { /* make skb appear as freshly allocated */
skb_trim(skb, 0);
skb_reserve(skb, - skb_headroom(skb));
}
}
/* Called when the tty driver has data for us. Runs parallel with the
other ldisc functions but will not be re-entered */
staticvoid
ppp_async_input(struct asyncppp *ap, const u8 *buf, const u8 *flags, int count)
{ struct sk_buff *skb; int c, i, j, n, s, f; unsignedchar *sp;
/* update bits used for 8-bit cleanness detection */ if (~ap->rbits & SC_RCV_BITS) {
s = 0; for (i = 0; i < count; ++i) {
c = buf[i]; if (flags && flags[i] != 0) continue;
s |= (c & 0x80)? SC_RCV_B7_1: SC_RCV_B7_0;
c = ((c >> 4) ^ c) & 0xf;
s |= (0x6996 & (1 << c))? SC_RCV_ODDP: SC_RCV_EVNP;
}
ap->rbits |= s;
}
while (count > 0) { /* scan through and see how many chars we can do in bulk */ if ((ap->state & SC_ESCAPE) && buf[0] == PPP_ESCAPE)
n = 1; else
n = scan_ordinary(ap, buf, count);
f = 0; if (flags && (ap->state & SC_TOSS) == 0) { /* check the flags to see if any char had an error */ for (j = 0; j < n; ++j) if ((f = flags[j]) != 0) break;
} if (f != 0) { /* start tossing */
ap->state |= SC_TOSS;
} elseif (n > 0 && (ap->state & SC_TOSS) == 0) { /* stuff the chars in the skb */
skb = ap->rpkt; if (!skb) {
skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2); if (!skb) goto nomem;
ap->rpkt = skb;
} if (skb->len == 0) { /* Try to get the payload 4-byte aligned. *Thisshouldmatchthe *PPP_ALLSTATIONS/PPP_UI/compressedtestsin *process_input_packet,butwedonothave *enoughcharsheretotestbuf[1]andbuf[2].
*/ if (buf[0] != PPP_ALLSTATIONS)
skb_reserve(skb, 2 + (buf[0] & 1));
} if (n > skb_tailroom(skb)) { /* packet overflowed MRU */
ap->state |= SC_TOSS;
} else {
sp = skb_put_data(skb, buf, n); if (ap->state & SC_ESCAPE) {
sp[0] ^= PPP_TRANS;
ap->state &= ~SC_ESCAPE;
}
}
}
if (n >= count) break;
c = buf[n]; if (flags != NULL && flags[n] != 0) {
ap->state |= SC_TOSS;
} elseif (c == PPP_FLAG) {
process_input_packet(ap);
} elseif (c == PPP_ESCAPE) {
ap->state |= SC_ESCAPE;
} elseif (I_IXON(ap->tty)) { if (c == START_CHAR(ap->tty))
start_tty(ap->tty); elseif (c == STOP_CHAR(ap->tty))
stop_tty(ap->tty);
} /* otherwise it's a char in the recv ACCM */
++n;
staticvoid async_lcp_peek(struct asyncppp *ap, unsignedchar *data, int len, int inbound)
{ int dlen, fcs, i, code;
u32 val;
data += 2; /* skip protocol bytes */
len -= 2; if (len < 4) /* 4 = code, ID, length */ return;
code = data[0]; if (code != CONFACK && code != CONFREQ) return;
dlen = get_unaligned_be16(data + 2); if (len < dlen) return; /* packet got truncated or length is bogus */
if (code == (inbound? CONFACK: CONFREQ)) { /* *sentconfreqorreceivedconfack: *calculatethecrcofthedatafromtheIDfieldon.
*/
fcs = PPP_INITFCS; for (i = 1; i < dlen; ++i)
fcs = PPP_FCS(fcs, data[i]);
if (!inbound) { /* outbound confreq - remember the crc for later */
ap->lcp_fcs = fcs; return;
}
/* received confack, check the crc */
fcs ^= ap->lcp_fcs;
ap->lcp_fcs = -1; if (fcs != 0) return;
} elseif (inbound) return; /* not interested in received confreq */
/* process the options in the confack */
data += 4;
dlen -= 4; /* data[0] is code, data[1] is length */ while (dlen >= 2 && dlen >= data[1] && data[1] >= 2) { switch (data[0]) { case LCP_MRU:
val = get_unaligned_be16(data + 2); if (inbound)
ap->mru = val; else
ap->chan.mtu = val; break; case LCP_ASYNCMAP:
val = get_unaligned_be32(data + 2); if (inbound)
ap->raccm = val; else
ap->xaccm[0] = val; break;
}
dlen -= data[1];
data += data[1];
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.