xref: /original-bsd/sys/netinet/raw_ip.c (revision ca3b5b26)
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 are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)raw_ip.c	7.5 (Berkeley) 04/08/89
18  */
19 
20 #include "param.h"
21 #include "malloc.h"
22 #include "mbuf.h"
23 #include "socket.h"
24 #include "protosw.h"
25 #include "socketvar.h"
26 #include "errno.h"
27 
28 #include "../net/if.h"
29 #include "../net/route.h"
30 #include "../net/raw_cb.h"
31 
32 #include "in.h"
33 #include "in_systm.h"
34 #include "ip.h"
35 #include "ip_var.h"
36 #include "in_pcb.h"
37 
38 /*
39  * Raw interface to IP protocol.
40  */
41 
42 struct	sockaddr_in ripdst = { sizeof(ripdst), AF_INET };
43 struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
44 struct	sockproto ripproto = { PF_INET };
45 /*
46  * Setup generic address and protocol structures
47  * for raw_input routine, then pass them along with
48  * mbuf chain.
49  */
50 rip_input(m)
51 	struct mbuf *m;
52 {
53 	register struct ip *ip = mtod(m, struct ip *);
54 
55 	ripproto.sp_protocol = ip->ip_p;
56 	ripdst.sin_addr = ip->ip_dst;
57 	ripsrc.sin_addr = ip->ip_src;
58 	raw_input(m, &ripproto, (struct sockaddr *)&ripsrc,
59 	  (struct sockaddr *)&ripdst);
60 }
61 
62 /*
63  * Generate IP header and pass packet to ip_output.
64  * Tack on options user may have setup with control call.
65  */
66 #define	satosin(sa)	((struct sockaddr_in *)(sa))
67 rip_output(m, so)
68 	register struct mbuf *m;
69 	struct socket *so;
70 {
71 	register struct ip *ip;
72 	register struct raw_inpcb *rp = sotorawinpcb(so);
73 	register struct sockaddr_in *sin;
74 
75 	/*
76 	 * If the user handed us a complete IP packet, use it.
77 	 * Otherwise, allocate an mbuf for a header and fill it in.
78 	 */
79 	if (rp->rinp_flags & RINPF_HDRINCL)
80 		ip = mtod(m, struct ip *);
81 	else {
82 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
83 		ip = mtod(m, struct ip *);
84 		ip->ip_tos = 0;
85 		ip->ip_off = 0;
86 		ip->ip_p = rp->rinp_rcb.rcb_proto.sp_protocol;
87 		ip->ip_len = m->m_pkthdr.len;
88 		if (sin = satosin(rp->rinp_rcb.rcb_laddr)) {
89 			ip->ip_src = sin->sin_addr;
90 		} else
91 			ip->ip_src.s_addr = 0;
92 		if (sin = satosin(rp->rinp_rcb.rcb_faddr))
93 		    ip->ip_dst = sin->sin_addr;
94 		ip->ip_ttl = MAXTTL;
95 	}
96 	return (ip_output(m,
97 	   (rp->rinp_flags & RINPF_HDRINCL)? (struct mbuf *)0: rp->rinp_options,
98 	    &rp->rinp_route,
99 	   (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
100 }
101 
102 /*
103  * Raw IP socket option processing.
104  */
105 rip_ctloutput(op, so, level, optname, m)
106 	int op;
107 	struct socket *so;
108 	int level, optname;
109 	struct mbuf **m;
110 {
111 	int error = 0;
112 	register struct raw_inpcb *rp = sotorawinpcb(so);
113 
114 	if (level != IPPROTO_IP)
115 		error = EINVAL;
116 	else switch (op) {
117 
118 	case PRCO_SETOPT:
119 		switch (optname) {
120 
121 		case IP_OPTIONS:
122 			return (ip_pcbopts(&rp->rinp_options, *m));
123 
124 		case IP_HDRINCL:
125 			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) {
126 				error = EINVAL;
127 				break;
128 			}
129 			if (*mtod(*m, int *))
130 				rp->rinp_flags |= RINPF_HDRINCL;
131 			else
132 				rp->rinp_flags &= ~RINPF_HDRINCL;
133 			break;
134 
135 		default:
136 			error = EINVAL;
137 			break;
138 		}
139 		break;
140 
141 	case PRCO_GETOPT:
142 		*m = m_get(M_WAIT, MT_SOOPTS);
143 		switch (optname) {
144 
145 		case IP_OPTIONS:
146 			if (rp->rinp_options) {
147 				(*m)->m_len = rp->rinp_options->m_len;
148 				bcopy(mtod(rp->rinp_options, caddr_t),
149 				    mtod(*m, caddr_t), (unsigned)(*m)->m_len);
150 			} else
151 				(*m)->m_len = 0;
152 			break;
153 
154 		case IP_HDRINCL:
155 			(*m)->m_len = sizeof (int);
156 			*mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL;
157 			break;
158 
159 		default:
160 			error = EINVAL;
161 			m_freem(*m);
162 			*m = 0;
163 			break;
164 		}
165 		break;
166 	}
167 	if (op == PRCO_SETOPT && *m)
168 		(void)m_free(*m);
169 	return (error);
170 }
171 
172 /*ARGSUSED*/
173 rip_usrreq(so, req, m, nam, rights, control)
174 	register struct socket *so;
175 	int req;
176 	struct mbuf *m, *nam, *rights, *control;
177 {
178 	register int error = 0;
179 	register struct raw_inpcb *rp = sotorawinpcb(so);
180 
181 	switch (req) {
182 
183 	case PRU_ATTACH:
184 		if (rp)
185 			panic("rip_attach");
186 		MALLOC(rp, struct raw_inpcb *, sizeof *rp, M_PCB, M_WAITOK);
187 		if (rp == 0)
188 			return (ENOBUFS);
189 		bzero((caddr_t)rp, sizeof *rp);
190 		so->so_pcb = (caddr_t)rp;
191 		break;
192 
193 	case PRU_DETACH:
194 		if (rp == 0)
195 			panic("rip_detach");
196 		if (rp->rinp_options)
197 			m_freem(rp->rinp_options);
198 		if (rp->rinp_route.ro_rt)
199 			RTFREE(rp->rinp_route.ro_rt);
200 		if (rp->rinp_rcb.rcb_laddr)
201 			rp->rinp_rcb.rcb_laddr = 0;
202 		break;
203 
204 	case PRU_BIND:
205 	    {
206 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
207 
208 		if (nam->m_len != sizeof(*addr))
209 			return (EINVAL);
210 		if ((ifnet == 0) ||
211 		    ((addr->sin_family != AF_INET) &&
212 		     (addr->sin_family != AF_IMPLINK)) ||
213 		    (addr->sin_addr.s_addr &&
214 		     ifa_ifwithaddr((struct sockaddr *)addr) == 0))
215 			return (EADDRNOTAVAIL);
216 		rp->rinp_rcb.rcb_laddr = (struct sockaddr *)&rp->rinp_laddr;
217 		rp->rinp_laddr = *addr;
218 		return (0);
219 	    }
220 	case PRU_CONNECT:
221 	    {
222 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
223 
224 		if (nam->m_len != sizeof(*addr))
225 			return (EINVAL);
226 		if (ifnet == 0)
227 			return (EADDRNOTAVAIL);
228 		if ((addr->sin_family != AF_INET) &&
229 		     (addr->sin_family != AF_IMPLINK))
230 			return (EAFNOSUPPORT);
231 		rp->rinp_rcb.rcb_faddr = (struct sockaddr *)&rp->rinp_faddr;
232 		rp->rinp_laddr = *addr;
233 		soisconnected(so);
234 		return (0);
235 	    }
236 	}
237 	error =  raw_usrreq(so, req, m, nam, rights, control);
238 
239 	if (error && (req == PRU_ATTACH) && so->so_pcb)
240 		free(so->so_pcb, M_PCB);
241 	return (error);
242 }
243