xref: /netbsd-src/sys/netinet/raw_ip.c (revision cda4f8f6ee55684e8d311b86c99ea59191e6b74f)
1 /*
2  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	from: @(#)raw_ip.c	7.8 (Berkeley) 7/25/90
34  *	$Id: raw_ip.c,v 1.5 1993/05/22 11:42:37 cgd Exp $
35  */
36 
37 #include "param.h"
38 #include "malloc.h"
39 #include "mbuf.h"
40 #include "socket.h"
41 #include "protosw.h"
42 #include "socketvar.h"
43 #include "errno.h"
44 
45 #include "../net/if.h"
46 #include "../net/route.h"
47 #include "../net/raw_cb.h"
48 
49 #include "in.h"
50 #include "in_systm.h"
51 #include "ip.h"
52 #include "ip_var.h"
53 #include "in_pcb.h"
54 
55 /*
56  * Raw interface to IP protocol.
57  */
58 
59 struct	sockaddr_in ripdst = { sizeof(ripdst), AF_INET };
60 struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
61 struct	sockproto ripproto = { PF_INET };
62 /*
63  * Setup generic address and protocol structures
64  * for raw_input routine, then pass them along with
65  * mbuf chain.
66  */
67 rip_input(m)
68 	struct mbuf *m;
69 {
70 	register struct ip *ip = mtod(m, struct ip *);
71 
72 	ripproto.sp_protocol = ip->ip_p;
73 	ripdst.sin_addr = ip->ip_dst;
74 	ripsrc.sin_addr = ip->ip_src;
75 	if (raw_input(m, &ripproto, (struct sockaddr *)&ripsrc,
76 	  (struct sockaddr *)&ripdst) == 0) {
77 		ipstat.ips_noproto++;
78 		ipstat.ips_delivered--;
79 	}
80 }
81 
82 /*
83  * Generate IP header and pass packet to ip_output.
84  * Tack on options user may have setup with control call.
85  */
86 #define	satosin(sa)	((struct sockaddr_in *)(sa))
87 rip_output(m, so)
88 	register struct mbuf *m;
89 	struct socket *so;
90 {
91 	register struct ip *ip;
92 	register struct raw_inpcb *rp = sotorawinpcb(so);
93 	register struct sockaddr_in *sin;
94 
95 	/*
96 	 * If the user handed us a complete IP packet, use it.
97 	 * Otherwise, allocate an mbuf for a header and fill it in.
98 	 */
99 	if (rp->rinp_flags & RINPF_HDRINCL) {
100 		ip = mtod(m, struct ip *);
101 		if (ip->ip_len > m->m_pkthdr.len)
102 			return EMSGSIZE;
103 		ip->ip_len = m->m_pkthdr.len;
104 	} else {
105 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
106 		ip = mtod(m, struct ip *);
107 		ip->ip_tos = 0;
108 		ip->ip_off = 0;
109 		ip->ip_p = rp->rinp_rcb.rcb_proto.sp_protocol;
110 		ip->ip_len = m->m_pkthdr.len;
111 		if (sin = satosin(rp->rinp_rcb.rcb_laddr)) {
112 			ip->ip_src = sin->sin_addr;
113 		} else
114 			ip->ip_src.s_addr = 0;
115 		if (sin = satosin(rp->rinp_rcb.rcb_faddr))
116 		    ip->ip_dst = sin->sin_addr;
117 		ip->ip_ttl = MAXTTL;
118 	}
119 	return (ip_output(m,
120 	   (rp->rinp_flags & RINPF_HDRINCL)? (struct mbuf *)0: rp->rinp_options,
121 	    &rp->rinp_route,
122 	   (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
123 }
124 
125 /*
126  * Raw IP socket option processing.
127  */
128 rip_ctloutput(op, so, level, optname, m)
129 	int op;
130 	struct socket *so;
131 	int level, optname;
132 	struct mbuf **m;
133 {
134 	int error = 0;
135 	register struct raw_inpcb *rp = sotorawinpcb(so);
136 
137 	if (level != IPPROTO_IP)
138 		error = EINVAL;
139 	else switch (op) {
140 
141 	case PRCO_SETOPT:
142 		switch (optname) {
143 
144 		case IP_OPTIONS:
145 			return (ip_pcbopts(&rp->rinp_options, *m));
146 
147 		case IP_HDRINCL:
148 			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) {
149 				error = EINVAL;
150 				break;
151 			}
152 			if (*mtod(*m, int *))
153 				rp->rinp_flags |= RINPF_HDRINCL;
154 			else
155 				rp->rinp_flags &= ~RINPF_HDRINCL;
156 			break;
157 
158 		default:
159 			error = EINVAL;
160 			break;
161 		}
162 		break;
163 
164 	case PRCO_GETOPT:
165 		*m = m_get(M_WAIT, MT_SOOPTS);
166 		switch (optname) {
167 
168 		case IP_OPTIONS:
169 			if (rp->rinp_options) {
170 				(*m)->m_len = rp->rinp_options->m_len;
171 				bcopy(mtod(rp->rinp_options, caddr_t),
172 				    mtod(*m, caddr_t), (unsigned)(*m)->m_len);
173 			} else
174 				(*m)->m_len = 0;
175 			break;
176 
177 		case IP_HDRINCL:
178 			(*m)->m_len = sizeof (int);
179 			*mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL;
180 			break;
181 
182 		default:
183 			error = EINVAL;
184 			m_freem(*m);
185 			*m = 0;
186 			break;
187 		}
188 		break;
189 	}
190 	if (op == PRCO_SETOPT && *m)
191 		(void)m_free(*m);
192 	return (error);
193 }
194 
195 /*ARGSUSED*/
196 rip_usrreq(so, req, m, nam, control)
197 	register struct socket *so;
198 	int req;
199 	struct mbuf *m, *nam, *control;
200 {
201 	register int error = 0;
202 	register struct raw_inpcb *rp = sotorawinpcb(so);
203 
204 	switch (req) {
205 
206 	case PRU_ATTACH:
207 		if (rp)
208 			panic("rip_attach");
209 		MALLOC(rp, struct raw_inpcb *, sizeof *rp, M_PCB, M_WAITOK);
210 		if (rp == 0)
211 			return (ENOBUFS);
212 		bzero((caddr_t)rp, sizeof *rp);
213 		so->so_pcb = (caddr_t)rp;
214 		break;
215 
216 	case PRU_DETACH:
217 		if (rp == 0)
218 			panic("rip_detach");
219 		if (rp->rinp_options)
220 			m_freem(rp->rinp_options);
221 		if (rp->rinp_route.ro_rt)
222 			RTFREE(rp->rinp_route.ro_rt);
223 		if (rp->rinp_rcb.rcb_laddr)
224 			rp->rinp_rcb.rcb_laddr = 0;
225 		break;
226 
227 	case PRU_BIND:
228 	    {
229 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
230 
231 		if (nam->m_len != sizeof(*addr))
232 			return (EINVAL);
233 		if ((ifnet == 0) ||
234 		    ((addr->sin_family != AF_INET) &&
235 		     (addr->sin_family != AF_IMPLINK)) ||
236 		    (addr->sin_addr.s_addr &&
237 		     ifa_ifwithaddr((struct sockaddr *)addr) == 0))
238 			return (EADDRNOTAVAIL);
239 		rp->rinp_rcb.rcb_laddr = (struct sockaddr *)&rp->rinp_laddr;
240 		rp->rinp_laddr = *addr;
241 		return (0);
242 	    }
243 	case PRU_CONNECT:
244 	    {
245 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
246 
247 		if (nam->m_len != sizeof(*addr))
248 			return (EINVAL);
249 		if (ifnet == 0)
250 			return (EADDRNOTAVAIL);
251 		if ((addr->sin_family != AF_INET) &&
252 		     (addr->sin_family != AF_IMPLINK))
253 			return (EAFNOSUPPORT);
254 		rp->rinp_rcb.rcb_faddr = (struct sockaddr *)&rp->rinp_faddr;
255 		rp->rinp_faddr = *addr;
256 		soisconnected(so);
257 		return (0);
258 	    }
259 	}
260 	error =  raw_usrreq(so, req, m, nam, control);
261 
262 	if (error && (req == PRU_ATTACH) && so->so_pcb)
263 		free(so->so_pcb, M_PCB);
264 	return (error);
265 }
266