📄 ppp.c
字号:
* to their DL_INFO_REQ. Fortunately, they will update the * MTU if we send an unsolicited DL_INFO_ACK up. */ if ((mq = allocb(sizeof(dl_info_req_t), BPRI_HI)) == 0) break; /* should do bufcall */ ((union DL_primitives *)mq->b_rptr)->dl_primitive = DL_INFO_REQ; mq->b_wptr = mq->b_rptr + sizeof(dl_info_req_t); dlpi_request(q, mq, us); error = 0; break; case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFADDR: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCGIFMETRIC: error = 0; break;#endif /* LACHTCP */ default: if (us->ppa == 0 || us->ppa->lowerq == 0) break; us->ioc_id = iop->ioc_id; error = -1; switch (iop->ioc_cmd) { case PPPIO_GETSTAT: case PPPIO_GETCSTAT: if (us->flags & US_LASTMOD) { error = EINVAL; break; } putnext(us->ppa->lowerq, mp); break; default: if (us->flags & US_PRIV) putnext(us->ppa->lowerq, mp); else { DPRINT1("ppp ioctl %x rejected\n", iop->ioc_cmd); error = EPERM; } break; } break; } if (error > 0) { iop->ioc_error = error; mp->b_datap->db_type = M_IOCNAK; qreply(q, mp); } else if (error == 0) { mp->b_datap->db_type = M_IOCACK; qreply(q, mp); } break; case M_FLUSH: if (us->flags & US_DBGLOG) DPRINT2("ppp/%d: flush %x\n", us->mn, *mp->b_rptr); if (*mp->b_rptr & FLUSHW) flushq(q, FLUSHDATA); if (*mp->b_rptr & FLUSHR) { *mp->b_rptr &= ~FLUSHW; qreply(q, mp); } else freemsg(mp); break; default: freemsg(mp); break; } return 0;}#ifndef NO_DLPIstatic voiddlpi_request(q, mp, us) queue_t *q; mblk_t *mp; upperstr_t *us;{ union DL_primitives *d = (union DL_primitives *) mp->b_rptr; int size = mp->b_wptr - mp->b_rptr; mblk_t *reply, *np; upperstr_t *ppa, *os; int sap, len; dl_info_ack_t *info; dl_bind_ack_t *ackp;#if DL_CURRENT_VERSION >= 2 dl_phys_addr_ack_t *paddrack; static struct ether_addr eaddr = {0};#endif if (us->flags & US_DBGLOG) DPRINT3("ppp/%d: dlpi prim %x len=%d\n", us->mn, d->dl_primitive, size); switch (d->dl_primitive) { case DL_INFO_REQ: if (size < sizeof(dl_info_req_t)) goto badprim; if ((reply = allocb(sizeof(dl_info_ack_t), BPRI_HI)) == 0) break; /* should do bufcall */ reply->b_datap->db_type = M_PCPROTO; info = (dl_info_ack_t *) reply->b_wptr; reply->b_wptr += sizeof(dl_info_ack_t); bzero((caddr_t) info, sizeof(dl_info_ack_t)); info->dl_primitive = DL_INFO_ACK; info->dl_max_sdu = us->ppa? us->ppa->mtu: PPP_MAXMTU; info->dl_min_sdu = 1; info->dl_addr_length = sizeof(uint); info->dl_mac_type = DL_ETHER; /* a bigger lie */ info->dl_current_state = us->state; info->dl_service_mode = DL_CLDLS; info->dl_provider_style = DL_STYLE2;#if DL_CURRENT_VERSION >= 2 info->dl_sap_length = sizeof(uint); info->dl_version = DL_CURRENT_VERSION;#endif qreply(q, reply); break; case DL_ATTACH_REQ: if (size < sizeof(dl_attach_req_t)) goto badprim; if (us->state != DL_UNATTACHED || us->ppa != 0) { dlpi_error(q, us, DL_ATTACH_REQ, DL_OUTSTATE, 0); break; } for (ppa = ppas; ppa != 0; ppa = ppa->nextppa) if (ppa->ppa_id == d->attach_req.dl_ppa) break; if (ppa == 0) { dlpi_error(q, us, DL_ATTACH_REQ, DL_BADPPA, 0); break; } us->ppa = ppa; qwriter(q, mp, attach_ppa, PERIM_OUTER); return; case DL_DETACH_REQ: if (size < sizeof(dl_detach_req_t)) goto badprim; if (us->state != DL_UNBOUND || us->ppa == 0) { dlpi_error(q, us, DL_DETACH_REQ, DL_OUTSTATE, 0); break; } qwriter(q, mp, detach_ppa, PERIM_OUTER); return; case DL_BIND_REQ: if (size < sizeof(dl_bind_req_t)) goto badprim; if (us->state != DL_UNBOUND || us->ppa == 0) { dlpi_error(q, us, DL_BIND_REQ, DL_OUTSTATE, 0); break; }#if 0 /* apparently this test fails (unnecessarily?) on some systems */ if (d->bind_req.dl_service_mode != DL_CLDLS) { dlpi_error(q, us, DL_BIND_REQ, DL_UNSUPPORTED, 0); break; }#endif /* saps must be valid PPP network protocol numbers, except that we accept ETHERTYPE_IP in place of PPP_IP. */ sap = d->bind_req.dl_sap; us->req_sap = sap;#if defined(SOL2) if (us->flags & US_DBGLOG) DPRINT2("DL_BIND_REQ: ip gives sap = 0x%x, us = 0x%x", sap, us); if (sap == ETHERTYPE_IP) /* normal IFF_IPV4 */ sap = PPP_IP; else if (sap == ETHERTYPE_IPV6) /* when IFF_IPV6 is set */ sap = PPP_IPV6; else if (sap == ETHERTYPE_ALLSAP) /* snoop gives sap of 0 */ sap = PPP_ALLSAP; else { DPRINT2("DL_BIND_REQ: unrecognized sap = 0x%x, us = 0x%x", sap, us); dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0); break; }#else if (sap == ETHERTYPE_IP) sap = PPP_IP; if (sap < 0x21 || sap > 0x3fff || (sap & 0x101) != 1) { dlpi_error(q, us, DL_BIND_REQ, DL_BADADDR, 0); break; }#endif /* defined(SOL2) */ /* check that no other stream is bound to this sap already. */ for (os = us->ppa; os != 0; os = os->next) if (os->sap == sap) break; if (os != 0) { dlpi_error(q, us, DL_BIND_REQ, DL_NOADDR, 0); break; } us->sap = sap; us->state = DL_IDLE; if ((reply = allocb(sizeof(dl_bind_ack_t) + sizeof(uint), BPRI_HI)) == 0) break; /* should do bufcall */ ackp = (dl_bind_ack_t *) reply->b_wptr; reply->b_wptr += sizeof(dl_bind_ack_t) + sizeof(uint); reply->b_datap->db_type = M_PCPROTO; bzero((caddr_t) ackp, sizeof(dl_bind_ack_t)); ackp->dl_primitive = DL_BIND_ACK; ackp->dl_sap = sap; ackp->dl_addr_length = sizeof(uint); ackp->dl_addr_offset = sizeof(dl_bind_ack_t); *(uint *)(ackp+1) = sap; qreply(q, reply); break; case DL_UNBIND_REQ: if (size < sizeof(dl_unbind_req_t)) goto badprim; if (us->state != DL_IDLE) { dlpi_error(q, us, DL_UNBIND_REQ, DL_OUTSTATE, 0); break; } us->sap = -1; us->state = DL_UNBOUND;#ifdef LACHTCP us->ppa->ifstats.ifs_active = 0;#endif dlpi_ok(q, DL_UNBIND_REQ); break; case DL_UNITDATA_REQ: if (size < sizeof(dl_unitdata_req_t)) goto badprim; if (us->state != DL_IDLE) { dlpi_error(q, us, DL_UNITDATA_REQ, DL_OUTSTATE, 0); break; } if ((ppa = us->ppa) == 0) { cmn_err(CE_CONT, "ppp: in state dl_idle but ppa == 0?\n"); break; } len = mp->b_cont == 0? 0: msgdsize(mp->b_cont); if (len > ppa->mtu) { DPRINT2("dlpi data too large (%d > %d)\n", len, ppa->mtu); break; }#if defined(SOL2) /* * Should there be any promiscuous stream(s), send the data * up for each promiscuous stream that we recognize. */ if (mp->b_cont) promisc_sendup(ppa, mp->b_cont, us->sap, 0);#endif /* defined(SOL2) */ mp->b_band = 0;#ifdef PRIOQ /* Extract s_port & d_port from IP-packet, the code is a bit dirty here, but so am I, too... */ if (mp->b_datap->db_type == M_PROTO && us->sap == PPP_IP && mp->b_cont != 0) { u_char *bb, *tlh; int iphlen, len; u_short *ptr; u_char band_unset, cur_band, syn; u_short s_port, d_port; bb = mp->b_cont->b_rptr; /* bb points to IP-header*/ len = mp->b_cont->b_wptr - mp->b_cont->b_rptr; syn = 0; s_port = IPPORT_DEFAULT; d_port = IPPORT_DEFAULT; if (len >= 20) { /* 20 = minimum length of IP header */ iphlen = (bb[0] & 0x0f) * 4; tlh = bb + iphlen; len -= iphlen; switch (bb[9]) { case IPPROTO_TCP: if (len >= 20) { /* min length of TCP header */ s_port = (tlh[0] << 8) + tlh[1]; d_port = (tlh[2] << 8) + tlh[3]; syn = tlh[13] & 0x02; } break; case IPPROTO_UDP: if (len >= 8) { /* min length of UDP header */ s_port = (tlh[0] << 8) + tlh[1]; d_port = (tlh[2] << 8) + tlh[3]; } break; } } /* * Now calculate b_band for this packet from the * port-priority table. */ ptr = prioq_table; cur_band = max_band; band_unset = 1; while (*ptr) { while (*ptr && band_unset) if (s_port == *ptr || d_port == *ptr++) { mp->b_band = cur_band; band_unset = 0; break; } ptr++; cur_band--; } if (band_unset) mp->b_band = def_band; /* It may be usable to urge SYN packets a bit */ if (syn) mp->b_band++; }#endif /* PRIOQ */ /* this assumes PPP_HDRLEN <= sizeof(dl_unitdata_req_t) */ if (mp->b_datap->db_ref > 1) { np = allocb(PPP_HDRLEN, BPRI_HI); if (np == 0) break; /* gak! */ np->b_cont = mp->b_cont; mp->b_cont = 0; freeb(mp); mp = np; } else mp->b_datap->db_type = M_DATA; /* XXX should use dl_dest_addr_offset/length here, but we would have to translate ETHERTYPE_IP -> PPP_IP */ mp->b_wptr = mp->b_rptr + PPP_HDRLEN; mp->b_rptr[0] = PPP_ALLSTATIONS; mp->b_rptr[1] = PPP_UI; mp->b_rptr[2] = us->sap >> 8; mp->b_rptr[3] = us->sap; if (pass_packet(us, mp, 1)) { if (!send_data(mp, us)) putq(q, mp); } return;#if DL_CURRENT_VERSION >= 2 case DL_PHYS_ADDR_REQ: if (size < sizeof(dl_phys_addr_req_t)) goto badprim; /* * Don't check state because ifconfig sends this one down too */ if ((reply = allocb(sizeof(dl_phys_addr_ack_t)+ETHERADDRL, BPRI_HI)) == 0) break; /* should do bufcall */ reply->b_datap->db_type = M_PCPROTO; paddrack = (dl_phys_addr_ack_t *) reply->b_wptr; reply->b_wptr += sizeof(dl_phys_addr_ack_t); bzero((caddr_t) paddrack, sizeof(dl_phys_addr_ack_t)+ETHERADDRL); paddrack->dl_primitive = DL_PHYS_ADDR_ACK; paddrack->dl_addr_length = ETHERADDRL; paddrack->dl_addr_offset = sizeof(dl_phys_addr_ack_t); bcopy(&eaddr, reply->b_wptr, ETHERADDRL); reply->b_wptr += ETHERADDRL; qreply(q, reply); break;#if defined(SOL2) case DL_PROMISCON_REQ: if (size < sizeof(dl_promiscon_req_t)) goto badprim; us->flags |= US_PROMISC; dlpi_ok(q, DL_PROMISCON_REQ); break; case DL_PROMISCOFF_REQ: if (size < sizeof(dl_promiscoff_req_t)) goto badprim; us->flags &= ~US_PROMISC; dlpi_ok(q, DL_PROMISCOFF_REQ); break;#else case DL_PROMISCON_REQ: /* fall thru */ case DL_PROMISCOFF_REQ: /* fall thru */#endif /* defined(SOL2) */#endif /* DL_CURRENT_VERSION >= 2 */#if DL_CURRENT_VERSION >= 2 case DL_SET_PHYS_ADDR_REQ: case DL_SUBS_BIND_REQ: case DL_SUBS_UNBIND_REQ: case DL_ENABMULTI_REQ: case DL_DISABMULTI_REQ: case DL_XID_REQ: case DL_TEST_REQ: case DL_REPLY_UPDATE_REQ: case DL_REPLY_REQ: case DL_DATA_ACK_REQ:#endif case DL_CONNECT_REQ: case DL_TOKEN_REQ: dlpi_error(q, us, d->dl_primitive, DL_NOTSUPPORTED, 0); break; case DL_CONNECT_RES: case DL_DISCONNECT_REQ: case DL_RESET_REQ: case DL_RESET_RES: dlpi_error(q, us, d->dl_primitive, DL_OUTSTATE, 0); break; case DL_UDQOS_REQ: dlpi_error(q, us, d->dl_primitive, DL_BADQOSTYPE, 0); break;#if DL_CURRENT_VERSION >= 2 case DL_TEST_RES: case DL_XID_RES: break;#endif default: cmn_err(CE_CONT, "ppp: unknown dlpi prim 0x%x\n", d->dl_primitive); /* fall through */ badprim: dlpi_error(q, us, d->dl_primitive, DL_BADPRIM, 0); break; } freemsg(mp);}static voiddlpi_error(q, us, prim, err, uerr) queue_t *q; upperstr_t *us; int prim, err, uerr;{ mblk_t *reply; dl_error_ack_t *errp; if (us->flags & US_DBGLOG) DPRINT3("ppp/%d: dlpi error, prim=%x, err=%x\n", us->mn, prim, err); reply = allocb(sizeof(dl_error_ack_t), BPRI_HI); if (reply == 0) return; /* XXX should do bufcall */ reply->b_datap->db_type = M_PCPROTO; errp = (dl_error_ack_t *) reply->b_wptr; reply->b_wptr += sizeof(dl_error_ack_t); errp->dl_primitive = DL_ERROR_ACK; errp->dl_error_primitive = prim; errp->dl_errno = err; errp->dl_unix_errno = uerr; qreply(q, reply);}static voiddlpi_ok(q, prim) queue_t *q; int prim;{ mblk_t *reply; dl_ok_ack_t *okp; reply = allocb(sizeof(dl_ok_ack_t), BPRI_HI); if (reply == 0) return; /* XXX should do bufcall */ reply->b_datap->db_type = M_PCPROTO; okp = (dl_ok_ack_t *) reply->b_wptr; reply->b_wptr += sizeof(dl_ok_ack_t); okp->dl_primitive = DL_OK_ACK; okp->dl_correct_primitive = prim; qreply(q, reply);}#endif /* NO_DLPI */static intpass_packet(us, mp, outbound) upperstr_t *us; mblk_t *mp; int outbound;{ int pass; upperstr_t *ppa; if ((ppa = us->ppa) == 0) { freemsg(mp); return 0; }#ifdef FILTER_PACKETS pass = ip_hard_filter(us, mp, outbound);#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -