2 * if_ppp.c - a network interface connected to a STREAMS module.
4 * Copyright (c) 1994 Paul Mackerras. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
18 * 3. The name(s) of the authors of this software must not be used to
19 * endorse or promote products derived from this software without
20 * prior written permission.
22 * 4. Redistributions of any form whatsoever must retain the following
24 * "This product includes software developed by Paul Mackerras
25 * <paulus@samba.org>".
27 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
28 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
29 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
30 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
31 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
32 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
33 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 * $Id: if_ppp.c,v 1.18 2002/12/06 09:49:15 paulus Exp $
39 * This file is used under SunOS 4 and Digital UNIX.
41 * This file provides the glue between PPP and IP.
46 #include <sys/types.h>
47 #include <sys/param.h>
48 #include <sys/errno.h>
50 #include <sys/socket.h>
52 #include <net/netisr.h>
53 #include <net/ppp_defs.h>
54 #include <net/pppio.h>
55 #include <netinet/in.h>
56 #include <netinet/in_var.h>
58 #include <sys/ioctl.h>
59 #include <net/if_types.h>
61 #include <sys/sockio.h>
65 #include <sys/stream.h>
69 #include <net/nit_if.h>
70 #include <netinet/if_ether.h>
74 #define SIOCSIFMTU SIOCSIPMTU
75 #define SIOCGIFMTU SIOCRIPMTU
76 #define IFA_ADDR(ifa) (*(ifa)->ifa_addr)
78 #define IFA_ADDR(ifa) ((ifa)->ifa_addr)
81 #define ifr_mtu ifr_metric
83 static int if_ppp_open
__P((queue_t
*, int, int, int));
84 static int if_ppp_close
__P((queue_t
*, int));
85 static int if_ppp_wput
__P((queue_t
*, mblk_t
*));
86 static int if_ppp_rput
__P((queue_t
*, mblk_t
*));
88 #define PPP_IF_ID 0x8021
89 static struct module_info minfo
= {
90 PPP_IF_ID
, "if_ppp", 0, INFPSZ
, 4096, 128
93 static struct qinit rinit
= {
94 if_ppp_rput
, NULL
, if_ppp_open
, if_ppp_close
, NULL
, &minfo
, NULL
97 static struct qinit winit
= {
98 if_ppp_wput
, NULL
, NULL
, NULL
, NULL
, &minfo
, NULL
101 struct streamtab if_pppinfo
= {
102 &rinit
, &winit
, NULL
, NULL
105 typedef struct if_ppp_state
{
111 /* Values for flags */
114 static int if_ppp_count
; /* Number of currently-active streams */
116 static int ppp_nalloc
; /* Number of elements of ifs and states */
117 static struct ifnet
**ifs
; /* Array of pointers to interface structs */
118 static if_ppp_t
**states
; /* Array of pointers to state structs */
120 static int if_ppp_output
__P((struct ifnet
*, struct mbuf
*,
122 static int if_ppp_ioctl
__P((struct ifnet
*, u_int
, caddr_t
));
123 static struct mbuf
*make_mbufs
__P((mblk_t
*, int));
124 static mblk_t
*make_message
__P((struct mbuf
*, int));
127 /* Fake ether header for SNIT */
128 static struct ether_header snit_ehdr
= {{0}, {0}, ETHERTYPE_IP
};
132 static void ppp_if_detach
__P((struct ifnet
*));
135 * Detach all the interfaces before unloading.
136 * Not sure this works.
143 if (if_ppp_count
> 0)
145 for (i
= 0; i
< ppp_nalloc
; ++i
)
147 ppp_if_detach(ifs
[i
]);
149 FREE(ifs
, ppp_nalloc
* sizeof (struct ifnet
*));
150 FREE(states
, ppp_nalloc
* sizeof (struct if_ppp_t
*));
158 * STREAMS module entry points.
161 if_ppp_open(q
, dev
, flag
, sflag
)
169 sp
= (if_ppp_t
*) ALLOC_SLEEP(sizeof (if_ppp_t
));
172 bzero(sp
, sizeof (if_ppp_t
));
173 q
->q_ptr
= (caddr_t
) sp
;
174 WR(q
)->q_ptr
= (caddr_t
) sp
;
175 sp
->unit
= -1; /* no interface unit attached at present */
184 if_ppp_close(q
, flag
)
191 sp
= (if_ppp_t
*) q
->q_ptr
;
193 if (sp
->flags
& DBGLOG
)
194 printf("if_ppp closed, q=%x sp=%x\n", q
, sp
);
196 if (sp
->unit
< ppp_nalloc
) {
197 states
[sp
->unit
] = 0;
200 ifp
->if_flags
&= ~(IFF_UP
| IFF_RUNNING
);
203 printf("if_ppp: unit %d nonexistent!\n", sp
->unit
);
207 FREE(sp
, sizeof (if_ppp_t
));
223 sp
= (if_ppp_t
*) q
->q_ptr
;
224 switch (mp
->b_datap
->db_type
) {
227 * Now why would we be getting data coming in here??
229 if (sp
->flags
& DBGLOG
)
230 printf("if_ppp: got M_DATA len=%d\n", msgdsize(mp
));
235 iop
= (struct iocblk
*) mp
->b_rptr
;
238 if (sp
->flags
& DBGLOG
)
239 printf("if_ppp: got ioctl cmd=%x count=%d\n",
240 iop
->ioc_cmd
, iop
->ioc_count
);
242 switch (iop
->ioc_cmd
) {
243 case PPPIO_NEWPPA
: /* well almost */
244 if (iop
->ioc_count
!= sizeof(int) || sp
->unit
>= 0)
246 if ((error
= NOTSUSER()) != 0)
248 unit
= *(int *)mp
->b_cont
->b_rptr
;
250 /* Check that this unit isn't already in use */
251 if (unit
< ppp_nalloc
&& states
[unit
] != 0) {
256 /* Extend ifs and states arrays if necessary. */
258 if (unit
>= ppp_nalloc
) {
260 struct ifnet
**newifs
;
261 if_ppp_t
**newstates
;
264 if (sp
->flags
& DBGLOG
)
265 printf("if_ppp: extending ifs to %d\n", newn
);
266 newifs
= (struct ifnet
**)
267 ALLOC_NOSLEEP(newn
* sizeof (struct ifnet
*));
270 bzero(newifs
, newn
* sizeof (struct ifnet
*));
271 newstates
= (if_ppp_t
**)
272 ALLOC_NOSLEEP(newn
* sizeof (struct if_ppp_t
*));
273 if (newstates
== 0) {
274 FREE(newifs
, newn
* sizeof (struct ifnet
*));
277 bzero(newstates
, newn
* sizeof (struct if_ppp_t
*));
278 bcopy(ifs
, newifs
, ppp_nalloc
* sizeof(struct ifnet
*));
279 bcopy(states
, newstates
, ppp_nalloc
* sizeof(if_ppp_t
*));
281 FREE(ifs
, ppp_nalloc
* sizeof(struct ifnet
*));
282 FREE(states
, ppp_nalloc
* sizeof(if_ppp_t
*));
289 /* Allocate a new ifnet struct if necessary. */
292 ifp
= (struct ifnet
*) ALLOC_NOSLEEP(sizeof (struct ifnet
));
295 bzero(ifp
, sizeof (struct ifnet
));
297 ifp
->if_name
= "ppp";
299 ifp
->if_mtu
= PPP_MTU
;
300 ifp
->if_flags
= IFF_POINTOPOINT
| IFF_RUNNING
;
303 ifp
->if_flags
|= IFF_MULTICAST
;
306 ifp
->if_output
= if_ppp_output
;
308 ifp
->if_version
= "Point-to-Point Protocol, version 2.3.11";
309 ifp
->if_mediamtu
= PPP_MTU
;
310 ifp
->if_type
= IFT_PPP
;
311 ifp
->if_hdrlen
= PPP_HDRLEN
;
313 ifp
->if_flags
|= IFF_NOARP
| IFF_SIMPLEX
| IFF_NOTRAILERS
;
315 ifp
->if_flags
|= IFF_VAR_MTU
;
318 ifp
->if_affinity
= NETMASTERCPU
;
321 ifp
->if_ioctl
= if_ppp_ioctl
;
322 ifp
->if_snd
.ifq_maxlen
= IFQ_MAXLEN
;
324 if (sp
->flags
& DBGLOG
)
325 printf("if_ppp: created unit %d\n", unit
);
327 ifp
->if_mtu
= PPP_MTU
;
328 ifp
->if_flags
|= IFF_RUNNING
;
336 if (sp
->flags
& DBGLOG
)
337 printf("if_ppp: attached unit %d, sp=%x q=%x\n", unit
,
343 if (iop
->ioc_count
== sizeof(int)) {
344 if (*(int *)mp
->b_cont
->b_rptr
== PPPDBG_LOG
+ PPPDBG_IF
) {
345 printf("if_ppp: debug log enabled, q=%x sp=%x\n", q
, sp
);
358 if (sp
->flags
& DBGLOG
)
359 printf("if_ppp: ioctl result %d\n", error
);
362 else if (error
== 0) {
363 mp
->b_datap
->db_type
= M_IOCACK
;
366 mp
->b_datap
->db_type
= M_IOCNAK
;
368 iop
->ioc_error
= error
;
391 sp
= (if_ppp_t
*) q
->q_ptr
;
392 switch (mp
->b_datap
->db_type
) {
395 * Convert the message into an mbuf chain
396 * and inject it into the network code.
398 if (sp
->flags
& DBGLOG
)
399 printf("if_ppp: rput pkt len %d data %x %x %x %x %x %x %x %x\n",
400 msgdsize(mp
), mp
->b_rptr
[0], mp
->b_rptr
[1], mp
->b_rptr
[2],
401 mp
->b_rptr
[3], mp
->b_rptr
[4], mp
->b_rptr
[5], mp
->b_rptr
[6],
408 if (sp
->unit
>= ppp_nalloc
|| (ifp
= ifs
[sp
->unit
]) == 0) {
410 printf("if_ppp: no unit %d!\n", sp
->unit
);
416 if ((ifp
->if_flags
& IFF_UP
) == 0) {
422 proto
= PPP_PROTOCOL(mp
->b_rptr
);
423 adjmsg(mp
, PPP_HDRLEN
);
425 mb
= make_mbufs(mp
, sizeof(struct ifnet
*));
428 if (sp
->flags
& DBGLOG
)
429 printf("if_ppp%d: make_mbufs failed\n", ifp
->if_unit
);
435 if (proto
== PPP_IP
&& (ifp
->if_flags
& IFF_PROMISC
)) {
438 nif
.nif_header
= (caddr_t
) &snit_ehdr
;
439 nif
.nif_hdrlen
= sizeof(snit_ehdr
);
440 nif
.nif_bodylen
= len
;
442 snit_intr(ifp
, mb
, &nif
);
447 * For Digital UNIX, there's space set aside in the header mbuf
448 * for the interface info.
450 * For Sun it's smuggled around via a pointer at the front of the mbuf.
453 mb
->m_pkthdr
.rcvif
= ifp
;
454 mb
->m_pkthdr
.len
= len
;
456 mb
->m_off
-= sizeof(struct ifnet
*);
457 mb
->m_len
+= sizeof(struct ifnet
*);
458 *mtod(mb
, struct ifnet
**) = ifp
;
465 schednetisr(NETISR_IP
);
473 if (sp
->flags
& DBGLOG
)
474 printf("if_ppp: inq full, proto=%x\n", proto
);
481 if (sp
->flags
& DBGLOG
)
482 printf("if_ppp%d: proto=%x?\n", ifp
->if_unit
, proto
);
495 * Network code wants to output a packet.
496 * Turn it into a STREAMS message and send it down.
499 if_ppp_output(ifp
, m0
, dst
)
502 struct sockaddr
*dst
;
509 if ((ifp
->if_flags
& IFF_UP
) == 0) {
514 if ((unsigned)ifp
->if_unit
>= ppp_nalloc
) {
516 printf("if_ppp_output: unit %d?\n", ifp
->if_unit
);
521 sp
= states
[ifp
->if_unit
];
524 printf("if_ppp_output: no queue?\n");
530 if (sp
->flags
& DBGLOG
) {
531 p
= mtod(m0
, u_char
*);
532 printf("if_ppp_output%d: af=%d data=%x %x %x %x %x %x %x %x q=%x\n",
533 ifp
->if_unit
, dst
->sa_family
, p
[0], p
[1], p
[2], p
[3], p
[4],
534 p
[5], p
[6], p
[7], sp
->q
);
537 switch (dst
->sa_family
) {
541 if (ifp
->if_flags
& IFF_PROMISC
) {
546 for (len
= 0, m
= m0
; m
!= NULL
; m
= m
->m_next
)
548 nif
.nif_header
= (caddr_t
) &snit_ehdr
;
549 nif
.nif_hdrlen
= sizeof(snit_ehdr
);
550 nif
.nif_bodylen
= len
;
552 snit_intr(ifp
, m0
, &nif
);
563 mp
= make_message(m0
, PPP_HDRLEN
);
569 mp
->b_rptr
-= PPP_HDRLEN
;
570 mp
->b_rptr
[0] = PPP_ALLSTATIONS
;
571 mp
->b_rptr
[1] = PPP_UI
;
572 mp
->b_rptr
[2] = proto
>> 8;
573 mp
->b_rptr
[3] = proto
;
576 if (sp
->flags
& DBGLOG
)
577 printf("if_ppp: putnext(%x, %x), r=%x w=%x p=%x\n",
578 sp
->q
, mp
, mp
->b_rptr
, mp
->b_wptr
, proto
);
586 * Socket ioctl routine for ppp interfaces.
589 if_ppp_ioctl(ifp
, cmd
, data
)
595 struct ifreq
*ifr
= (struct ifreq
*) data
;
596 struct ifaddr
*ifa
= (struct ifaddr
*) data
;
603 if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
604 ifp
->if_flags
&= ~IFF_UP
;
608 if (IFA_ADDR(ifa
).sa_family
!= AF_INET
)
609 error
= EAFNOSUPPORT
;
613 if (IFA_ADDR(ifa
).sa_family
!= AF_INET
)
614 error
= EAFNOSUPPORT
;
618 if ((error
= NOTSUSER()) != 0)
621 /* this hack is necessary because ifioctl checks ifr_data
622 * in 4.0 and 5.0, but ifr_data and ifr_metric overlay each
623 * other in the definition of struct ifreq so pppd can't set both.
625 bcopy(ifr
->ifr_data
, &mtu
, sizeof (u_short
));
629 if (ifr
->ifr_mtu
< PPP_MINMTU
|| ifr
->ifr_mtu
> PPP_MAXMTU
) {
633 ifp
->if_mtu
= ifr
->ifr_mtu
;
637 ifr
->ifr_mtu
= ifp
->if_mtu
;
642 switch(ifr
->ifr_addr
.sa_family
) {
646 error
= EAFNOSUPPORT
;
659 * Turn a STREAMS message into an mbuf chain.
666 struct mbuf
*head
, **prevp
, *m
;
668 unsigned char *cp
, *dp
;
677 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
682 dp
= mtod(m
, unsigned char *);
687 while (cp
>= mp
->b_wptr
) {
697 MGET(m
, M_DONTWAIT
, MT_DATA
);
704 if (len
+ off
> 2 * MLEN
) {
706 MCLGET(m
, M_DONTWAIT
);
712 space
= ((m
->m_flags
& M_EXT
) ? MCLBYTES
: MLEN
);
714 space
= (m
->m_off
> MMAXOFF
? MCLBYTES
: MLEN
) - off
;
719 dp
= mtod(m
, unsigned char *);
734 * Turn an mbuf chain into a STREAMS message.
736 #define ALLOCB_MAX 4096
743 mblk_t
*head
, **prevp
, *mp
;
744 int len
, space
, n
, nb
;
745 unsigned char *cp
, *dp
;
749 for (nm
= m
; nm
!= 0; nm
= nm
->m_next
)
753 cp
= mtod(m
, unsigned char *);
762 cp
= mtod(m
, unsigned char *);
767 if (space
> ALLOCB_MAX
)
769 mp
= allocb(space
, BPRI_LO
);
776 dp
= mp
->b_rptr
+= off
;
782 n
= nb
< space
? nb
: space
;
793 * Digital UNIX doesn't allow for removing ifnet structures
794 * from the list. But then we're not using this as a loadable
795 * module anyway, so that's OK.
797 * Under SunOS, this should allow the module to be unloaded.
798 * Unfortunately, it doesn't seem to detach all the references,
799 * so your system may well crash after you unload this module :-(
804 * Remove an interface from the system.
805 * This routine contains magic.
807 #include <net/route.h>
808 #include <netinet/in_pcb.h>
809 #include <netinet/ip_var.h>
810 #include <netinet/tcp.h>
811 #include <netinet/tcp_timer.h>
812 #include <netinet/tcp_var.h>
813 #include <netinet/udp.h>
814 #include <netinet/udp_var.h>
823 struct in_ifaddr
**inap
;
829 * Clear the interface from any routes currently cached in
830 * TCP or UDP protocol control blocks.
832 for (pcb
= tcb
.inp_next
; pcb
!= &tcb
; pcb
= pcb
->inp_next
)
833 if (pcb
->inp_route
.ro_rt
&& pcb
->inp_route
.ro_rt
->rt_ifp
== ifp
)
835 for (pcb
= udb
.inp_next
; pcb
!= &udb
; pcb
= pcb
->inp_next
)
836 if (pcb
->inp_route
.ro_rt
&& pcb
->inp_route
.ro_rt
->rt_ifp
== ifp
)
840 * Delete routes through all addresses of the interface.
842 for (ifa
= ifp
->if_addrlist
; ifa
!= 0; ifa
= ifa
->ifa_next
) {
843 rtinit(ifa
, ifa
, SIOCDELRT
, RTF_HOST
);
844 rtinit(ifa
, ifa
, SIOCDELRT
, 0);
848 * Unlink the interface's address(es) from the in_ifaddr list.
850 for (inap
= &in_ifaddr
; *inap
!= 0; ) {
851 if ((*inap
)->ia_ifa
.ifa_ifp
== ifp
)
852 *inap
= (*inap
)->ia_next
;
854 inap
= &(*inap
)->ia_next
;
858 * Delete the interface from the ifnet list.
860 for (ifpp
= &ifnet
; (*ifpp
) != 0; ) {
863 ifpp
= &(*ifpp
)->if_next
;
866 printf("couldn't find interface ppp%d in ifnet list\n", ifp
->if_unit
);
868 *ifpp
= ifp
->if_next
;