This is ppp_if.c in view mode; [Download] [Up]
/* ppp_if.c - Streams PPP top level module handles if_ and packetizing PPP packets. Copyright (C) 1990 Brad K. Clements, All Rights Reserved See copyright notice in Readme.streams */ #define VJC 1 #include <sys/types.h> #include "ppp.h" #if NPPP > 0 #define STREAMS 1 #define PPP_STATS 1 #define DEBUGS 1 #include <sys/param.h> #include <sys/stream.h> #include <sys/stropts.h> #include <sys/user.h> #include <sys/systm.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/errno.h> #include <sys/ioctl.h> #include <sys/file.h> #include <sys/uio.h> #include <net/if.h> #include <net/netisr.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/in_var.h> #include <netinet/ip.h> #ifdef PPP_STATS #include <sys/slip_var.h> #define INCR(comp) ++p->pii_stats.comp #else #define INCR(comp) #endif #ifdef VJC #include "slcompress.h" #endif #include <sys/if_ppp.h> #include <sys/ppp_str.h> #ifdef DEBUGS #include <sys/syslog.h> #define DLOG(s,a) if(ppp_if_debug) log(LOG_INFO, s, a) int ppp_if_debug=0; #else #define DLOG(s) {} #endif static int ppp_if_open(), ppp_if_close(), ppp_if_rput(), ppp_if_wput(), ppp_if_wsrv(), ppp_if_rsrv(); static struct module_info minfo ={ 0xbad,"ppp_if",0, INFPSZ, 16384, 4096 }; static struct qinit r_init = { ppp_if_rput, ppp_if_rsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL }; static struct qinit w_init = { ppp_if_wput, ppp_if_wsrv, ppp_if_open, ppp_if_close, NULL, &minfo, NULL }; struct streamtab ppp_ifinfo = { &r_init, &w_init, NULL, NULL, NULL }; #ifdef OLD struct ppp_if_info { int pii_flags; #define PII_FLAGS_INUSE 0x1 /* in use by a stream */ #define PII_FLAGS_COMPAC 0x2 #define PII_FLAGS_COMPPROT 0x4 #define PII_FLAGS_ATTACHED 0x8 /* already if_attached */ #define PII_FLAGS_VJC_ON 0x10 /* VJ TCP header compression enabled */ struct ifnet pii_ifnet; queue_t *pii_writeq; /* used by ppp_output */ #ifdef VJC struct slcompress pii_sc_comp; /* vjc control buffer */ #endif }; #endif typedef struct ppp_if_info PII; PII pii[NPPP]; int ppp_output(), ppp_ioctl(); int ppp_attach(unit) int unit; { register struct ifnet *ifp = &pii[unit].pii_ifnet; ifp->if_name = "ppp"; ifp->if_mtu = PPP_MTU; ifp->if_flags = IFF_POINTOPOINT; ifp->if_unit = unit; ifp->if_ioctl = ppp_ioctl; ifp->if_output = ppp_output; ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; if_attach(ifp); pii[unit].pii_flags |= PII_FLAGS_ATTACHED; } static int ppp_if_open(q, dev, flag, sflag) queue_t *q; dev_t dev; int flag, sflag; { register PII *p; register int x; int s; if(!suser()) { u.u_error = EPERM; return(OPENFAIL); } s = splstr(); if(!q->q_ptr) { for(x=0; x < NPPP; x++) { if(!(pii[x].pii_flags & PII_FLAGS_INUSE)) { /* we can use it */ p = &pii[x]; #ifdef VJC #ifdef PPP_STATS bzero(&p->pii_stats,sizeof(p->pii_stats)); #endif #ifdef JUNK if(!p->pii_sc_comp) { p->pii_sc_comp = (struct slcompress *) kmem_alloc(sizeof(struct slcompress)); if(!p->pii_sc_comp) { u.u_error = ENOSR; return(OPENFAIL); } } #endif sl_compress_init(&p->pii_sc_comp); #endif if(!(p->pii_flags & PII_FLAGS_ATTACHED)) ppp_attach(x); /* attach it */ p->pii_writeq = WR(q); WR(q)->q_ptr = q->q_ptr = (caddr_t) p; /* set write Q and read Q to point here */ p->pii_ifnet.if_flags |= IFF_RUNNING; p->pii_flags = PII_FLAGS_INUSE|PII_FLAGS_ATTACHED; DLOG("ppp_if%d: open\n",x); splx(s); return(x); } } } else { p = (PII *) q->q_ptr; #ifdef VJC #ifdef PPP_STATS bzero(&p->pii_stats,sizeof(p->pii_stats)); #endif #ifdef JUNK if(!p->pii_sc_comp) { p->pii_sc_comp = (struct slcompress *) kmem_alloc(sizeof(struct slcompress)); if(!p->pii_sc_comp) { u.u_error = ENOSR; return(OPENFAIL); } } #endif sl_compress_init(&p->pii_sc_comp); #endif DLOG("ppp_if%d: reopen\n", (p-pii)/sizeof(PII)); if(!(p->pii_flags & PII_FLAGS_ATTACHED)) ppp_attach(x); /* attach it */ p->pii_writeq = WR(q); WR(q)->q_ptr = q->q_ptr = (caddr_t) p; /* set write Q and read Q to point here */ p->pii_ifnet.if_flags |= IFF_RUNNING; p->pii_flags = PII_FLAGS_INUSE|PII_FLAGS_ATTACHED; splx(s); return(0); } splx(s); return(OPENFAIL); } static int ppp_if_close(q) queue_t *q; /* queue info */ { PII *p = (PII *) q->q_ptr; int s; s = splimp(); p->pii_flags &= ~PII_FLAGS_INUSE; if_down(&p->pii_ifnet); p->pii_ifnet.if_flags &= ~IFF_RUNNING; #ifdef VJC #ifdef JUNK if(p->pii_sc_comp) kmem_free(p->pii_sc_comp); #endif #endif DLOG("ppp_if%d: closed\n", (p-pii)/sizeof(PII)); splx(s); return(0); /* no work to be done */ } static int ppp_if_wput(q, mp) queue_t *q; register mblk_t *mp; { register struct iocblk *i; register PII *p; switch (mp->b_datap->db_type) { case M_FLUSH : if(*mp->b_rptr & FLUSHW) flushq(q, FLUSHDATA); putnext(q, mp); /* send it along too */ break; case M_DATA : putq(q, mp); /* queue it for my service routine */ break; case M_IOCTL : i = (struct iocblk *) mp->b_rptr; p = (PII *) q->q_ptr; switch (i->ioc_cmd) { case SIOCSIFCOMPAC : /* enable or disable AC compression */ if(i->ioc_count != sizeof(u_char)) goto passalong; DLOG("ppp_if: SIFCOMPAC %d\n", *(u_char *) mp->b_cont->b_rptr); if( *(u_char *) mp->b_cont->b_rptr) p->pii_flags |= PII_FLAGS_COMPAC; else p->pii_flags &= ~PII_FLAGS_COMPAC; goto passalong; case SIOCSIFCOMPPROT: /* enable or disable PROT compression */ DLOG("ppp_if: SIFCOMPPROT %d\n", *(u_char *) mp->b_cont->b_rptr); if(i->ioc_count != sizeof(u_char)) goto passalong; if( *(u_char *) mp->b_cont->b_rptr) p->pii_flags |= PII_FLAGS_COMPPROT; else p->pii_flags &= ~PII_FLAGS_COMPPROT; goto passalong; case SIOCSIFVJCOMP: /* enable or disable VJ compression */ #ifdef VJC if(i->ioc_count != sizeof(u_char)) goto passalong; DLOG("ppp_if: SIFVJCOMP %d\n", *(u_char *) mp->b_cont->b_rptr); if( *(u_char *) mp->b_cont->b_rptr) p->pii_flags |= PII_FLAGS_VJC_ON; else p->pii_flags &= ~PII_FLAGS_VJC_ON; mp->b_datap->db_type = M_IOCACK; #else mp->b_datap->db_type = M_IOCNAK; i->ioc_error = EINVAL; i->ioc_count = 0; #endif qreply(q,mp); break; case SIOCGETU : /* get unit number */ if(mp->b_cont = allocb(sizeof(int), BPRI_MED)) { *(int *) mp->b_cont->b_wptr = p->pii_ifnet.if_unit; mp->b_cont->b_wptr += i->ioc_count = sizeof(int); mp->b_datap->db_type = M_IOCACK; qreply(q,mp); break; } i->ioc_error = ENOSR; i->ioc_count = 0; mp->b_datap->db_type = M_IOCNAK; qreply(q, mp); break; default: /* unknown IOCTL call */ passalong:; putnext(q,mp); /* pass it along */ } DLOG("ppp: Pii->flags 0x%x\n",p->pii_flags); break; default : putnext(q,mp); /* don't know what to do with this, so send it along*/ } } static int ppp_if_wsrv(q) queue_t *q; { register mblk_t *mp; register PII *p; p = (PII *) q->q_ptr; while((mp = getq(q)) != NULL) { /* we can only get M_DATA types into our Queue, due to our Put function */ if(!canput(q->q_next)) { putbq(q, mp); return; } p->pii_ifnet.if_opackets++; /* increment count of outgoing packets */ INCR(sl_opackets); putnext(q, mp); /* just pass it along, nothing to do in this direction */ } /* end while */ } static int ppp_if_rput(q, mp) queue_t *q; register mblk_t *mp; { register u_char *c; register PII *p; switch (mp->b_datap->db_type) { case M_FLUSH : if(*mp->b_rptr & FLUSHR) flushq(q, FLUSHDATA); putnext(q, mp); /* send it along too */ break; case M_DATA : putq(q, mp); /* queue it for my service routine */ break; case M_CTL : /* could be a message from below */ p = (PII *) q->q_ptr; c = (u_char *) mp->b_rptr; switch (c) { case IF_INPUT_ERROR : p->pii_ifnet.if_ierrors++; INCR(sl_ierrors); DLOG("ppp_if: input error inc to %d\n", p->pii_ifnet.if_ierrors); break; case IF_OUTPUT_ERROR : p->pii_ifnet.if_oerrors++; INCR(sl_oerrors); DLOG("ppp_if: output error inc to %d\n", p->pii_ifnet.if_oerrors); break; default:; break; } freemsg(mp); /* putnext(q, mp); */ break; default : putnext(q,mp); /* don't know what to do with this, so send it along*/ } } static int ppp_if_rsrv(q) queue_t *q; { register mblk_t *mp,*m0; #ifdef VJC register mblk_t *mvjc; unsigned char *cp; #endif register PII *p; struct ifnet **ifp; struct ppp_header *ph; struct mbuf *mb1, *mb2,*mbtail; int len,xlen,count,s; u_char *rptr; p = (PII *) q->q_ptr; while((mp = getq(q)) != NULL) { /* we can only get M_DATA types into our Queue, due to our Put function */ m0 = mp; /* remember first message block */ ph = (struct ppp_header *) mp->b_rptr; /* assume ppp_header is completely in first block */ if(mp->b_wptr - mp->b_rptr < sizeof(struct ppp_header)) { freemsg(mp); p->pii_ifnet.if_ierrors++; continue; } #ifdef VJC switch (ntohs(ph->ph_protocol)) { case PPP_IP : break; case PPP_VJC_COMP : if(p->pii_flags & PII_FLAGS_VJC_ON) { for(xlen=0, mvjc = mp; mvjc; mvjc = mvjc->b_cont) xlen += (mvjc->b_wptr - mvjc->b_rptr); xlen -= sizeof(struct ppp_header); if(!(mvjc = allocb(128, BPRI_MED))) { /* get a 128 byte buffer for IP header*/ putbq(q,mp); qenable(q); return; } mvjc->b_wptr += 128; linkb(mvjc,mp); if(!pullupmsg(mvjc,-1)) { /* string em all together. ugh what a waste */ freemsg(mvjc); continue; } cp = mvjc->b_rptr + 128 + sizeof(struct ppp_header); m0 = mp = mvjc; xlen = sl_uncompress_tcp(&cp,xlen, TYPE_COMPRESSED_TCP, &p->pii_sc_comp); if(!xlen) { DLOG("ppp: sl_uncompress failed on type Compressed",0);; goto reject; } mp->b_rptr = cp - sizeof(struct ppp_header); ((struct ppp_header *) mp->b_rptr)->ph_protocol = htons(PPP_IP); break; } case PPP_VJC_UNCOMP : if(p->pii_flags & PII_FLAGS_VJC_ON) { cp = (unsigned char *) mp->b_rptr + sizeof(struct ppp_header); if(sl_uncompress_tcp(&cp, 1, TYPE_UNCOMPRESSED_TCP, &p->pii_sc_comp)) { ((struct ppp_header *) mp->b_rptr)->ph_protocol = htons(PPP_IP); break; } DLOG("ppp: sl_uncompress failed on type Uncompresed\n",0); reject:; freemsg(mp); continue; } default :; #endif #ifndef VJC if(ntohs(ph->ph_protocol) != PPP_IP) { #endif DLOG("ppp: unknown protocol 0x%x\n",ntohs(ph->ph_protocol)); INCR(sl_ipackets); if(!canput(q->q_next)) { putbq(q, mp); return; } putnext(q,mp); p->pii_ifnet.if_ipackets++; continue; #ifndef VJC } #endif } len = 0; mb1 = NULL; xlen = mp->b_wptr - (rptr = mp->b_rptr); while(mp) { if(len < 1) { MGET(mb2, M_DONTWAIT, MT_DATA); if(!mb2) { p->pii_ifnet.if_ierrors++; putbq(q,m0); qenable(q); if(mb1) m_freem(mb1); /* discard what we've used already */ return; } /* if we couldn't get a buffer, put back the message and try later */ len = MLEN; mb2->m_len = 0; if(mb1) { mbtail->m_next = mb2; mbtail = mb2; } else mbtail = mb1 = mb2; } count = MIN(xlen, len); bcopy((char *) rptr, mtod(mb2, char *) + mb2->m_len, count); #ifdef PPP_STATS p->pii_stats.sl_ibytes += count; #endif rptr += count; len -= count; xlen -= count; mb2->m_len += count; if(!xlen) { /* move to the next mblk */ mp = mp->b_cont; if(mp) xlen = mp->b_wptr - (rptr = mp->b_rptr); } } #define HADJ (sizeof(struct ppp_header) - sizeof(struct ifnet *)) /* note, HADJ >= 0 is assumed */ ifp = (struct ifnet **) (mtod(mb1, u_char *) + HADJ); *ifp = &p->pii_ifnet; /* stick ifnet * in front of packet */ mb1->m_off += HADJ; mb1->m_len -= HADJ; freemsg(m0); p->pii_ifnet.if_ipackets++; INCR(sl_ipackets); s = splimp(); if (IF_QFULL(&ipintrq)) { IF_DROP(&ipintrq); p->pii_ifnet.if_ierrors++; m_freem(mb1); } else { IF_ENQUEUE(&ipintrq, mb1); schednetisr(NETISR_IP); } splx(s); } /* end while */ } /* ifp output procedure */ int ppp_output(ifp, m0, dst) struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst; { register PII *p = &pii[ifp->if_unit]; struct mbuf *m1; int error,s, len; u_short protocol; #ifdef VJC u_char type; #endif mblk_t *mp; error = 0; if((ifp->if_flags & IFF_RUNNING) != IFF_RUNNING || !p->pii_writeq) { error = ENETDOWN; goto getout; } switch (dst->sa_family) { #ifdef INET case AF_INET : protocol = PPP_IP; break; #endif #ifdef NS case AF_NS : protocol = PPP_XNS; break; #endif default :; printf("ppp%d: af%d not supported\n",ifp->if_unit, dst->sa_family); error = EAFNOSUPPORT; goto getout; } #ifdef VJC if((protocol == PPP_IP) && (p->pii_flags & PII_FLAGS_VJC_ON)) { register struct ip *ip; ip = mtod(m0, struct ip *); if(ip->ip_p == IPPROTO_TCP) { type = sl_compress_tcp(m0, ip, &p->pii_sc_comp, 1); switch (type) { case TYPE_UNCOMPRESSED_TCP : protocol = PPP_VJC_UNCOMP; break; case TYPE_COMPRESSED_TCP : protocol = PPP_VJC_COMP; break; default :; } } } #endif len = 0; for(m1 = m0; m1; m1 = m1->m_next) len += m1->m_len; if(!(p->pii_flags & PII_FLAGS_COMPAC)) len += 2; /* if we are not compac, then need 2 extra bytes */ if(p->pii_flags & PII_FLAGS_COMPPROT) len += 1; else len += 2; /* we never need to check the actual protocol, since its always either PPP_IP,PPP_VJC_* or PPP_XNS */ if(!(mp = allocb(len, BPRI_LO))) { error = ENOBUFS; goto getout; } #ifdef PPP_STATS p->pii_stats.sl_obytes += len; #endif if(!(p->pii_flags & PII_FLAGS_COMPAC)) { *mp->b_wptr++ = PPP_ALLSTATIONS; *mp->b_wptr++ = PPP_UI; } if(!(p->pii_flags & PII_FLAGS_COMPPROT)) *mp->b_wptr++ = 0; *mp->b_wptr++ = protocol & 0xff; for(m1 = m0; m1; m1 = m1->m_next) { /* copy all data */ bcopy(mtod(m1, char *), (char *) mp->b_wptr, m1->m_len); mp->b_wptr += m1->m_len; } s = splstr(); putq(p->pii_writeq, mp); splx(s); p->pii_ifnet.if_opackets++; INCR(sl_opackets); getout:; m_freem(m0); if(error) { INCR(sl_oerrors); p->pii_ifnet.if_oerrors++; } return(error); /* gads, streams are great */ } /* * if_ ioctl requests */ ppp_ioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data; { register struct ifaddr *ifa = (struct ifaddr *) data; register struct ifreq *ifr = (struct ifreq *) data; int s = splimp(), error = 0; if(ifa == NULL ) { splx(s); return(EFAULT); } switch (cmd) { case SIOCSIFFLAGS : if(!suser()) { error = EPERM; break; } ifp->if_flags &= (IFF_CANTCHANGE); /* clear the flags that can be cleared */ ifp->if_flags |= (ifr->ifr_flags & ~IFF_CANTCHANGE); /* or in the flags that can be changed */ break; case SIOCGIFFLAGS : ifr->ifr_flags = ifp->if_flags; break; case SIOCSIFADDR : if( ifa->ifa_addr.sa_family != AF_INET) error = EAFNOSUPPORT; break; case SIOCSIFDSTADDR : if(ifa->ifa_addr.sa_family != AF_INET) error = EAFNOSUPPORT; break; case SIOCSIFMTU : if(!suser()) { error = EPERM; break; } if(ifr->ifr_mtu > (4096 - (sizeof(struct ppp_header) + sizeof(u_short)))) { error = EINVAL; break; } ifp->if_mtu = ifr->ifr_mtu; break; case SIOCGIFMTU : ifr->ifr_mtu = ifp->if_mtu; break; default :; error = EINVAL; break; } splx(s); return(error); } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.