Commit | Line | Data |
---|---|---|
8ae0e4b4 | 1 | /* |
1e881221 | 2 | * Copyright (c) 1982, 1986, 1988 Regents of the University of California. |
2b6b6284 | 3 | * All rights reserved. |
8ae0e4b4 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
2b6b6284 | 6 | * |
17a0384b | 7 | * @(#)raw_ip.c 7.12 (Berkeley) %G% |
8ae0e4b4 | 8 | */ |
2a598b25 | 9 | |
5548a02f KB |
10 | #include <sys/param.h> |
11 | #include <sys/malloc.h> | |
12 | #include <sys/mbuf.h> | |
13 | #include <sys/socket.h> | |
14 | #include <sys/protosw.h> | |
15 | #include <sys/socketvar.h> | |
16 | #include <sys/errno.h> | |
17 | #include <sys/systm.h> | |
18 | ||
19 | #include <net/if.h> | |
20 | #include <net/route.h> | |
21 | ||
22 | #include <netinet/in.h> | |
23 | #include <netinet/in_systm.h> | |
24 | #include <netinet/ip.h> | |
25 | #include <netinet/ip_var.h> | |
26 | #include <netinet/ip_mroute.h> | |
27 | #include <netinet/in_pcb.h> | |
2a598b25 | 28 | |
d6fa15c2 KS |
29 | struct inpcb rawinpcb; |
30 | ||
31 | /* | |
32 | * Nominal space allocated to a raw ip socket. | |
33 | */ | |
34 | #define RIPSNDQ 8192 | |
35 | #define RIPRCVQ 8192 | |
36 | ||
2a598b25 | 37 | /* |
94a62155 BJ |
38 | * Raw interface to IP protocol. |
39 | */ | |
40 | ||
d6fa15c2 KS |
41 | /* |
42 | * Initialize raw connection block q. | |
43 | */ | |
44 | rip_init() | |
45 | { | |
46 | ||
47 | rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb; | |
48 | } | |
49 | ||
1e881221 | 50 | struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; |
94a62155 BJ |
51 | /* |
52 | * Setup generic address and protocol structures | |
53 | * for raw_input routine, then pass them along with | |
54 | * mbuf chain. | |
2a598b25 | 55 | */ |
2a598b25 BJ |
56 | rip_input(m) |
57 | struct mbuf *m; | |
58 | { | |
94a62155 | 59 | register struct ip *ip = mtod(m, struct ip *); |
d6fa15c2 KS |
60 | register struct inpcb *inp; |
61 | struct socket *last = 0; | |
2a598b25 | 62 | |
faad37c0 | 63 | ripsrc.sin_addr = ip->ip_src; |
d6fa15c2 KS |
64 | for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) { |
65 | if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) | |
66 | continue; | |
67 | if (inp->inp_laddr.s_addr && | |
68 | inp->inp_laddr.s_addr == ip->ip_dst.s_addr) | |
69 | continue; | |
70 | if (inp->inp_faddr.s_addr && | |
71 | inp->inp_faddr.s_addr == ip->ip_src.s_addr) | |
72 | continue; | |
73 | if (last) { | |
74 | struct mbuf *n; | |
75 | if (n = m_copy(m, 0, (int)M_COPYALL)) { | |
76 | if (sbappendaddr(&last->so_rcv, &ripsrc, | |
77 | n, (struct mbuf *)0) == 0) | |
78 | /* should notify about lost packet */ | |
79 | m_freem(n); | |
80 | else | |
81 | sorwakeup(last); | |
82 | } | |
83 | } | |
84 | last = inp->inp_socket; | |
85 | } | |
86 | if (last) { | |
87 | if (sbappendaddr(&last->so_rcv, &ripsrc, | |
88 | m, (struct mbuf *)0) == 0) | |
89 | m_freem(m); | |
90 | else | |
91 | sorwakeup(last); | |
92 | } else { | |
93 | m_freem(m); | |
978e3cbe KS |
94 | ipstat.ips_noproto++; |
95 | ipstat.ips_delivered--; | |
96 | } | |
2a598b25 BJ |
97 | } |
98 | ||
94a62155 BJ |
99 | /* |
100 | * Generate IP header and pass packet to ip_output. | |
101 | * Tack on options user may have setup with control call. | |
102 | */ | |
d6fa15c2 | 103 | rip_output(m, so, dst) |
1e881221 | 104 | register struct mbuf *m; |
94a62155 | 105 | struct socket *so; |
d6fa15c2 | 106 | u_long dst; |
2a598b25 | 107 | { |
94a62155 | 108 | register struct ip *ip; |
d6fa15c2 | 109 | register struct inpcb *inp = sotoinpcb(so); |
1e881221 | 110 | register struct sockaddr_in *sin; |
a9522c7f AC |
111 | struct mbuf *opts; |
112 | int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; | |
2a598b25 | 113 | |
94a62155 | 114 | /* |
1e881221 MK |
115 | * If the user handed us a complete IP packet, use it. |
116 | * Otherwise, allocate an mbuf for a header and fill it in. | |
94a62155 | 117 | */ |
d6fa15c2 | 118 | if ((inp->inp_flags & INP_HDRINCL) == 0) { |
1e881221 MK |
119 | M_PREPEND(m, sizeof(struct ip), M_WAIT); |
120 | ip = mtod(m, struct ip *); | |
121 | ip->ip_tos = 0; | |
122 | ip->ip_off = 0; | |
d6fa15c2 | 123 | ip->ip_p = inp->inp_ip.ip_p; |
1e881221 | 124 | ip->ip_len = m->m_pkthdr.len; |
d6fa15c2 KS |
125 | ip->ip_src = inp->inp_laddr; |
126 | ip->ip_dst.s_addr = dst; | |
1e881221 | 127 | ip->ip_ttl = MAXTTL; |
a9522c7f AC |
128 | opts = inp->inp_options; |
129 | } else { | |
130 | opts = NULL; | |
131 | /* XXX prevent ip_output from overwriting header fields */ | |
132 | flags |= IP_RAWOUTPUT; | |
133 | ipstat.ips_rawout++; | |
94a62155 | 134 | } |
a9522c7f | 135 | return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions)); |
2a598b25 | 136 | } |
b197d52e MK |
137 | |
138 | /* | |
139 | * Raw IP socket option processing. | |
140 | */ | |
141 | rip_ctloutput(op, so, level, optname, m) | |
142 | int op; | |
143 | struct socket *so; | |
144 | int level, optname; | |
145 | struct mbuf **m; | |
146 | { | |
d6fa15c2 KS |
147 | register struct inpcb *inp = sotoinpcb(so); |
148 | register int error; | |
b197d52e MK |
149 | |
150 | if (level != IPPROTO_IP) | |
d6fa15c2 | 151 | return (EINVAL); |
1e881221 | 152 | |
d6fa15c2 | 153 | switch (optname) { |
1e881221 | 154 | |
d6fa15c2 KS |
155 | case IP_HDRINCL: |
156 | if (op == PRCO_SETOPT || op == PRCO_GETOPT) { | |
157 | if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) | |
158 | return (EINVAL); | |
159 | if (op == PRCO_SETOPT) { | |
160 | if (*mtod(*m, int *)) | |
161 | inp->inp_flags |= INP_HDRINCL; | |
162 | else | |
163 | inp->inp_flags &= ~INP_HDRINCL; | |
164 | (void)m_free(*m); | |
165 | } else { | |
166 | (*m)->m_len = sizeof (int); | |
167 | *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; | |
1e881221 | 168 | } |
d6fa15c2 | 169 | return (0); |
b197d52e MK |
170 | } |
171 | break; | |
172 | ||
d6fa15c2 KS |
173 | case DVMRP_INIT: |
174 | case DVMRP_DONE: | |
175 | case DVMRP_ADD_VIF: | |
176 | case DVMRP_DEL_VIF: | |
177 | case DVMRP_ADD_LGRP: | |
178 | case DVMRP_DEL_LGRP: | |
179 | case DVMRP_ADD_MRT: | |
180 | case DVMRP_DEL_MRT: | |
181 | #ifdef MROUTING | |
182 | if (op == PRCO_SETOPT) { | |
183 | error = ip_mrouter_cmd(optname, so, *m); | |
184 | if (*m) | |
185 | (void)m_free(*m); | |
186 | } else | |
b197d52e | 187 | error = EINVAL; |
d6fa15c2 KS |
188 | return (error); |
189 | #else | |
190 | if (op == PRCO_SETOPT && *m) | |
191 | (void)m_free(*m); | |
192 | return (EOPNOTSUPP); | |
193 | #endif | |
b197d52e | 194 | } |
d6fa15c2 | 195 | return (ip_ctloutput(op, so, level, optname, m)); |
b197d52e | 196 | } |
1e881221 | 197 | |
d6fa15c2 KS |
198 | u_long rip_sendspace = RIPSNDQ; |
199 | u_long rip_recvspace = RIPRCVQ; | |
200 | ||
1e881221 | 201 | /*ARGSUSED*/ |
d6fa15c2 | 202 | rip_usrreq(so, req, m, nam, control) |
1e881221 MK |
203 | register struct socket *so; |
204 | int req; | |
d6fa15c2 | 205 | struct mbuf *m, *nam, *control; |
1e881221 MK |
206 | { |
207 | register int error = 0; | |
d6fa15c2 | 208 | register struct inpcb *inp = sotoinpcb(so); |
69d96ae2 | 209 | #ifdef MROUTING |
d6fa15c2 KS |
210 | extern struct socket *ip_mrouter; |
211 | #endif | |
1e881221 MK |
212 | |
213 | switch (req) { | |
214 | ||
215 | case PRU_ATTACH: | |
d6fa15c2 | 216 | if (inp) |
1e881221 | 217 | panic("rip_attach"); |
d6fa15c2 KS |
218 | if ((so->so_state & SS_PRIV) == 0) { |
219 | error = EACCES; | |
220 | break; | |
221 | } | |
222 | if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || | |
223 | (error = in_pcballoc(so, &rawinpcb))) | |
224 | break; | |
225 | inp = (struct inpcb *)so->so_pcb; | |
226 | inp->inp_ip.ip_p = (int)nam; | |
1e881221 MK |
227 | break; |
228 | ||
d6fa15c2 KS |
229 | case PRU_DISCONNECT: |
230 | if ((so->so_state & SS_ISCONNECTED) == 0) { | |
231 | error = ENOTCONN; | |
232 | break; | |
233 | } | |
234 | /* FALLTHROUGH */ | |
235 | case PRU_ABORT: | |
236 | soisdisconnected(so); | |
237 | /* FALLTHROUGH */ | |
1e881221 | 238 | case PRU_DETACH: |
d6fa15c2 | 239 | if (inp == 0) |
1e881221 | 240 | panic("rip_detach"); |
69d96ae2 | 241 | #ifdef MROUTING |
d6fa15c2 KS |
242 | if (so == ip_mrouter) |
243 | ip_mrouter_done(); | |
244 | #endif | |
245 | in_pcbdetach(inp); | |
1e881221 MK |
246 | break; |
247 | ||
248 | case PRU_BIND: | |
249 | { | |
250 | struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); | |
251 | ||
d6fa15c2 KS |
252 | if (nam->m_len != sizeof(*addr)) { |
253 | error = EINVAL; | |
254 | break; | |
255 | } | |
1e881221 MK |
256 | if ((ifnet == 0) || |
257 | ((addr->sin_family != AF_INET) && | |
258 | (addr->sin_family != AF_IMPLINK)) || | |
259 | (addr->sin_addr.s_addr && | |
d6fa15c2 KS |
260 | ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { |
261 | error = EADDRNOTAVAIL; | |
262 | break; | |
263 | } | |
264 | inp->inp_laddr = addr->sin_addr; | |
265 | break; | |
1e881221 MK |
266 | } |
267 | case PRU_CONNECT: | |
268 | { | |
269 | struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); | |
270 | ||
d6fa15c2 KS |
271 | if (nam->m_len != sizeof(*addr)) { |
272 | error = EINVAL; | |
273 | break; | |
274 | } | |
275 | if (ifnet == 0) { | |
276 | error = EADDRNOTAVAIL; | |
277 | break; | |
278 | } | |
1e881221 | 279 | if ((addr->sin_family != AF_INET) && |
d6fa15c2 KS |
280 | (addr->sin_family != AF_IMPLINK)) { |
281 | error = EAFNOSUPPORT; | |
282 | break; | |
283 | } | |
284 | inp->inp_faddr = addr->sin_addr; | |
1e881221 | 285 | soisconnected(so); |
d6fa15c2 | 286 | break; |
1e881221 | 287 | } |
1e881221 | 288 | |
d6fa15c2 KS |
289 | case PRU_CONNECT2: |
290 | error = EOPNOTSUPP; | |
291 | break; | |
292 | ||
293 | /* | |
294 | * Mark the connection as being incapable of further input. | |
295 | */ | |
296 | case PRU_SHUTDOWN: | |
297 | socantsendmore(so); | |
298 | break; | |
299 | ||
300 | /* | |
301 | * Ship a packet out. The appropriate raw output | |
302 | * routine handles any massaging necessary. | |
303 | */ | |
304 | case PRU_SEND: | |
305 | { | |
306 | register u_long dst; | |
307 | ||
308 | if (so->so_state & SS_ISCONNECTED) { | |
309 | if (nam) { | |
310 | error = EISCONN; | |
311 | break; | |
312 | } | |
313 | dst = inp->inp_faddr.s_addr; | |
314 | } else { | |
315 | if (nam == NULL) { | |
316 | error = ENOTCONN; | |
317 | break; | |
318 | } | |
319 | dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; | |
320 | } | |
321 | error = rip_output(m, so, dst); | |
322 | m = NULL; | |
323 | break; | |
324 | } | |
325 | ||
326 | case PRU_SENSE: | |
327 | /* | |
328 | * stat: don't bother with a blocksize. | |
329 | */ | |
330 | return (0); | |
331 | ||
332 | /* | |
333 | * Not supported. | |
334 | */ | |
335 | case PRU_RCVOOB: | |
336 | case PRU_RCVD: | |
337 | case PRU_LISTEN: | |
338 | case PRU_ACCEPT: | |
339 | case PRU_SENDOOB: | |
340 | error = EOPNOTSUPP; | |
341 | break; | |
342 | ||
343 | case PRU_SOCKADDR: | |
344 | in_setsockaddr(inp, nam); | |
345 | break; | |
346 | ||
347 | case PRU_PEERADDR: | |
348 | in_setpeeraddr(inp, nam); | |
349 | break; | |
350 | ||
351 | default: | |
352 | panic("rip_usrreq"); | |
353 | } | |
354 | if (m != NULL) | |
355 | m_freem(m); | |
1e881221 MK |
356 | return (error); |
357 | } |