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 | * |
0fe7c40f | 7 | * @(#)if_loop.c 7.19 (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 | 60 | ifp->if_flags = IFF_LOOPBACK | IFF_MULTICAST; |
639a8848 | 61 | ifp->if_ioctl = loioctl; |
0a486d2b | 62 | ifp->if_output = looutput; |
b72a6efb KS |
63 | ifp->if_type = IFT_LOOP; |
64 | ifp->if_hdrlen = 0; | |
65 | ifp->if_addrlen = 0; | |
405c9168 | 66 | if_attach(ifp); |
78cafbd4 KS |
67 | #if NBPFILTER > 0 |
68 | bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int)); | |
69 | #endif | |
0a486d2b BJ |
70 | } |
71 | ||
9c5bb641 | 72 | looutput(ifp, m, dst, rt) |
0a486d2b | 73 | struct ifnet *ifp; |
38a81509 | 74 | register struct mbuf *m; |
ee787340 | 75 | struct sockaddr *dst; |
9c5bb641 | 76 | register struct rtentry *rt; |
0a486d2b | 77 | { |
98fb6aa9 KS |
78 | int s, isr; |
79 | register struct ifqueue *ifq = 0; | |
38a81509 MK |
80 | |
81 | if ((m->m_flags & M_PKTHDR) == 0) | |
82 | panic("looutput no HDR"); | |
78cafbd4 KS |
83 | ifp->if_lastchange = time; |
84 | #if NBPFILTER > 0 | |
85 | if (loif.if_bpf) { | |
86 | /* | |
87 | * We need to prepend the address family as | |
88 | * a four byte field. Cons up a dummy header | |
89 | * to pacify bpf. This is safe because bpf | |
90 | * will only read from the mbuf (i.e., it won't | |
91 | * try to free it or keep a pointer a to it). | |
92 | */ | |
93 | struct mbuf m0; | |
94 | u_int af = dst->sa_family; | |
95 | ||
96 | m0.m_next = m; | |
97 | m0.m_len = 4; | |
98 | m0.m_data = (char *)⁡ | |
99 | ||
100 | bpf_mtap(loif.if_bpf, &m0); | |
101 | } | |
102 | #endif | |
38a81509 MK |
103 | m->m_pkthdr.rcvif = ifp; |
104 | ||
9c5bb641 KS |
105 | if (rt && rt->rt_flags & RTF_REJECT) { |
106 | m_freem(m); | |
107 | return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); | |
108 | } | |
b454c3ea | 109 | ifp->if_opackets++; |
5f08a978 | 110 | ifp->if_obytes += m->m_pkthdr.len; |
ee787340 | 111 | switch (dst->sa_family) { |
0a486d2b BJ |
112 | |
113 | #ifdef INET | |
ee787340 | 114 | case AF_INET: |
1e977657 | 115 | ifq = &ipintrq; |
98fb6aa9 | 116 | isr = NETISR_IP; |
0a486d2b | 117 | break; |
edecfd58 KS |
118 | #endif |
119 | #ifdef NS | |
120 | case AF_NS: | |
121 | ifq = &nsintrq; | |
98fb6aa9 | 122 | isr = NETISR_NS; |
edecfd58 | 123 | break; |
b72a6efb KS |
124 | #endif |
125 | #ifdef ISO | |
126 | case AF_ISO: | |
127 | ifq = &clnlintrq; | |
98fb6aa9 KS |
128 | isr = NETISR_ISO; |
129 | break; | |
0a486d2b | 130 | #endif |
0a486d2b | 131 | default: |
ee787340 SL |
132 | printf("lo%d: can't handle af%d\n", ifp->if_unit, |
133 | dst->sa_family); | |
38a81509 | 134 | m_freem(m); |
4c5902e0 | 135 | return (EAFNOSUPPORT); |
0a486d2b | 136 | } |
ee85cf85 | 137 | s = splimp(); |
98fb6aa9 KS |
138 | if (IF_QFULL(ifq)) { |
139 | IF_DROP(ifq); | |
140 | m_freem(m); | |
141 | splx(s); | |
142 | return (ENOBUFS); | |
143 | } | |
144 | IF_ENQUEUE(ifq, m); | |
145 | schednetisr(isr); | |
b454c3ea | 146 | ifp->if_ipackets++; |
5f08a978 | 147 | ifp->if_ibytes += m->m_pkthdr.len; |
0a486d2b | 148 | splx(s); |
4c5902e0 | 149 | return (0); |
0a486d2b | 150 | } |
639a8848 | 151 | |
ee85cf85 | 152 | /* ARGSUSED */ |
78cafbd4 | 153 | void |
ee85cf85 | 154 | lortrequest(cmd, rt, sa) |
64f72726 CT |
155 | int cmd; |
156 | struct rtentry *rt; | |
157 | struct sockaddr *sa; | |
ee85cf85 | 158 | { |
64f72726 | 159 | |
ee85cf85 KS |
160 | if (rt) |
161 | rt->rt_rmx.rmx_mtu = LOMTU; | |
162 | } | |
163 | ||
639a8848 SL |
164 | /* |
165 | * Process an ioctl request. | |
166 | */ | |
bba52753 | 167 | /* ARGSUSED */ |
639a8848 SL |
168 | loioctl(ifp, cmd, data) |
169 | register struct ifnet *ifp; | |
170 | int cmd; | |
171 | caddr_t data; | |
172 | { | |
ee85cf85 | 173 | register struct ifaddr *ifa; |
78cafbd4 | 174 | register struct ifreq *ifr; |
78cafbd4 | 175 | register int error = 0; |
639a8848 SL |
176 | |
177 | switch (cmd) { | |
178 | ||
179 | case SIOCSIFADDR: | |
bba52753 | 180 | ifp->if_flags |= IFF_UP; |
ee85cf85 KS |
181 | ifa = (struct ifaddr *)data; |
182 | if (ifa != 0 && ifa->ifa_addr->sa_family == AF_ISO) | |
183 | ifa->ifa_rtrequest = lortrequest; | |
bba52753 MK |
184 | /* |
185 | * Everything else is done at a higher level. | |
186 | */ | |
639a8848 SL |
187 | break; |
188 | ||
78cafbd4 KS |
189 | case SIOCADDMULTI: |
190 | case SIOCDELMULTI: | |
191 | ifr = (struct ifreq *)data; | |
192 | if (ifr == 0) { | |
193 | error = EAFNOSUPPORT; /* XXX */ | |
194 | break; | |
195 | } | |
196 | switch (ifr->ifr_addr.sa_family) { | |
197 | ||
198 | #ifdef INET | |
199 | case AF_INET: | |
200 | break; | |
201 | #endif | |
202 | ||
203 | default: | |
204 | error = EAFNOSUPPORT; | |
205 | break; | |
206 | } | |
207 | break; | |
78cafbd4 | 208 | |
639a8848 SL |
209 | default: |
210 | error = EINVAL; | |
211 | } | |
639a8848 SL |
212 | return (error); |
213 | } |