xref: /original-bsd/sys/net/if_loop.c (revision fac0c393)
1 /*
2  * Copyright (c) 1982, 1986, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if_loop.c	8.2 (Berkeley) 01/09/95
8  */
9 
10 /*
11  * Loopback interface driver for protocol testing and timing.
12  */
13 
14 #include <sys/param.h>
15 #include <sys/systm.h>
16 #include <sys/kernel.h>
17 #include <sys/mbuf.h>
18 #include <sys/socket.h>
19 #include <sys/errno.h>
20 #include <sys/ioctl.h>
21 #include <sys/time.h>
22 #include <machine/cpu.h>
23 
24 #include <net/if.h>
25 #include <net/if_types.h>
26 #include <net/netisr.h>
27 #include <net/route.h>
28 #include <net/bpf.h>
29 
30 #ifdef	INET
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
33 #include <netinet/in_var.h>
34 #include <netinet/ip.h>
35 #endif
36 
37 #ifdef NS
38 #include <netns/ns.h>
39 #include <netns/ns_if.h>
40 #endif
41 
42 #ifdef ISO
43 #include <netiso/iso.h>
44 #include <netiso/iso_var.h>
45 #endif
46 
47 #include "bpfilter.h"
48 
49 #define	LOMTU	(1024+512)
50 
51 struct	ifnet loif;
52 
53 /* ARGSUSED */
54 void
55 loopattach(n)
56 	int n;
57 {
58 	register struct ifnet *ifp = &loif;
59 
60 #ifdef lint
61 	n = n;			/* Highlander: there can only be one... */
62 #endif
63 	ifp->if_name = "lo";
64 	ifp->if_mtu = LOMTU;
65 	ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST;
66 	ifp->if_ioctl = loioctl;
67 	ifp->if_output = looutput;
68 	ifp->if_type = IFT_LOOP;
69 	ifp->if_hdrlen = 0;
70 	ifp->if_addrlen = 0;
71 	if_attach(ifp);
72 #if NBPFILTER > 0
73 	bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
74 #endif
75 }
76 
77 int
78 looutput(ifp, m, dst, rt)
79 	struct ifnet *ifp;
80 	register struct mbuf *m;
81 	struct sockaddr *dst;
82 	register struct rtentry *rt;
83 {
84 	int s, isr;
85 	register struct ifqueue *ifq = 0;
86 
87 	if ((m->m_flags & M_PKTHDR) == 0)
88 		panic("looutput no HDR");
89 	ifp->if_lastchange = time;
90 #if NBPFILTER > 0
91 	if (loif.if_bpf) {
92 		/*
93 		 * We need to prepend the address family as
94 		 * a four byte field.  Cons up a dummy header
95 		 * to pacify bpf.  This is safe because bpf
96 		 * will only read from the mbuf (i.e., it won't
97 		 * try to free it or keep a pointer a to it).
98 		 */
99 		struct mbuf m0;
100 		u_int af = dst->sa_family;
101 
102 		m0.m_next = m;
103 		m0.m_len = 4;
104 		m0.m_data = (char *)&af;
105 
106 		bpf_mtap(loif.if_bpf, &m0);
107 	}
108 #endif
109 	m->m_pkthdr.rcvif = ifp;
110 
111 	if (rt && rt->rt_flags & (RTF_REJECT|RTF_BLACKHOLE)) {
112 		m_freem(m);
113 		return (rt->rt_flags & RTF_BLACKHOLE ? 0 :
114 		        rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
115 	}
116 	ifp->if_opackets++;
117 	ifp->if_obytes += m->m_pkthdr.len;
118 	switch (dst->sa_family) {
119 
120 #ifdef INET
121 	case AF_INET:
122 		ifq = &ipintrq;
123 		isr = NETISR_IP;
124 		break;
125 #endif
126 #ifdef NS
127 	case AF_NS:
128 		ifq = &nsintrq;
129 		isr = NETISR_NS;
130 		break;
131 #endif
132 #ifdef ISO
133 	case AF_ISO:
134 		ifq = &clnlintrq;
135 		isr = NETISR_ISO;
136 		break;
137 #endif
138 	default:
139 		printf("lo%d: can't handle af%d\n", ifp->if_unit,
140 			dst->sa_family);
141 		m_freem(m);
142 		return (EAFNOSUPPORT);
143 	}
144 	s = splimp();
145 	if (IF_QFULL(ifq)) {
146 		IF_DROP(ifq);
147 		m_freem(m);
148 		splx(s);
149 		return (ENOBUFS);
150 	}
151 	IF_ENQUEUE(ifq, m);
152 	schednetisr(isr);
153 	ifp->if_ipackets++;
154 	ifp->if_ibytes += m->m_pkthdr.len;
155 	splx(s);
156 	return (0);
157 }
158 
159 /* ARGSUSED */
160 void
161 lortrequest(cmd, rt, sa)
162 	int cmd;
163 	struct rtentry *rt;
164 	struct sockaddr *sa;
165 {
166 
167 	if (rt)
168 		rt->rt_rmx.rmx_mtu = LOMTU;
169 }
170 
171 /*
172  * Process an ioctl request.
173  */
174 /* ARGSUSED */
175 int
176 loioctl(ifp, cmd, data)
177 	register struct ifnet *ifp;
178 	u_long cmd;
179 	caddr_t data;
180 {
181 	register struct ifaddr *ifa;
182 	register struct ifreq *ifr;
183 	register int error = 0;
184 
185 	switch (cmd) {
186 
187 	case SIOCSIFADDR:
188 		ifp->if_flags |= IFF_UP;
189 		ifa = (struct ifaddr *)data;
190 		if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO)
191 			ifa->ifa_rtrequest = lortrequest;
192 		/*
193 		 * Everything else is done at a higher level.
194 		 */
195 		break;
196 
197 	case SIOCADDMULTI:
198 	case SIOCDELMULTI:
199 		ifr = (struct ifreq *)data;
200 		if (ifr == 0) {
201 			error = EAFNOSUPPORT;		/* XXX */
202 			break;
203 		}
204 		switch (ifr->ifr_addr.sa_family) {
205 
206 #ifdef INET
207 		case AF_INET:
208 			break;
209 #endif
210 
211 		default:
212 			error = EAFNOSUPPORT;
213 			break;
214 		}
215 		break;
216 
217 	default:
218 		error = EINVAL;
219 	}
220 	return (error);
221 }
222