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.1.4 2003/10/14 08:09:53 sparq 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
;
295 ifp
->if_flags
|= IFF_MULTICAST
;
298 ifp
->if_output
= if_ppp_output
;
300 ifp
->if_version
= "Point-to-Point Protocol, version 2.3.11";
301 ifp
->if_mediamtu
= PPP_MTU
;
302 ifp
->if_type
= IFT_PPP
;
303 ifp
->if_hdrlen
= PPP_HDRLEN
;
305 ifp
->if_flags
|= IFF_NOARP
| IFF_SIMPLEX
| IFF_NOTRAILERS
;
307 ifp
->if_flags
|= IFF_VAR_MTU
;
310 ifp
->if_affinity
= NETMASTERCPU
;
313 ifp
->if_ioctl
= if_ppp_ioctl
;
314 ifp
->if_snd
.ifq_maxlen
= IFQ_MAXLEN
;
316 if (sp
->flags
& DBGLOG
)
317 printf("if_ppp: created unit %d\n", unit
);
319 ifp
->if_mtu
= PPP_MTU
;
320 ifp
->if_flags
|= IFF_RUNNING
;
328 if (sp
->flags
& DBGLOG
)
329 printf("if_ppp: attached unit %d, sp=%x q=%x\n", unit
,
335 if (iop
->ioc_count
== sizeof(int)) {
336 if (*(int *)mp
->b_cont
->b_rptr
== PPPDBG_LOG
+ PPPDBG_IF
) {
337 printf("if_ppp: debug log enabled, q=%x sp=%x\n", q
, sp
);
350 if (sp
->flags
& DBGLOG
)
351 printf("if_ppp: ioctl result %d\n", error
);
354 else if (error
== 0) {
355 mp
->b_datap
->db_type
= M_IOCACK
;
358 mp
->b_datap
->db_type
= M_IOCNAK
;
360 iop
->ioc_error
= error
;
383 sp
= (if_ppp_t
*) q
->q_ptr
;
384 switch (mp
->b_datap
->db_type
) {
387 * Convert the message into an mbuf chain
388 * and inject it into the network code.
390 if (sp
->flags
& DBGLOG
)
391 printf("if_ppp: rput pkt len %d data %x %x %x %x %x %x %x %x\n",
392 msgdsize(mp
), mp
->b_rptr
[0], mp
->b_rptr
[1], mp
->b_rptr
[2],
393 mp
->b_rptr
[3], mp
->b_rptr
[4], mp
->b_rptr
[5], mp
->b_rptr
[6],
400 if (sp
->unit
>= ppp_nalloc
|| (ifp
= ifs
[sp
->unit
]) == 0) {
402 printf("if_ppp: no unit %d!\n", sp
->unit
);
408 if ((ifp
->if_flags
& IFF_UP
) == 0) {
414 proto
= PPP_PROTOCOL(mp
->b_rptr
);
415 adjmsg(mp
, PPP_HDRLEN
);
417 mb
= make_mbufs(mp
, sizeof(struct ifnet
*));
420 if (sp
->flags
& DBGLOG
)
421 printf("if_ppp%d: make_mbufs failed\n", ifp
->if_unit
);
427 if (proto
== PPP_IP
&& (ifp
->if_flags
& IFF_PROMISC
)) {
430 nif
.nif_header
= (caddr_t
) &snit_ehdr
;
431 nif
.nif_hdrlen
= sizeof(snit_ehdr
);
432 nif
.nif_bodylen
= len
;
434 snit_intr(ifp
, mb
, &nif
);
439 * For Digital UNIX, there's space set aside in the header mbuf
440 * for the interface info.
442 * For Sun it's smuggled around via a pointer at the front of the mbuf.
445 mb
->m_pkthdr
.rcvif
= ifp
;
446 mb
->m_pkthdr
.len
= len
;
448 mb
->m_off
-= sizeof(struct ifnet
*);
449 mb
->m_len
+= sizeof(struct ifnet
*);
450 *mtod(mb
, struct ifnet
**) = ifp
;
457 schednetisr(NETISR_IP
);
465 if (sp
->flags
& DBGLOG
)
466 printf("if_ppp: inq full, proto=%x\n", proto
);
473 if (sp
->flags
& DBGLOG
)
474 printf("if_ppp%d: proto=%x?\n", ifp
->if_unit
, proto
);
487 * Network code wants to output a packet.
488 * Turn it into a STREAMS message and send it down.
491 if_ppp_output(ifp
, m0
, dst
)
494 struct sockaddr
*dst
;
501 if ((ifp
->if_flags
& IFF_UP
) == 0) {
506 if ((unsigned)ifp
->if_unit
>= ppp_nalloc
) {
508 printf("if_ppp_output: unit %d?\n", ifp
->if_unit
);
513 sp
= states
[ifp
->if_unit
];
516 printf("if_ppp_output: no queue?\n");
522 if (sp
->flags
& DBGLOG
) {
523 p
= mtod(m0
, u_char
*);
524 printf("if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n",
525 ifp
->if_unit
, dst
->sa_family
, p
[0], p
[1], p
[2], p
[3], p
[4],
526 p
[5], p
[6], p
[7], sp
->q
);
529 switch (dst
->sa_family
) {
533 if (ifp
->if_flags
& IFF_PROMISC
) {
538 for (len
= 0, m
= m0
; m
!= NULL
; m
= m
->m_next
)
540 nif
.nif_header
= (caddr_t
) &snit_ehdr
;
541 nif
.nif_hdrlen
= sizeof(snit_ehdr
);
542 nif
.nif_bodylen
= len
;
544 snit_intr(ifp
, m0
, &nif
);
555 mp
= make_message(m0
, PPP_HDRLEN
);
561 mp
->b_rptr
-= PPP_HDRLEN
;
562 mp
->b_rptr
[0] = PPP_ALLSTATIONS
;
563 mp
->b_rptr
[1] = PPP_UI
;
564 mp
->b_rptr
[2] = proto
>> 8;
565 mp
->b_rptr
[3] = proto
;
568 if (sp
->flags
& DBGLOG
)
569 printf("if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n",
570 sp
->q
, mp
, mp
->b_rptr
, mp
->b_wptr
, proto
);
578 * Socket ioctl routine for ppp interfaces.
581 if_ppp_ioctl(ifp
, cmd
, data
)
587 struct ifreq
*ifr
= (struct ifreq
*) data
;
588 struct ifaddr
*ifa
= (struct ifaddr
*) data
;
595 if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
596 ifp
->if_flags
&= ~IFF_UP
;
600 if (IFA_ADDR(ifa
).sa_family
!= AF_INET
)
601 error
= EAFNOSUPPORT
;
605 if (IFA_ADDR(ifa
).sa_family
!= AF_INET
)
606 error
= EAFNOSUPPORT
;
610 if ((error
= NOTSUSER()) != 0)
613 /* this hack is necessary because ifioctl checks ifr_data
614 * in 4.0 and 5.0, but ifr_data and ifr_metric overlay each
615 * other in the definition of struct ifreq so pppd can't set both.
617 bcopy(ifr
->ifr_data
, &mtu
, sizeof (u_short
));
621 if (ifr
->ifr_mtu
< PPP_MINMTU
|| ifr
->ifr_mtu
> PPP_MAXMTU
) {
625 ifp
->if_mtu
= ifr
->ifr_mtu
;
629 ifr
->ifr_mtu
= ifp
->if_mtu
;
634 switch(ifr
->ifr_addr
.sa_family
) {
638 error
= EAFNOSUPPORT
;
651 * Turn a STREAMS message into an mbuf chain.
658 struct mbuf
*head
, **prevp
, *m
;
660 unsigned char *cp
, *dp
;
669 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
674 dp
= mtod(m
, unsigned char *);
679 while (cp
>= mp
->b_wptr
) {
689 MGET(m
, M_DONTWAIT
, MT_DATA
);
696 if (len
+ off
> 2 * MLEN
) {
698 MCLGET(m
, M_DONTWAIT
);
704 space
= ((m
->m_flags
& M_EXT
) ? MCLBYTES
: MLEN
);
706 space
= (m
->m_off
> MMAXOFF
? MCLBYTES
: MLEN
) - off
;
711 dp
= mtod(m
, unsigned char *);
726 * Turn an mbuf chain into a STREAMS message.
728 #define ALLOCB_MAX 4096
735 mblk_t
*head
, **prevp
, *mp
;
736 int len
, space
, n
, nb
;
737 unsigned char *cp
, *dp
;
741 for (nm
= m
; nm
!= 0; nm
= nm
->m_next
)
745 cp
= mtod(m
, unsigned char *);
754 cp
= mtod(m
, unsigned char *);
759 if (space
> ALLOCB_MAX
)
761 mp
= allocb(space
, BPRI_LO
);
768 dp
= mp
->b_rptr
+= off
;
774 n
= nb
< space
? nb
: space
;
785 * Digital UNIX doesn't allow for removing ifnet structures
786 * from the list. But then we're not using this as a loadable
787 * module anyway, so that's OK.
789 * Under SunOS, this should allow the module to be unloaded.
790 * Unfortunately, it doesn't seem to detach all the references,
791 * so your system may well crash after you unload this module :-(
796 * Remove an interface from the system.
797 * This routine contains magic.
799 #include <net/route.h>
800 #include <netinet/in_pcb.h>
801 #include <netinet/ip_var.h>
802 #include <netinet/tcp.h>
803 #include <netinet/tcp_timer.h>
804 #include <netinet/tcp_var.h>
805 #include <netinet/udp.h>
806 #include <netinet/udp_var.h>
815 struct in_ifaddr
**inap
;
821 * Clear the interface from any routes currently cached in
822 * TCP or UDP protocol control blocks.
824 for (pcb
= tcb
.inp_next
; pcb
!= &tcb
; pcb
= pcb
->inp_next
)
825 if (pcb
->inp_route
.ro_rt
&& pcb
->inp_route
.ro_rt
->rt_ifp
== ifp
)
827 for (pcb
= udb
.inp_next
; pcb
!= &udb
; pcb
= pcb
->inp_next
)
828 if (pcb
->inp_route
.ro_rt
&& pcb
->inp_route
.ro_rt
->rt_ifp
== ifp
)
832 * Delete routes through all addresses of the interface.
834 for (ifa
= ifp
->if_addrlist
; ifa
!= 0; ifa
= ifa
->ifa_next
) {
835 rtinit(ifa
, ifa
, SIOCDELRT
, RTF_HOST
);
836 rtinit(ifa
, ifa
, SIOCDELRT
, 0);
840 * Unlink the interface's address(es) from the in_ifaddr list.
842 for (inap
= &in_ifaddr
; *inap
!= 0; ) {
843 if ((*inap
)->ia_ifa
.ifa_ifp
== ifp
)
844 *inap
= (*inap
)->ia_next
;
846 inap
= &(*inap
)->ia_next
;
850 * Delete the interface from the ifnet list.
852 for (ifpp
= &ifnet
; (*ifpp
) != 0; ) {
855 ifpp
= &(*ifpp
)->if_next
;
858 printf("couldn't find interface ppp%d in ifnet list\n", ifp
->if_unit
);
860 *ifpp
= ifp
->if_next
;