xref: /csrg-svn/sys/netinet/raw_ip.c (revision 54716)
123186Smckusick /*
237322Skarels  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
332787Sbostic  * All rights reserved.
423186Smckusick  *
544482Sbostic  * %sccs.include.redist.c%
632787Sbostic  *
7*54716Ssklower  *	@(#)raw_ip.c	7.9 (Berkeley) 07/06/92
823186Smckusick  */
95123Swnj 
1017062Sbloom #include "param.h"
1137322Skarels #include "malloc.h"
1217062Sbloom #include "mbuf.h"
1317062Sbloom #include "socket.h"
1417062Sbloom #include "protosw.h"
1517062Sbloom #include "socketvar.h"
1617062Sbloom #include "errno.h"
17*54716Ssklower #include "systm.h"
1810894Ssam 
196509Ssam #include "../net/if.h"
2013455Ssam #include "../net/route.h"
2110894Ssam 
2217062Sbloom #include "in.h"
2317062Sbloom #include "in_systm.h"
2417062Sbloom #include "ip.h"
2517062Sbloom #include "ip_var.h"
26*54716Ssklower #include "ip_mroute.h"
2737322Skarels #include "in_pcb.h"
285123Swnj 
29*54716Ssklower struct inpcb rawinpcb;
30*54716Ssklower 
315123Swnj /*
32*54716Ssklower  * Nominal space allocated to a raw ip socket.
33*54716Ssklower  */
34*54716Ssklower #define	RIPSNDQ		8192
35*54716Ssklower #define	RIPRCVQ		8192
36*54716Ssklower 
37*54716Ssklower /*
385612Swnj  * Raw interface to IP protocol.
395123Swnj  */
405612Swnj 
41*54716Ssklower /*
42*54716Ssklower  * Initialize raw connection block q.
43*54716Ssklower  */
44*54716Ssklower rip_init()
45*54716Ssklower {
46*54716Ssklower 
47*54716Ssklower 	rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb;
48*54716Ssklower }
49*54716Ssklower 
5037322Skarels struct	sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
515612Swnj /*
525612Swnj  * Setup generic address and protocol structures
535612Swnj  * for raw_input routine, then pass them along with
545612Swnj  * mbuf chain.
555612Swnj  */
565123Swnj rip_input(m)
575123Swnj 	struct mbuf *m;
585123Swnj {
595612Swnj 	register struct ip *ip = mtod(m, struct ip *);
60*54716Ssklower 	register struct inpcb *inp;
61*54716Ssklower 	struct socket *last = 0;
625123Swnj 
635646Ssam 	ripsrc.sin_addr = ip->ip_src;
64*54716Ssklower 	for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) {
65*54716Ssklower 		if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
66*54716Ssklower 			continue;
67*54716Ssklower 		if (inp->inp_laddr.s_addr &&
68*54716Ssklower 		    inp->inp_laddr.s_addr == ip->ip_dst.s_addr)
69*54716Ssklower 			continue;
70*54716Ssklower 		if (inp->inp_faddr.s_addr &&
71*54716Ssklower 		    inp->inp_faddr.s_addr == ip->ip_src.s_addr)
72*54716Ssklower 			continue;
73*54716Ssklower 		if (last) {
74*54716Ssklower 			struct mbuf *n;
75*54716Ssklower 			if (n = m_copy(m, 0, (int)M_COPYALL)) {
76*54716Ssklower 				if (sbappendaddr(&last->so_rcv, &ripsrc,
77*54716Ssklower 				    n, (struct mbuf *)0) == 0)
78*54716Ssklower 					/* should notify about lost packet */
79*54716Ssklower 					m_freem(n);
80*54716Ssklower 				else
81*54716Ssklower 					sorwakeup(last);
82*54716Ssklower 			}
83*54716Ssklower 		}
84*54716Ssklower 		last = inp->inp_socket;
85*54716Ssklower 	}
86*54716Ssklower 	if (last) {
87*54716Ssklower 		if (sbappendaddr(&last->so_rcv, &ripsrc,
88*54716Ssklower 		    m, (struct mbuf *)0) == 0)
89*54716Ssklower 			m_freem(m);
90*54716Ssklower 		else
91*54716Ssklower 			sorwakeup(last);
92*54716Ssklower 	} else {
93*54716Ssklower 		m_freem(m);
9439184Ssklower 		ipstat.ips_noproto++;
9539184Ssklower 		ipstat.ips_delivered--;
9639184Ssklower 	}
975123Swnj }
985123Swnj 
995612Swnj /*
1005612Swnj  * Generate IP header and pass packet to ip_output.
1015612Swnj  * Tack on options user may have setup with control call.
1025612Swnj  */
103*54716Ssklower rip_output(m, so, dst)
10437322Skarels 	register struct mbuf *m;
1055612Swnj 	struct socket *so;
106*54716Ssklower 	u_long dst;
1075123Swnj {
1085612Swnj 	register struct ip *ip;
109*54716Ssklower 	register struct inpcb *inp = sotoinpcb(so);
11037322Skarels 	register struct sockaddr_in *sin;
1115123Swnj 
1125612Swnj 	/*
11337322Skarels 	 * If the user handed us a complete IP packet, use it.
11437322Skarels 	 * Otherwise, allocate an mbuf for a header and fill it in.
1155612Swnj 	 */
116*54716Ssklower 	if ((inp->inp_flags & INP_HDRINCL) == 0) {
11737322Skarels 		M_PREPEND(m, sizeof(struct ip), M_WAIT);
11837322Skarels 		ip = mtod(m, struct ip *);
11937322Skarels 		ip->ip_tos = 0;
12037322Skarels 		ip->ip_off = 0;
121*54716Ssklower 		ip->ip_p = inp->inp_ip.ip_p;
12237322Skarels 		ip->ip_len = m->m_pkthdr.len;
123*54716Ssklower 		ip->ip_src = inp->inp_laddr;
124*54716Ssklower 		ip->ip_dst.s_addr = dst;
12537322Skarels 		ip->ip_ttl = MAXTTL;
1265612Swnj 	}
12737322Skarels 	return (ip_output(m,
128*54716Ssklower 	   (inp->inp_flags & INP_HDRINCL)? (struct mbuf *)0: inp->inp_options,
129*54716Ssklower 	    &inp->inp_route,
130*54716Ssklower 	   (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST
131*54716Ssklower #ifdef MULTICAST
132*54716Ssklower 	   , inp->inp_moptions
133*54716Ssklower #endif
134*54716Ssklower 	   ));
1355123Swnj }
13626037Skarels 
13726037Skarels /*
13826037Skarels  * Raw IP socket option processing.
13926037Skarels  */
14026037Skarels rip_ctloutput(op, so, level, optname, m)
14126037Skarels 	int op;
14226037Skarels 	struct socket *so;
14326037Skarels 	int level, optname;
14426037Skarels 	struct mbuf **m;
14526037Skarels {
146*54716Ssklower 	register struct inpcb *inp = sotoinpcb(so);
147*54716Ssklower 	register int error;
14826037Skarels 
14926037Skarels 	if (level != IPPROTO_IP)
150*54716Ssklower 		return (EINVAL);
15126037Skarels 
152*54716Ssklower 	switch (optname) {
15337322Skarels 
154*54716Ssklower 	case IP_HDRINCL:
155*54716Ssklower 		if (op == PRCO_SETOPT || op == PRCO_GETOPT) {
156*54716Ssklower 			if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int))
157*54716Ssklower 				return (EINVAL);
158*54716Ssklower 			if (op == PRCO_SETOPT) {
159*54716Ssklower 				if (*mtod(*m, int *))
160*54716Ssklower 					inp->inp_flags |= INP_HDRINCL;
161*54716Ssklower 				else
162*54716Ssklower 					inp->inp_flags &= ~INP_HDRINCL;
163*54716Ssklower 				(void)m_free(*m);
164*54716Ssklower 			} else {
165*54716Ssklower 				(*m)->m_len = sizeof (int);
166*54716Ssklower 				*mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
16737322Skarels 			}
168*54716Ssklower 			return (0);
16926037Skarels 		}
17026037Skarels 		break;
17126037Skarels 
172*54716Ssklower 	case DVMRP_INIT:
173*54716Ssklower 	case DVMRP_DONE:
174*54716Ssklower 	case DVMRP_ADD_VIF:
175*54716Ssklower 	case DVMRP_DEL_VIF:
176*54716Ssklower 	case DVMRP_ADD_LGRP:
177*54716Ssklower 	case DVMRP_DEL_LGRP:
178*54716Ssklower 	case DVMRP_ADD_MRT:
179*54716Ssklower 	case DVMRP_DEL_MRT:
180*54716Ssklower #ifdef MROUTING
181*54716Ssklower 		if (op == PRCO_SETOPT) {
182*54716Ssklower 			error = ip_mrouter_cmd(optname, so, *m);
183*54716Ssklower 			if (*m)
184*54716Ssklower 				(void)m_free(*m);
185*54716Ssklower 		} else
18626037Skarels 			error = EINVAL;
187*54716Ssklower 		return (error);
188*54716Ssklower #else
189*54716Ssklower 		if (op == PRCO_SETOPT && *m)
190*54716Ssklower 			(void)m_free(*m);
191*54716Ssklower 		return (EOPNOTSUPP);
192*54716Ssklower #endif
19326037Skarels 	}
194*54716Ssklower 	return (ip_ctloutput(op, so, level, optname, m));
19526037Skarels }
19637322Skarels 
197*54716Ssklower u_long	rip_sendspace = RIPSNDQ;
198*54716Ssklower u_long	rip_recvspace = RIPRCVQ;
199*54716Ssklower 
20037322Skarels /*ARGSUSED*/
201*54716Ssklower rip_usrreq(so, req, m, nam, control)
20237322Skarels 	register struct socket *so;
20337322Skarels 	int req;
204*54716Ssklower 	struct mbuf *m, *nam, *control;
20537322Skarels {
20637322Skarels 	register int error = 0;
207*54716Ssklower 	register struct inpcb *inp = sotoinpcb(so);
208*54716Ssklower #if defined(MULTICAST) && defined(MROUTING)
209*54716Ssklower 	extern struct socket *ip_mrouter;
210*54716Ssklower #endif
21137322Skarels 
21237322Skarels 	switch (req) {
21337322Skarels 
21437322Skarels 	case PRU_ATTACH:
215*54716Ssklower 		if (inp)
21637322Skarels 			panic("rip_attach");
217*54716Ssklower 		if ((so->so_state & SS_PRIV) == 0) {
218*54716Ssklower 			error = EACCES;
219*54716Ssklower 			break;
220*54716Ssklower 		}
221*54716Ssklower 		if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
222*54716Ssklower 		    (error = in_pcballoc(so, &rawinpcb)))
223*54716Ssklower 			break;
224*54716Ssklower 		inp = (struct inpcb *)so->so_pcb;
225*54716Ssklower 		inp->inp_ip.ip_p = (int)nam;
22637322Skarels 		break;
22737322Skarels 
228*54716Ssklower 	case PRU_DISCONNECT:
229*54716Ssklower 		if ((so->so_state & SS_ISCONNECTED) == 0) {
230*54716Ssklower 			error = ENOTCONN;
231*54716Ssklower 			break;
232*54716Ssklower 		}
233*54716Ssklower 		/* FALLTHROUGH */
234*54716Ssklower 	case PRU_ABORT:
235*54716Ssklower 		soisdisconnected(so);
236*54716Ssklower 		/* FALLTHROUGH */
23737322Skarels 	case PRU_DETACH:
238*54716Ssklower 		if (inp == 0)
23937322Skarels 			panic("rip_detach");
240*54716Ssklower #if defined(MULTICAST) && defined(MROUTING)
241*54716Ssklower 		if (so == ip_mrouter)
242*54716Ssklower 			ip_mrouter_done();
243*54716Ssklower #endif
244*54716Ssklower 		in_pcbdetach(inp);
24537322Skarels 		break;
24637322Skarels 
24737322Skarels 	case PRU_BIND:
24837322Skarels 	    {
24937322Skarels 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
25037322Skarels 
251*54716Ssklower 		if (nam->m_len != sizeof(*addr)) {
252*54716Ssklower 			error = EINVAL;
253*54716Ssklower 			break;
254*54716Ssklower 		}
25537322Skarels 		if ((ifnet == 0) ||
25637322Skarels 		    ((addr->sin_family != AF_INET) &&
25737322Skarels 		     (addr->sin_family != AF_IMPLINK)) ||
25837322Skarels 		    (addr->sin_addr.s_addr &&
259*54716Ssklower 		     ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
260*54716Ssklower 			error = EADDRNOTAVAIL;
261*54716Ssklower 			break;
262*54716Ssklower 		}
263*54716Ssklower 		inp->inp_laddr = addr->sin_addr;
264*54716Ssklower 		break;
26537322Skarels 	    }
26637322Skarels 	case PRU_CONNECT:
26737322Skarels 	    {
26837322Skarels 		struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
26937322Skarels 
270*54716Ssklower 		if (nam->m_len != sizeof(*addr)) {
271*54716Ssklower 			error = EINVAL;
272*54716Ssklower 			break;
273*54716Ssklower 		}
274*54716Ssklower 		if (ifnet == 0) {
275*54716Ssklower 			error = EADDRNOTAVAIL;
276*54716Ssklower 			break;
277*54716Ssklower 		}
27837322Skarels 		if ((addr->sin_family != AF_INET) &&
279*54716Ssklower 		     (addr->sin_family != AF_IMPLINK)) {
280*54716Ssklower 			error = EAFNOSUPPORT;
281*54716Ssklower 			break;
282*54716Ssklower 		}
283*54716Ssklower 		inp->inp_faddr = addr->sin_addr;
28437322Skarels 		soisconnected(so);
285*54716Ssklower 		break;
286*54716Ssklower 	    }
287*54716Ssklower 
288*54716Ssklower 	case PRU_CONNECT2:
289*54716Ssklower 		error = EOPNOTSUPP;
290*54716Ssklower 		break;
291*54716Ssklower 
292*54716Ssklower 	/*
293*54716Ssklower 	 * Mark the connection as being incapable of further input.
294*54716Ssklower 	 */
295*54716Ssklower 	case PRU_SHUTDOWN:
296*54716Ssklower 		socantsendmore(so);
297*54716Ssklower 		break;
298*54716Ssklower 
299*54716Ssklower 	/*
300*54716Ssklower 	 * Ship a packet out.  The appropriate raw output
301*54716Ssklower 	 * routine handles any massaging necessary.
302*54716Ssklower 	 */
303*54716Ssklower 	case PRU_SEND:
304*54716Ssklower 	    {
305*54716Ssklower 		register u_long dst;
306*54716Ssklower 
307*54716Ssklower 		if (so->so_state & SS_ISCONNECTED) {
308*54716Ssklower 			if (nam) {
309*54716Ssklower 				error = EISCONN;
310*54716Ssklower 				break;
311*54716Ssklower 			}
312*54716Ssklower 			dst = inp->inp_faddr.s_addr;
313*54716Ssklower 		} else {
314*54716Ssklower 			if (nam == NULL) {
315*54716Ssklower 				error = ENOTCONN;
316*54716Ssklower 				break;
317*54716Ssklower 			}
318*54716Ssklower 			dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
319*54716Ssklower 		}
320*54716Ssklower 		error = rip_output(m, so, dst);
321*54716Ssklower 		m = NULL;
322*54716Ssklower 		break;
323*54716Ssklower 	    }
324*54716Ssklower 
325*54716Ssklower 	case PRU_SENSE:
326*54716Ssklower 		/*
327*54716Ssklower 		 * stat: don't bother with a blocksize.
328*54716Ssklower 		 */
32937322Skarels 		return (0);
330*54716Ssklower 
331*54716Ssklower 	/*
332*54716Ssklower 	 * Not supported.
333*54716Ssklower 	 */
334*54716Ssklower 	case PRU_RCVOOB:
335*54716Ssklower 	case PRU_RCVD:
336*54716Ssklower 	case PRU_LISTEN:
337*54716Ssklower 	case PRU_ACCEPT:
338*54716Ssklower 	case PRU_SENDOOB:
339*54716Ssklower 		error = EOPNOTSUPP;
340*54716Ssklower 		break;
341*54716Ssklower 
342*54716Ssklower 	case PRU_SOCKADDR:
343*54716Ssklower 		in_setsockaddr(inp, nam);
344*54716Ssklower 		break;
345*54716Ssklower 
346*54716Ssklower 	case PRU_PEERADDR:
347*54716Ssklower 		in_setpeeraddr(inp, nam);
348*54716Ssklower 		break;
349*54716Ssklower 
350*54716Ssklower 	default:
351*54716Ssklower 		panic("rip_usrreq");
35237322Skarels 	}
353*54716Ssklower 	if (m != NULL)
354*54716Ssklower 		m_freem(m);
35537322Skarels 	return (error);
35637322Skarels }
357