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