📄 ppp.c
字号:
/* * Here is where we might, in future, decide whether to pass * or drop the packet, and whether it counts as link activity. */ pass = 1;#endif /* FILTER_PACKETS */ if (pass < 0) { /* pass only if link already up, and don't update time */ if (ppa->lowerq == 0) { freemsg(mp); return 0; } pass = 1; } else if (pass) { if (outbound) ppa->last_sent = time; else ppa->last_recv = time; } return pass;}/* * We have some data to send down to the lower stream (or up the * control stream, if we don't have a lower stream attached). * Returns 1 if the message was dealt with, 0 if it wasn't able * to be sent on and should therefore be queued up. */static intsend_data(mp, us) mblk_t *mp; upperstr_t *us;{ upperstr_t *ppa; if ((us->flags & US_BLOCKED) || us->npmode == NPMODE_QUEUE) return 0; ppa = us->ppa; if (ppa == 0 || us->npmode == NPMODE_DROP || us->npmode == NPMODE_ERROR) { if (us->flags & US_DBGLOG) DPRINT2("ppp/%d: dropping pkt (npmode=%d)\n", us->mn, us->npmode); freemsg(mp); return 1; } if (ppa->lowerq == 0) { /* try to send it up the control stream */ if (bcanputnext(ppa->q, mp->b_band)) { /* * The message seems to get corrupted for some reason if * we just send the message up as it is, so we send a copy. */ mblk_t *np = copymsg(mp); freemsg(mp); if (np != 0) putnext(ppa->q, np); return 1; } } else { if (bcanputnext(ppa->lowerq, mp->b_band)) { MT_ENTER(&ppa->stats_lock); ppa->stats.ppp_opackets++; ppa->stats.ppp_obytes += msgdsize(mp);#ifdef INCR_OPACKETS INCR_OPACKETS(ppa);#endif MT_EXIT(&ppa->stats_lock); /* * The lower queue is only ever detached while holding an * exclusive lock on the whole driver. So we can be confident * that the lower queue is still there. */ putnext(ppa->lowerq, mp); return 1; } } us->flags |= US_BLOCKED; return 0;}/* * Allocate a new PPA id and link this stream into the list of PPAs. * This procedure is called with an exclusive lock on all queues in * this driver. */static voidnew_ppa(q, mp) queue_t *q; mblk_t *mp;{ upperstr_t *us, *up, **usp; int ppa_id; us = (upperstr_t *) q->q_ptr; if (us == 0) { DPRINT("new_ppa: q_ptr = 0!\n"); return; } usp = &ppas; ppa_id = 0; while ((up = *usp) != 0 && ppa_id == up->ppa_id) { ++ppa_id; usp = &up->nextppa; } us->ppa_id = ppa_id; us->ppa = us; us->next = 0; us->nextppa = *usp; *usp = us; us->flags |= US_CONTROL; us->npmode = NPMODE_PASS; us->mtu = PPP_MTU; us->mru = PPP_MRU;#ifdef SOL2 /* * Create a kstats record for our statistics, so netstat -i works. */ if (us->kstats == 0) { char unit[32]; sprintf(unit, "ppp%d", us->ppa->ppa_id); us->kstats = kstat_create("ppp", us->ppa->ppa_id, unit, "net", KSTAT_TYPE_NAMED, 4, 0); if (us->kstats != 0) { kstat_named_t *kn = KSTAT_NAMED_PTR(us->kstats); strcpy(kn[0].name, "ipackets"); kn[0].data_type = KSTAT_DATA_ULONG; strcpy(kn[1].name, "ierrors"); kn[1].data_type = KSTAT_DATA_ULONG; strcpy(kn[2].name, "opackets"); kn[2].data_type = KSTAT_DATA_ULONG; strcpy(kn[3].name, "oerrors"); kn[3].data_type = KSTAT_DATA_ULONG; kstat_install(us->kstats); } }#endif /* SOL2 */ *(int *)mp->b_cont->b_rptr = ppa_id; mp->b_datap->db_type = M_IOCACK; qreply(q, mp);}static voidattach_ppa(q, mp) queue_t *q; mblk_t *mp;{ upperstr_t *us, *t; us = (upperstr_t *) q->q_ptr; if (us == 0) { DPRINT("attach_ppa: q_ptr = 0!\n"); return; }#ifndef NO_DLPI us->state = DL_UNBOUND;#endif for (t = us->ppa; t->next != 0; t = t->next) ; t->next = us; us->next = 0; if (mp->b_datap->db_type == M_IOCTL) { mp->b_datap->db_type = M_IOCACK; qreply(q, mp); } else {#ifndef NO_DLPI dlpi_ok(q, DL_ATTACH_REQ);#endif }}static voiddetach_ppa(q, mp) queue_t *q; mblk_t *mp;{ upperstr_t *us, *t; us = (upperstr_t *) q->q_ptr; if (us == 0) { DPRINT("detach_ppa: q_ptr = 0!\n"); return; } for (t = us->ppa; t->next != 0; t = t->next) if (t->next == us) { t->next = us->next; break; } us->next = 0; us->ppa = 0;#ifndef NO_DLPI us->state = DL_UNATTACHED; dlpi_ok(q, DL_DETACH_REQ);#endif}/* * We call this with qwriter in order to give the upper queue procedures * the guarantee that the lower queue is not going to go away while * they are executing. */static voiddetach_lower(q, mp) queue_t *q; mblk_t *mp;{ upperstr_t *us; us = (upperstr_t *) q->q_ptr; if (us == 0) { DPRINT("detach_lower: q_ptr = 0!\n"); return; } LOCK_LOWER_W; us->lowerq->q_ptr = 0; RD(us->lowerq)->q_ptr = 0; us->lowerq = 0; UNLOCK_LOWER; /* Unblock streams which now feed back up the control stream. */ qenable(us->q); mp->b_datap->db_type = M_IOCACK; qreply(q, mp);}static intpppuwsrv(q) queue_t *q;{ upperstr_t *us, *as; mblk_t *mp; us = (upperstr_t *) q->q_ptr; if (us == 0) { DPRINT("pppuwsrv: q_ptr = 0!\n"); return 0; } /* * If this is a control stream, then this service procedure * probably got enabled because of flow control in the lower * stream being enabled (or because of the lower stream going * away). Therefore we enable the service procedure of all * attached upper streams. */ if (us->flags & US_CONTROL) { for (as = us->next; as != 0; as = as->next) qenable(WR(as->q)); } /* Try to send on any data queued here. */ us->flags &= ~US_BLOCKED; while ((mp = getq(q)) != 0) { if (!send_data(mp, us)) { putbq(q, mp); break; } } return 0;}/* should never get called... */static intppplwput(q, mp) queue_t *q; mblk_t *mp;{ putnext(q, mp); return 0;}static intppplwsrv(q) queue_t *q;{ queue_t *uq; /* * Flow control has back-enabled this stream: * enable the upper write service procedure for * the upper control stream for this lower stream. */ LOCK_LOWER_R; uq = (queue_t *) q->q_ptr; if (uq != 0) qenable(uq); UNLOCK_LOWER; return 0;}/* * This should only get called for control streams. */static intpppurput(q, mp) queue_t *q; mblk_t *mp;{ upperstr_t *ppa, *us; int proto, len; struct iocblk *iop; ppa = (upperstr_t *) q->q_ptr; if (ppa == 0) { DPRINT("pppurput: q_ptr = 0!\n"); return 0; } switch (mp->b_datap->db_type) { case M_CTL: MT_ENTER(&ppa->stats_lock); switch (*mp->b_rptr) { case PPPCTL_IERROR:#ifdef INCR_IERRORS INCR_IERRORS(ppa);#endif ppa->stats.ppp_ierrors++; break; case PPPCTL_OERROR:#ifdef INCR_OERRORS INCR_OERRORS(ppa);#endif ppa->stats.ppp_oerrors++; break; } MT_EXIT(&ppa->stats_lock); freemsg(mp); break; case M_IOCACK: case M_IOCNAK: /* * Attempt to match up the response with the stream * that the request came from. */ iop = (struct iocblk *) mp->b_rptr; for (us = ppa; us != 0; us = us->next) if (us->ioc_id == iop->ioc_id) break; if (us == 0) freemsg(mp); else putnext(us->q, mp); break; case M_HANGUP: /* * The serial device has hung up. We don't want to send * the M_HANGUP message up to pppd because that will stop * us from using the control stream any more. Instead we * send a zero-length message as an end-of-file indication. */ freemsg(mp); mp = allocb(1, BPRI_HI); if (mp == 0) { DPRINT1("ppp/%d: couldn't allocate eof message!\n", ppa->mn); break; } putnext(ppa->q, mp); break; default: if (mp->b_datap->db_type == M_DATA) { len = msgdsize(mp); if (mp->b_wptr - mp->b_rptr < PPP_HDRLEN) { PULLUP(mp, PPP_HDRLEN); if (mp == 0) { DPRINT1("ppp_urput: msgpullup failed (len=%d)\n", len); break; } } MT_ENTER(&ppa->stats_lock); ppa->stats.ppp_ipackets++; ppa->stats.ppp_ibytes += len;#ifdef INCR_IPACKETS INCR_IPACKETS(ppa);#endif MT_EXIT(&ppa->stats_lock); proto = PPP_PROTOCOL(mp->b_rptr);#if defined(SOL2) /* * Should there be any promiscuous stream(s), send the data * up for each promiscuous stream that we recognize. */ promisc_sendup(ppa, mp, proto, 1);#endif /* defined(SOL2) */ if (proto < 0x8000 && (us = find_dest(ppa, proto)) != 0) { /* * A data packet for some network protocol. * Queue it on the upper stream for that protocol. * XXX could we just putnext it? (would require thought) * The rblocked flag is there to ensure that we keep * messages in order for each network protocol. */ if (!pass_packet(us, mp, 0)) break; if (!us->rblocked && !canput(us->q)) us->rblocked = 1; if (!us->rblocked) putq(us->q, mp); else putq(q, mp); break; } } /* * A control frame, a frame for an unknown protocol, * or some other message type. * Send it up to pppd via the control stream. */ if (queclass(mp) == QPCTL || canputnext(ppa->q)) putnext(ppa->q, mp); else putq(q, mp); break; } return 0;}static intpppursrv(q) queue_t *q;{ upperstr_t *us, *as; mblk_t *mp, *hdr;#ifndef NO_DLPI dl_unitdata_ind_t *ud;#endif int proto; us = (upperstr_t *) q->q_ptr; if (us == 0) { DPRINT("pppursrv: q_ptr = 0!\n"); return 0; } if (us->flags & US_CONTROL) { /* * A control stream. * If there is no lower queue attached, run the write service * routines of other upper streams attached to this PPA. */ if (us->lowerq == 0) { as = us; do { if (as->flags & US_BLOCKED) qenable(WR(as->q)); as = as->next; } while (as != 0); } /* * Messages get queued on this stream's read queue if they * can't be queued on the read queue of the attached stream * that they are destined for. This is for flow control - * when this queue fills up, the lower read put procedure will * queue messages there and the flow control will propagate * down from there. */ while ((mp = getq(q)) != 0) { proto = PPP_PROTOCOL(mp->b_rptr); if (proto < 0x8000 && (as = find_dest(us, proto)) != 0) { if (!canput(as->q)) break; putq(as->q, mp); } else { if (!canputnext(q)) break; putnext(q, mp); } } if (mp) { putbq(q, mp); } else { /* can now put stuff directly on network protocol streams again */ for (as = us->next; as != 0; as = as->next) as->rblocked = 0; } /* * If this stream has a lower stream attached, * enable the read queue's service routine. * XXX we should really only do this if the queue length
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -