2 * if_ppp.c - a network interface connected to a STREAMS module.
4 * Copyright (c) 1994 The Australian National University.
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation is hereby granted, provided that the above copyright
9 * notice appears in all copies. This software is provided without any
10 * warranty, express or implied. The Australian National University
11 * makes no representations about the suitability of this software for
14 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
15 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
17 * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
20 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
23 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
24 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
27 * $Id: if_ppp.c,v 1.10 1998/05/04 06:11:14 paulus Exp $
31 * This file is used under SunOS 4 and Digital UNIX.
33 * This file provides the glue between PPP and IP.
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/errno.h>
42 #include <sys/socket.h>
44 #include <net/netisr.h>
45 #include <net/ppp_defs.h>
46 #include <net/pppio.h>
47 #include <netinet/in.h>
48 #include <netinet/in_var.h>
50 #include <sys/ioctl.h>
51 #include <net/if_types.h>
53 #include <sys/sockio.h>
57 #include <sys/stream.h>
61 #include <net/nit_if.h>
62 #include <netinet/if_ether.h>
66 #define SIOCSIFMTU SIOCSIPMTU
67 #define SIOCGIFMTU SIOCRIPMTU
68 #define IFA_ADDR(ifa) (*(ifa)->ifa_addr)
70 #define IFA_ADDR(ifa) ((ifa)->ifa_addr)
73 #define ifr_mtu ifr_metric
75 static int if_ppp_open __P((queue_t *, int, int, int));
76 static int if_ppp_close __P((queue_t *, int));
77 static int if_ppp_wput __P((queue_t *, mblk_t *));
78 static int if_ppp_rput __P((queue_t *, mblk_t *));
80 #define PPP_IF_ID 0x8021
81 static struct module_info minfo = {
82 PPP_IF_ID, "if_ppp", 0, INFPSZ, 4096, 128
85 static struct qinit rinit = {
86 if_ppp_rput, NULL, if_ppp_open, if_ppp_close, NULL, &minfo, NULL
89 static struct qinit winit = {
90 if_ppp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
93 struct streamtab if_pppinfo = {
94 &rinit, &winit, NULL, NULL
97 typedef struct if_ppp_state {
103 /* Values for flags */
106 static int if_ppp_count; /* Number of currently-active streams */
108 static int ppp_nalloc; /* Number of elements of ifs and states */
109 static struct ifnet **ifs; /* Array of pointers to interface structs */
110 static if_ppp_t **states; /* Array of pointers to state structs */
112 static int if_ppp_output __P((struct ifnet *, struct mbuf *,
114 static int if_ppp_ioctl __P((struct ifnet *, u_int, caddr_t));
115 static struct mbuf *make_mbufs __P((mblk_t *, int));
116 static mblk_t *make_message __P((struct mbuf *, int));
119 /* Fake ether header for SNIT */
120 static struct ether_header snit_ehdr = {{0}, {0}, ETHERTYPE_IP};
124 static void ppp_if_detach __P((struct ifnet *));
127 * Detach all the interfaces before unloading.
128 * Not sure this works.
135 if (if_ppp_count > 0)
137 for (i = 0; i < ppp_nalloc; ++i)
139 ppp_if_detach(ifs[i]);
141 FREE(ifs, ppp_nalloc * sizeof (struct ifnet *));
142 FREE(states, ppp_nalloc * sizeof (struct if_ppp_t *));
150 * STREAMS module entry points.
153 if_ppp_open(q, dev, flag, sflag)
161 sp = (if_ppp_t *) ALLOC_SLEEP(sizeof (if_ppp_t));
164 bzero(sp, sizeof (if_ppp_t));
165 q->q_ptr = (caddr_t) sp;
166 WR(q)->q_ptr = (caddr_t) sp;
167 sp->unit = -1; /* no interface unit attached at present */
176 if_ppp_close(q, flag)
183 sp = (if_ppp_t *) q->q_ptr;
185 if (sp->flags & DBGLOG)
186 printf("if_ppp closed, q=%x sp=%x\n", q, sp);
188 if (sp->unit < ppp_nalloc) {
189 states[sp->unit] = 0;
192 ifp->if_flags &= ~(IFF_UP | IFF_RUNNING);
195 printf("if_ppp: unit %d nonexistent!\n", sp->unit);
199 FREE(sp, sizeof (if_ppp_t));
215 sp = (if_ppp_t *) q->q_ptr;
216 switch (mp->b_datap->db_type) {
219 * Now why would we be getting data coming in here??
221 if (sp->flags & DBGLOG)
222 printf("if_ppp: got M_DATA len=%d\n", msgdsize(mp));
227 iop = (struct iocblk *) mp->b_rptr;
230 if (sp->flags & DBGLOG)
231 printf("if_ppp: got ioctl cmd=%x count=%d\n",
232 iop->ioc_cmd, iop->ioc_count);
234 switch (iop->ioc_cmd) {
235 case PPPIO_NEWPPA: /* well almost */
236 if (iop->ioc_count != sizeof(int) || sp->unit >= 0)
238 if ((error = NOTSUSER()) != 0)
240 unit = *(int *)mp->b_cont->b_rptr;
242 /* Check that this unit isn't already in use */
243 if (unit < ppp_nalloc && states[unit] != 0) {
248 /* Extend ifs and states arrays if necessary. */
250 if (unit >= ppp_nalloc) {
252 struct ifnet **newifs;
253 if_ppp_t **newstates;
256 if (sp->flags & DBGLOG)
257 printf("if_ppp: extending ifs to %d\n", newn);
258 newifs = (struct ifnet **)
259 ALLOC_NOSLEEP(newn * sizeof (struct ifnet *));
262 bzero(newifs, newn * sizeof (struct ifnet *));
263 newstates = (if_ppp_t **)
264 ALLOC_NOSLEEP(newn * sizeof (struct if_ppp_t *));
265 if (newstates == 0) {
266 FREE(newifs, newn * sizeof (struct ifnet *));
269 bzero(newstates, newn * sizeof (struct if_ppp_t *));
270 bcopy(ifs, newifs, ppp_nalloc * sizeof(struct ifnet *));
271 bcopy(states, newstates, ppp_nalloc * sizeof(if_ppp_t *));
273 FREE(ifs, ppp_nalloc * sizeof(struct ifnet *));
274 FREE(states, ppp_nalloc * sizeof(if_ppp_t *));
281 /* Allocate a new ifnet struct if necessary. */
284 ifp = (struct ifnet *) ALLOC_NOSLEEP(sizeof (struct ifnet));
287 bzero(ifp, sizeof (struct ifnet));
289 ifp->if_name = "ppp";
291 ifp->if_mtu = PPP_MTU;
292 ifp->if_flags = IFF_POINTOPOINT | IFF_RUNNING;
294 ifp->if_flags |= IFF_MULTICAST;
296 ifp->if_output = if_ppp_output;
298 ifp->if_version = "Point-to-Point Protocol, version 2.3.5";
299 ifp->if_mediamtu = PPP_MTU;
300 ifp->if_type = IFT_PPP;
301 ifp->if_hdrlen = PPP_HDRLEN;
303 ifp->if_flags |= IFF_NOARP | IFF_SIMPLEX | IFF_NOTRAILERS;
305 ifp->if_flags |= IFF_VAR_MTU;
308 ifp->if_affinity = NETMASTERCPU;
311 ifp->if_ioctl = if_ppp_ioctl;
312 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
314 if (sp->flags & DBGLOG)
315 printf("if_ppp: created unit %d\n", unit);
317 ifp->if_mtu = PPP_MTU;
318 ifp->if_flags |= IFF_RUNNING;
326 if (sp->flags & DBGLOG)
327 printf("if_ppp: attached unit %d, sp=%x q=%x\n", unit,
333 if (iop->ioc_count == sizeof(int)) {
334 if (*(int *)mp->b_cont->b_rptr == PPPDBG_LOG + PPPDBG_IF) {
335 printf("if_ppp: debug log enabled, q=%x sp=%x\n", q, sp);
348 if (sp->flags & DBGLOG)
349 printf("if_ppp: ioctl result %d\n", error);
352 else if (error == 0) {
353 mp->b_datap->db_type = M_IOCACK;
356 mp->b_datap->db_type = M_IOCNAK;
358 iop->ioc_error = error;
381 sp = (if_ppp_t *) q->q_ptr;
382 switch (mp->b_datap->db_type) {
385 * Convert the message into an mbuf chain
386 * and inject it into the network code.
388 if (sp->flags & DBGLOG)
389 printf("if_ppp: rput pkt len %d data %x %x %x %x %x %x %x %x\n",
390 msgdsize(mp), mp->b_rptr[0], mp->b_rptr[1], mp->b_rptr[2],
391 mp->b_rptr[3], mp->b_rptr[4], mp->b_rptr[5], mp->b_rptr[6],
398 if (sp->unit >= ppp_nalloc || (ifp = ifs[sp->unit]) == 0) {
400 printf("if_ppp: no unit %d!\n", sp->unit);
406 if ((ifp->if_flags & IFF_UP) == 0) {
412 proto = PPP_PROTOCOL(mp->b_rptr);
413 adjmsg(mp, PPP_HDRLEN);
415 mb = make_mbufs(mp, sizeof(struct ifnet *));
418 if (sp->flags & DBGLOG)
419 printf("if_ppp%d: make_mbufs failed\n", ifp->if_unit);
425 if (proto == PPP_IP && (ifp->if_flags & IFF_PROMISC)) {
428 nif.nif_header = (caddr_t) &snit_ehdr;
429 nif.nif_hdrlen = sizeof(snit_ehdr);
430 nif.nif_bodylen = len;
432 snit_intr(ifp, mb, &nif);
437 * For Digital UNIX, there's space set aside in the header mbuf
438 * for the interface info.
440 * For Sun it's smuggled around via a pointer at the front of the mbuf.
443 mb->m_pkthdr.rcvif = ifp;
444 mb->m_pkthdr.len = len;
446 mb->m_off -= sizeof(struct ifnet *);
447 mb->m_len += sizeof(struct ifnet *);
448 *mtod(mb, struct ifnet **) = ifp;
455 schednetisr(NETISR_IP);
463 if (sp->flags & DBGLOG)
464 printf("if_ppp: inq full, proto=%x\n", proto);
471 if (sp->flags & DBGLOG)
472 printf("if_ppp%d: proto=%x?\n", ifp->if_unit, proto);
485 * Network code wants to output a packet.
486 * Turn it into a STREAMS message and send it down.
489 if_ppp_output(ifp, m0, dst)
492 struct sockaddr *dst;
499 if ((ifp->if_flags & IFF_UP) == 0) {
504 if ((unsigned)ifp->if_unit >= ppp_nalloc) {
506 printf("if_ppp_output: unit %d?\n", ifp->if_unit);
511 sp = states[ifp->if_unit];
514 printf("if_ppp_output: no queue?\n");
520 if (sp->flags & DBGLOG) {
521 p = mtod(m0, u_char *);
522 printf("if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n",
523 ifp->if_unit, dst->sa_family, p[0], p[1], p[2], p[3], p[4],
524 p[5], p[6], p[7], sp->q);
527 switch (dst->sa_family) {
531 if (ifp->if_flags & IFF_PROMISC) {
536 for (len = 0, m = m0; m != NULL; m = m->m_next)
538 nif.nif_header = (caddr_t) &snit_ehdr;
539 nif.nif_hdrlen = sizeof(snit_ehdr);
540 nif.nif_bodylen = len;
542 snit_intr(ifp, m0, &nif);
553 mp = make_message(m0, PPP_HDRLEN);
559 mp->b_rptr -= PPP_HDRLEN;
560 mp->b_rptr[0] = PPP_ALLSTATIONS;
561 mp->b_rptr[1] = PPP_UI;
562 mp->b_rptr[2] = proto >> 8;
563 mp->b_rptr[3] = proto;
566 if (sp->flags & DBGLOG)
567 printf("if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n",
568 sp->q, mp, mp->b_rptr, mp->b_wptr, proto);
576 * Socket ioctl routine for ppp interfaces.
579 if_ppp_ioctl(ifp, cmd, data)
585 struct ifreq *ifr = (struct ifreq *) data;
586 struct ifaddr *ifa = (struct ifaddr *) data;
592 if ((ifp->if_flags & IFF_RUNNING) == 0)
593 ifp->if_flags &= ~IFF_UP;
597 if (IFA_ADDR(ifa).sa_family != AF_INET)
598 error = EAFNOSUPPORT;
602 if (IFA_ADDR(ifa).sa_family != AF_INET)
603 error = EAFNOSUPPORT;
607 if ((error = NOTSUSER()) != 0)
609 if (ifr->ifr_mtu < PPP_MINMTU || ifr->ifr_mtu > PPP_MAXMTU) {
613 ifp->if_mtu = ifr->ifr_mtu;
617 ifr->ifr_mtu = ifp->if_mtu;
622 switch(ifr->ifr_addr.sa_family) {
626 error = EAFNOSUPPORT;
639 * Turn a STREAMS message into an mbuf chain.
646 struct mbuf *head, **prevp, *m;
648 unsigned char *cp, *dp;
657 MGETHDR(m, M_DONTWAIT, MT_DATA);
662 dp = mtod(m, unsigned char *);
667 while (cp >= mp->b_wptr) {
677 MGET(m, M_DONTWAIT, MT_DATA);
684 if (len + off > 2 * MLEN) {
686 MCLGET(m, M_DONTWAIT);
692 space = ((m->m_flags & M_EXT) ? MCLBYTES : MLEN);
694 space = (m->m_off > MMAXOFF? MCLBYTES: MLEN) - off;
699 dp = mtod(m, unsigned char *);
714 * Turn an mbuf chain into a STREAMS message.
716 #define ALLOCB_MAX 4096
723 mblk_t *head, **prevp, *mp;
724 int len, space, n, nb;
725 unsigned char *cp, *dp;
729 for (nm = m; nm != 0; nm = nm->m_next)
733 cp = mtod(m, unsigned char *);
742 cp = mtod(m, unsigned char *);
747 if (space > ALLOCB_MAX)
749 mp = allocb(space, BPRI_LO);
756 dp = mp->b_rptr += off;
762 n = nb < space? nb: space;
773 * Digital UNIX doesn't allow for removing ifnet structures
774 * from the list. But then we're not using this as a loadable
775 * module anyway, so that's OK.
777 * Under SunOS, this should allow the module to be unloaded.
778 * Unfortunately, it doesn't seem to detach all the references,
779 * so your system may well crash after you unload this module :-(
784 * Remove an interface from the system.
785 * This routine contains magic.
787 #include <net/route.h>
788 #include <netinet/in_pcb.h>
789 #include <netinet/ip_var.h>
790 #include <netinet/tcp.h>
791 #include <netinet/tcp_timer.h>
792 #include <netinet/tcp_var.h>
793 #include <netinet/udp.h>
794 #include <netinet/udp_var.h>
803 struct in_ifaddr **inap;
809 * Clear the interface from any routes currently cached in
810 * TCP or UDP protocol control blocks.
812 for (pcb = tcb.inp_next; pcb != &tcb; pcb = pcb->inp_next)
813 if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
815 for (pcb = udb.inp_next; pcb != &udb; pcb = pcb->inp_next)
816 if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
820 * Delete routes through all addresses of the interface.
822 for (ifa = ifp->if_addrlist; ifa != 0; ifa = ifa->ifa_next) {
823 rtinit(ifa, ifa, SIOCDELRT, RTF_HOST);
824 rtinit(ifa, ifa, SIOCDELRT, 0);
828 * Unlink the interface's address(es) from the in_ifaddr list.
830 for (inap = &in_ifaddr; *inap != 0; ) {
831 if ((*inap)->ia_ifa.ifa_ifp == ifp)
832 *inap = (*inap)->ia_next;
834 inap = &(*inap)->ia_next;
838 * Delete the interface from the ifnet list.
840 for (ifpp = &ifnet; (*ifpp) != 0; ) {
843 ifpp = &(*ifpp)->if_next;
846 printf("couldn't find interface ppp%d in ifnet list\n", ifp->if_unit);
848 *ifpp = ifp->if_next;