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
loopattach(n)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
looutput(ifp,m,dst,rt)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 *)⁡
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
lortrequest(cmd,rt,sa)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
loioctl(ifp,cmd,data)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