xref: /csrg-svn/sys/netinet/raw_ip.c (revision 39184)
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.6 (Berkeley) 09/20/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 	if (raw_input(m, &ripproto, (struct sockaddr *)&ripsrc,
59 	  (struct sockaddr *)&ripdst) == 0) {
60 		ipstat.ips_noproto++;
61 		ipstat.ips_delivered--;
62 	}
63 }
64 
65 /*
66  * Generate IP header and pass packet to ip_output.
67  * Tack on options user may have setup with control call.
68  */
69 #define	satosin(sa)	((struct sockaddr_in *)(sa))
70 rip_output(m, so)
71 	register struct mbuf *m;
72 	struct socket *so;
73 {
74 	register struct ip *ip;
75 	register struct raw_inpcb *rp = sotorawinpcb(so);
76 	register struct sockaddr_in *sin;
77 
78 	/*
79 	 * If the user handed us a complete IP packet, use it.
80 	 * Otherwise, allocate an mbuf for a header and fill it in.
81 	 */
82 	if (rp->rinp_flags & RINPF_HDRINCL)
83 		ip = mtod(m, struct ip *);
84 	else {
85 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
86 		ip = mtod(m, struct ip *);
87 		ip->ip_tos = 0;
88 		ip->ip_off = 0;
89 		ip->ip_p = rp->rinp_rcb.rcb_proto.sp_protocol;
90 		ip->ip_len = m->m_pkthdr.len;
91 		if (sin = satosin(rp->rinp_rcb.rcb_laddr)) {
92 			ip->ip_src = sin->sin_addr;
93 		} else
94 			ip->ip_src.s_addr = 0;
95 		if (sin = satosin(rp->rinp_rcb.rcb_faddr))
96 		    ip->ip_dst = sin->sin_addr;
97 		ip->ip_ttl = MAXTTL;
98 	}
99 	return (ip_output(m,
100 	   (rp->rinp_flags & RINPF_HDRINCL)? (struct mbuf *)0: rp->rinp_options,
101 	    &rp->rinp_route,
102 	   (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
103 }
104 
105 /*
106  * Raw IP socket option processing.
107  */
108 rip_ctloutput(op, so, level, optname, m)
109 	int op;
110 	struct socket *so;
111 	int level, optname;
112 	struct mbuf **m;
113 {
114 	int error = 0;
115 	register struct raw_inpcb *rp = sotorawinpcb(so);
116 
117 	if (level != IPPROTO_IP)
118 		error = EINVAL;
119 	else switch (op) {
120 
121 	case PRCO_SETOPT:
122 		switch (optname) {
123 
124 		case IP_OPTIONS:
125 			return (ip_pcbopts(&rp->rinp_options, *m));
126 
127 		case IP_HDRINCL:
128 			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) {
129 				error = EINVAL;
130 				break;
131 			}
132 			if (*mtod(*m, int *))
133 				rp->rinp_flags |= RINPF_HDRINCL;
134 			else
135 				rp->rinp_flags &= ~RINPF_HDRINCL;
136 			break;
137 
138 		default:
139 			error = EINVAL;
140 			break;
141 		}
142 		break;
143 
144 	case PRCO_GETOPT:
145 		*m = m_get(M_WAIT, MT_SOOPTS);
146 		switch (optname) {
147 
148 		case IP_OPTIONS:
149 			if (rp->rinp_options) {
150 				(*m)->m_len = rp->rinp_options->m_len;
151 				bcopy(mtod(rp->rinp_options, caddr_t),
152 				    mtod(*m, caddr_t), (unsigned)(*m)->m_len);
153 			} else
154 				(*m)->m_len = 0;
155 			break;
156 
157 		case IP_HDRINCL:
158 			(*m)->m_len = sizeof (int);
159 			*mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL;
160 			break;
161 
162 		default:
163 			error = EINVAL;
164 			m_freem(*m);
165 			*m = 0;
166 			break;
167 		}
168 		break;
169 	}
170 	if (op == PRCO_SETOPT && *m)
171 		(void)m_free(*m);
172 	return (error);
173 }
174 
175 /*ARGSUSED*/
176 rip_usrreq(so, req, m, nam, rights, control)
177 	register struct socket *so;
178 	int req;
179 	struct mbuf *m, *nam, *rights, *control;
180 {
181 	register int error = 0;
182 	register struct raw_inpcb *rp = sotorawinpcb(so);
183 
184 	switch (req) {
185 
186 	case PRU_ATTACH:
187 		if (rp)
188 			panic("rip_attach");
189 		MALLOC(rp, struct raw_inpcb *, sizeof *rp, M_PCB, M_WAITOK);
190 		if (rp == 0)
191 			return (ENOBUFS);
192 		bzero((caddr_t)rp, sizeof *rp);
193 		so->so_pcb = (caddr_t)rp;
194 		break;
195 
196 	case PRU_DETACH:
197 		if (rp == 0)
198 			panic("rip_detach");
199 		if (rp->rinp_options)
200 			m_freem(rp->rinp_options);
201 		if (rp->rinp_route.ro_rt)
202 			RTFREE(rp->rinp_route.ro_rt);
203 		if (rp->rinp_rcb.rcb_laddr)
204 			rp->rinp_rcb.rcb_laddr = 0;
205 		break;
206 
207 	case PRU_BIND:
208 	    {
209 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
210 
211 		if (nam->m_len != sizeof(*addr))
212 			return (EINVAL);
213 		if ((ifnet == 0) ||
214 		    ((addr->sin_family != AF_INET) &&
215 		     (addr->sin_family != AF_IMPLINK)) ||
216 		    (addr->sin_addr.s_addr &&
217 		     ifa_ifwithaddr((struct sockaddr *)addr) == 0))
218 			return (EADDRNOTAVAIL);
219 		rp->rinp_rcb.rcb_laddr = (struct sockaddr *)&rp->rinp_laddr;
220 		rp->rinp_laddr = *addr;
221 		return (0);
222 	    }
223 	case PRU_CONNECT:
224 	    {
225 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
226 
227 		if (nam->m_len != sizeof(*addr))
228 			return (EINVAL);
229 		if (ifnet == 0)
230 			return (EADDRNOTAVAIL);
231 		if ((addr->sin_family != AF_INET) &&
232 		     (addr->sin_family != AF_IMPLINK))
233 			return (EAFNOSUPPORT);
234 		rp->rinp_rcb.rcb_faddr = (struct sockaddr *)&rp->rinp_faddr;
235 		rp->rinp_laddr = *addr;
236 		soisconnected(so);
237 		return (0);
238 	    }
239 	}
240 	error =  raw_usrreq(so, req, m, nam, rights, control);
241 
242 	if (error && (req == PRU_ATTACH) && so->so_pcb)
243 		free(so->so_pcb, M_PCB);
244 	return (error);
245 }
246