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.1 1995/12/19 00:05:59 paulus Exp $
31 * This file is used under SunOS 4.
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/stream.h>
39 #include <sys/errno.h>
40 #include <sys/kmem_alloc.h>
42 #include <sys/socket.h>
43 #include <sys/sockio.h>
45 #include <net/netisr.h>
46 #include <net/ppp_defs.h>
47 #include <net/pppio.h>
48 #include <netinet/in.h>
49 #include <netinet/in_var.h>
51 #define NOTSUSER() (suser()? 0: EPERM)
52 #define ifr_mtu ifr_metric
54 #define ZALLOC(n, t, how) ((t *) kmem_zalloc((n) * sizeof(t), (how)))
55 #define ZFREE(p, n, t) kmem_free((void *)(p), (n) * sizeof(t))
58 #define PPP_MAXMTU 65536
60 typedef unsigned char uchar_t;
61 typedef unsigned short ushort_t;
63 static int if_ppp_open __P((queue_t *, int, int, int));
64 static int if_ppp_close __P((queue_t *, int));
65 static int if_ppp_wput __P((queue_t *, mblk_t *));
66 static int if_ppp_rput __P((queue_t *, mblk_t *));
68 static struct module_info minfo = {
69 0x8021, "if_ppp", 0, INFPSZ, 4096, 128
72 static struct qinit rinit = {
73 if_ppp_rput, NULL, if_ppp_open, if_ppp_close, NULL, &minfo, NULL
76 static struct qinit winit = {
77 if_ppp_wput, NULL, NULL, NULL, NULL, &minfo, NULL
80 struct streamtab if_pppinfo = {
81 &rinit, &winit, NULL, NULL
84 typedef struct if_ppp_state {
90 /* Values for flags */
93 static int if_ppp_count; /* Number of currently-active streams */
95 static int ppp_nalloc; /* Number of elements of ifs and states */
96 static struct ifnet **ifs; /* Array of pointers to interface structs */
97 static if_ppp_t **states; /* Array of pointers to state structs */
99 static int if_ppp_output __P((struct ifnet *, struct mbuf *,
101 static int if_ppp_ioctl __P((struct ifnet *, u_long, caddr_t));
102 static struct mbuf *make_mbufs __P((mblk_t *, int));
103 static mblk_t *make_message __P((struct mbuf *, int));
104 static void ppp_if_detach __P((struct ifnet *));
107 * Detach all the interfaces before unloading.
108 * Not sure this works.
115 if (if_ppp_count > 0)
117 for (i = 0; i < ppp_nalloc; ++i)
119 ppp_if_detach(ifs[i]);
120 ZFREE(ifs, ppp_nalloc, struct ifnet *);
121 ZFREE(states, ppp_nalloc, if_ppp_t *);
127 * STREAMS module entry points.
130 if_ppp_open(q, dev, flag, sflag)
138 sp = ZALLOC(1, if_ppp_t, KMEM_SLEEP);
141 q->q_ptr = (caddr_t) sp;
142 WR(q)->q_ptr = (caddr_t) sp;
143 sp->unit = -1; /* no interface unit attached at present */
152 if_ppp_close(q, flag)
159 sp = (if_ppp_t *) q->q_ptr;
161 if (sp->flags & DBGLOG)
162 printf("if_ppp closed, q=%x sp=%x\n", q, sp);
164 if (sp->unit < ppp_nalloc) {
165 states[sp->unit] = 0;
168 ifp->if_flags &= ~(IFF_UP | IFF_RUNNING);
171 printf("if_ppp: unit %d nonexistent!\n", sp->unit);
175 ZFREE(sp, 1, if_ppp_t);
191 sp = (if_ppp_t *) q->q_ptr;
192 switch (mp->b_datap->db_type) {
195 * Now why would we be getting data coming in here??
197 if (sp->flags & DBGLOG)
198 printf("if_ppp: got M_DATA len=%d\n", msgdsize(mp));
203 iop = (struct iocblk *) mp->b_rptr;
206 if (sp->flags & DBGLOG)
207 printf("if_ppp: got ioctl cmd=%x count=%d\n",
208 iop->ioc_cmd, iop->ioc_count);
210 switch (iop->ioc_cmd) {
211 case PPPIO_NEWPPA: /* well almost */
212 if (iop->ioc_count != sizeof(int) || sp->unit >= 0)
214 if ((error = NOTSUSER()) != 0)
216 unit = *(int *)mp->b_cont->b_rptr;
218 /* Check that this unit isn't already in use */
219 if (unit < ppp_nalloc && states[unit] != 0) {
224 /* Extend ifs and states arrays if necessary. */
226 if (unit >= ppp_nalloc) {
228 struct ifnet **newifs;
229 if_ppp_t **newstates;
232 if (sp->flags & DBGLOG)
233 printf("if_ppp: extending ifs to %d\n", newn);
234 newifs = ZALLOC(newn, struct ifnet *, KMEM_NOSLEEP);
237 newstates = ZALLOC(newn, if_ppp_t *, KMEM_NOSLEEP);
238 if (newstates == 0) {
239 ZFREE(newifs, newn, struct ifnet *);
242 bcopy(ifs, newifs, ppp_nalloc * sizeof(struct ifnet *));
243 bcopy(states, newstates, ppp_nalloc * sizeof(if_ppp_t *));
249 /* Allocate a new ifnet struct if necessary. */
252 ifp = ZALLOC(1, struct ifnet, KMEM_NOSLEEP);
256 ifp->if_name = "ppp";
258 ifp->if_mtu = PPP_MRU;
259 ifp->if_flags = IFF_POINTOPOINT | IFF_RUNNING;
261 ifp->if_flags |= IFF_MULTICAST;
263 ifp->if_output = if_ppp_output;
264 ifp->if_ioctl = if_ppp_ioctl;
265 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
267 if (sp->flags & DBGLOG)
268 printf("if_ppp: created unit %d\n", unit);
270 ifp->if_mtu = PPP_MRU;
271 ifp->if_flags |= IFF_RUNNING;
279 if (sp->flags & DBGLOG)
280 printf("if_ppp: attached unit %d, sp=%x q=%x\n", unit,
286 if (iop->ioc_count == sizeof(int)) {
287 if (*(int *)mp->b_cont->b_rptr == PPPDBG_LOG + PPPDBG_IF) {
288 printf("if_ppp: debug log enabled, q=%x sp=%x\n", q, sp);
301 if (sp->flags & DBGLOG)
302 printf("if_ppp: ioctl result %d\n", error);
305 else if (error == 0) {
306 mp->b_datap->db_type = M_IOCACK;
309 mp->b_datap->db_type = M_IOCNAK;
311 iop->ioc_error = error;
333 sp = (if_ppp_t *) q->q_ptr;
334 switch (mp->b_datap->db_type) {
337 * Convert the message into an mbuf chain
338 * and inject it into the network code.
340 if (sp->flags & DBGLOG)
341 printf("if_ppp: rput pkt len %d data %x %x %x %x %x %x %x %x\n",
342 msgdsize(mp), mp->b_rptr[0], mp->b_rptr[1], mp->b_rptr[2],
343 mp->b_rptr[3], mp->b_rptr[4], mp->b_rptr[5], mp->b_rptr[6],
350 if (sp->unit >= ppp_nalloc || (ifp = ifs[sp->unit]) == 0) {
352 printf("if_ppp: no unit %d!\n", sp->unit);
358 if ((ifp->if_flags & IFF_UP) == 0) {
364 proto = PPP_PROTOCOL(mp->b_rptr);
365 adjmsg(mp, PPP_HDRLEN);
366 mb = make_mbufs(mp, sizeof(struct ifnet *));
369 if (sp->flags & DBGLOG)
370 printf("if_ppp%d: make_mbufs failed\n", ifp->if_unit);
374 mb->m_off -= sizeof(struct ifnet *);
375 mb->m_len += sizeof(struct ifnet *);
376 *mtod(mb, struct ifnet **) = ifp;
382 schednetisr(NETISR_IP);
390 if (sp->flags & DBGLOG)
391 printf("if_ppp: inq full, proto=%x\n", proto);
398 if (sp->flags & DBGLOG)
399 printf("if_ppp%d: proto=%x?\n", ifp->if_unit, proto);
412 * Network code wants to output a packet.
413 * Turn it into a STREAMS message and send it down.
416 if_ppp_output(ifp, m0, dst)
419 struct sockaddr *dst;
426 if ((ifp->if_flags & IFF_UP) == 0) {
431 if ((unsigned)ifp->if_unit >= ppp_nalloc) {
433 printf("if_ppp_output: unit %d?\n", ifp->if_unit);
438 sp = states[ifp->if_unit];
441 printf("if_ppp_output: no queue?\n");
447 if (sp->flags & DBGLOG) {
448 p = mtod(m0, u_char *);
449 printf("if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n",
450 ifp->if_unit, dst->sa_family, p[0], p[1], p[2], p[3], p[4],
451 p[5], p[6], p[7], sp->q);
454 switch (dst->sa_family) {
464 mp = make_message(m0, PPP_HDRLEN);
470 mp->b_rptr -= PPP_HDRLEN;
471 mp->b_rptr[0] = PPP_ALLSTATIONS;
472 mp->b_rptr[1] = PPP_UI;
473 mp->b_rptr[2] = proto >> 8;
474 mp->b_rptr[3] = proto;
477 if (sp->flags & DBGLOG)
478 printf("if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n",
479 sp->q, mp, mp->b_rptr, mp->b_wptr, proto);
487 * Socket ioctl routine for ppp interfaces.
490 if_ppp_ioctl(ifp, cmd, data)
496 struct ifreq *ifr = (struct ifreq *) data;
497 struct ifaddr *ifa = (struct ifaddr *) data;
503 if ((ifp->if_flags & IFF_RUNNING) == 0)
504 ifp->if_flags &= ~IFF_UP;
508 if (ifa->ifa_addr.sa_family != AF_INET)
509 error = EAFNOSUPPORT;
513 if (ifa->ifa_addr.sa_family != AF_INET)
514 error = EAFNOSUPPORT;
518 if ((error = NOTSUSER()) != 0)
520 if (ifr->ifr_mtu < PPP_MINMTU || ifr->ifr_mtu > PPP_MAXMTU) {
524 ifp->if_mtu = ifr->ifr_mtu;
528 ifr->ifr_mtu = ifp->if_mtu;
533 switch(ifr->ifr_addr.sa_family) {
537 error = EAFNOSUPPORT;
550 * Turn a STREAMS message into an mbuf chain.
557 struct mbuf *head, **prevp, *m;
559 unsigned char *cp, *dp;
568 while (cp >= mp->b_wptr) {
578 MGET(m, M_DONTWAIT, MT_DATA);
585 if (len + off > 2 * MLEN) {
588 space = (m->m_off > MMAXOFF? MCLBYTES: MLEN) - off;
592 dp = mtod(m, unsigned char *);
607 * Turn an mbuf chain into a STREAMS message.
609 #define ALLOCB_MAX 4096
616 mblk_t *head, **prevp, *mp;
617 int len, space, n, nb;
618 unsigned char *cp, *dp;
622 for (nm = m; nm != 0; nm = nm->m_next)
626 cp = mtod(m, unsigned char *);
635 cp = mtod(m, unsigned char *);
640 if (space > ALLOCB_MAX)
642 mp = allocb(space, BPRI_LO);
649 dp = mp->b_rptr += off;
655 n = nb < space? nb: space;
666 * Remove an interface from the system.
667 * This routine contains magic.
669 #include <net/route.h>
670 #include <netinet/in_pcb.h>
671 #include <netinet/ip_var.h>
672 #include <netinet/tcp.h>
673 #include <netinet/tcp_timer.h>
674 #include <netinet/tcp_var.h>
675 #include <netinet/udp.h>
676 #include <netinet/udp_var.h>
685 struct in_ifaddr **inap;
691 * Clear the interface from any routes currently cached in
692 * TCP or UDP protocol control blocks.
694 for (pcb = tcb.inp_next; pcb != &tcb; pcb = pcb->inp_next)
695 if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
697 for (pcb = udb.inp_next; pcb != &udb; pcb = pcb->inp_next)
698 if (pcb->inp_route.ro_rt && pcb->inp_route.ro_rt->rt_ifp == ifp)
702 * Delete routes through all addresses of the interface.
704 for (ifa = ifp->if_addrlist; ifa != 0; ifa = ifa->ifa_next) {
705 rtinit(ifa, ifa, SIOCDELRT, RTF_HOST);
706 rtinit(ifa, ifa, SIOCDELRT, 0);
710 * Unlink the interface's address(es) from the in_ifaddr list.
712 for (inap = &in_ifaddr; *inap != 0; ) {
713 if ((*inap)->ia_ifa.ifa_ifp == ifp)
714 *inap = (*inap)->ia_next;
716 inap = &(*inap)->ia_next;
720 * Delete the interface from the ifnet list.
722 for (ifpp = &ifnet; (*ifpp) != 0; ) {
725 ifpp = &(*ifpp)->if_next;
728 printf("couldn't find interface ppp%d in ifnet list\n", ifp->if_unit);
730 *ifpp = ifp->if_next;