123186Smckusick /*
263218Sbostic * Copyright (c) 1982, 1986, 1988, 1993
363218Sbostic * The Regents of the University of California. All rights reserved.
423186Smckusick *
544482Sbostic * %sccs.include.redist.c%
632787Sbostic *
7*69479Smckusick * @(#)raw_ip.c 8.7 (Berkeley) 05/15/95
823186Smckusick */
95123Swnj
1056531Sbostic #include <sys/param.h>
1156531Sbostic #include <sys/malloc.h>
1256531Sbostic #include <sys/mbuf.h>
1356531Sbostic #include <sys/socket.h>
1456531Sbostic #include <sys/protosw.h>
1556531Sbostic #include <sys/socketvar.h>
1656531Sbostic #include <sys/errno.h>
1756531Sbostic #include <sys/systm.h>
1810894Ssam
1956531Sbostic #include <net/if.h>
2056531Sbostic #include <net/route.h>
2110894Ssam
2256531Sbostic #include <netinet/in.h>
2356531Sbostic #include <netinet/in_systm.h>
2456531Sbostic #include <netinet/ip.h>
2556531Sbostic #include <netinet/ip_var.h>
2656531Sbostic #include <netinet/ip_mroute.h>
2756531Sbostic #include <netinet/in_pcb.h>
285123Swnj
2954716Ssklower struct inpcb rawinpcb;
3054716Ssklower
315123Swnj /*
3254716Ssklower * Nominal space allocated to a raw ip socket.
3354716Ssklower */
3454716Ssklower #define RIPSNDQ 8192
3554716Ssklower #define RIPRCVQ 8192
3654716Ssklower
3754716Ssklower /*
385612Swnj * Raw interface to IP protocol.
395123Swnj */
405612Swnj
4154716Ssklower /*
4254716Ssklower * Initialize raw connection block q.
4354716Ssklower */
4461335Sbostic void
rip_init()4554716Ssklower rip_init()
4654716Ssklower {
4754716Ssklower
4854716Ssklower rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb;
4954716Ssklower }
5054716Ssklower
5137322Skarels struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET };
525612Swnj /*
535612Swnj * Setup generic address and protocol structures
545612Swnj * for raw_input routine, then pass them along with
555612Swnj * mbuf chain.
565612Swnj */
5761335Sbostic void
rip_input(m)585123Swnj rip_input(m)
595123Swnj struct mbuf *m;
605123Swnj {
615612Swnj register struct ip *ip = mtod(m, struct ip *);
6254716Ssklower register struct inpcb *inp;
6354716Ssklower struct socket *last = 0;
645123Swnj
655646Ssam ripsrc.sin_addr = ip->ip_src;
6654716Ssklower for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) {
6754716Ssklower if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p)
6854716Ssklower continue;
6954716Ssklower if (inp->inp_laddr.s_addr &&
7068263Smckusick inp->inp_laddr.s_addr != ip->ip_dst.s_addr)
7154716Ssklower continue;
7254716Ssklower if (inp->inp_faddr.s_addr &&
7368263Smckusick inp->inp_faddr.s_addr != ip->ip_src.s_addr)
7454716Ssklower continue;
7554716Ssklower if (last) {
7654716Ssklower struct mbuf *n;
7754716Ssklower if (n = m_copy(m, 0, (int)M_COPYALL)) {
7868255Scgd if (sbappendaddr(&last->so_rcv,
7968255Scgd (struct sockaddr *)&ripsrc, n,
8068255Scgd (struct mbuf *)0) == 0)
8154716Ssklower /* should notify about lost packet */
8254716Ssklower m_freem(n);
8354716Ssklower else
8454716Ssklower sorwakeup(last);
8554716Ssklower }
8654716Ssklower }
8754716Ssklower last = inp->inp_socket;
8854716Ssklower }
8954716Ssklower if (last) {
9068255Scgd if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc,
9154716Ssklower m, (struct mbuf *)0) == 0)
9254716Ssklower m_freem(m);
9354716Ssklower else
9454716Ssklower sorwakeup(last);
9554716Ssklower } else {
9654716Ssklower m_freem(m);
9739184Ssklower ipstat.ips_noproto++;
9839184Ssklower ipstat.ips_delivered--;
9939184Ssklower }
1005123Swnj }
1015123Swnj
1025612Swnj /*
1035612Swnj * Generate IP header and pass packet to ip_output.
1045612Swnj * Tack on options user may have setup with control call.
1055612Swnj */
10661335Sbostic int
rip_output(m,so,dst)10754716Ssklower rip_output(m, so, dst)
10837322Skarels register struct mbuf *m;
1095612Swnj struct socket *so;
11054716Ssklower u_long dst;
1115123Swnj {
1125612Swnj register struct ip *ip;
11354716Ssklower register struct inpcb *inp = sotoinpcb(so);
11457969Sandrew struct mbuf *opts;
11557969Sandrew int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST;
1165123Swnj
1175612Swnj /*
11837322Skarels * If the user handed us a complete IP packet, use it.
11937322Skarels * Otherwise, allocate an mbuf for a header and fill it in.
1205612Swnj */
12154716Ssklower if ((inp->inp_flags & INP_HDRINCL) == 0) {
12237322Skarels M_PREPEND(m, sizeof(struct ip), M_WAIT);
12337322Skarels ip = mtod(m, struct ip *);
12437322Skarels ip->ip_tos = 0;
12537322Skarels ip->ip_off = 0;
12654716Ssklower ip->ip_p = inp->inp_ip.ip_p;
12737322Skarels ip->ip_len = m->m_pkthdr.len;
12854716Ssklower ip->ip_src = inp->inp_laddr;
12954716Ssklower ip->ip_dst.s_addr = dst;
13037322Skarels ip->ip_ttl = MAXTTL;
13157969Sandrew opts = inp->inp_options;
13257969Sandrew } else {
13359019Sandrew ip = mtod(m, struct ip *);
13459019Sandrew if (ip->ip_id == 0)
13559019Sandrew ip->ip_id = htons(ip_id++);
13657969Sandrew opts = NULL;
13757969Sandrew /* XXX prevent ip_output from overwriting header fields */
13857969Sandrew flags |= IP_RAWOUTPUT;
13957969Sandrew ipstat.ips_rawout++;
1405612Swnj }
14157969Sandrew return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions));
1425123Swnj }
14326037Skarels
14426037Skarels /*
14526037Skarels * Raw IP socket option processing.
14626037Skarels */
14761335Sbostic int
rip_ctloutput(op,so,level,optname,m)14826037Skarels rip_ctloutput(op, so, level, optname, m)
14926037Skarels int op;
15026037Skarels struct socket *so;
15126037Skarels int level, optname;
15226037Skarels struct mbuf **m;
15326037Skarels {
15454716Ssklower register struct inpcb *inp = sotoinpcb(so);
15554716Ssklower register int error;
15626037Skarels
15768185Smckusick if (level != IPPROTO_IP) {
15869149Smckusick if (op == PRCO_SETOPT && *m)
15969149Smckusick (void) m_free(*m);
16054716Ssklower return (EINVAL);
16168185Smckusick }
16226037Skarels
16354716Ssklower switch (optname) {
16437322Skarels
16554716Ssklower case IP_HDRINCL:
16669149Smckusick error = 0;
16769149Smckusick if (op == PRCO_SETOPT) {
16869149Smckusick if (*m == 0 || (*m)->m_len < sizeof (int))
16969149Smckusick error = EINVAL;
17069149Smckusick else if (*mtod(*m, int *))
17169149Smckusick inp->inp_flags |= INP_HDRINCL;
17269149Smckusick else
17369149Smckusick inp->inp_flags &= ~INP_HDRINCL;
17469149Smckusick if (*m)
17554716Ssklower (void)m_free(*m);
17669149Smckusick } else {
17769149Smckusick *m = m_get(M_WAIT, MT_SOOPTS);
17869149Smckusick (*m)->m_len = sizeof (int);
17969149Smckusick *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL;
18026037Skarels }
18169149Smckusick return (error);
18226037Skarels
18354716Ssklower case DVMRP_INIT:
18454716Ssklower case DVMRP_DONE:
18554716Ssklower case DVMRP_ADD_VIF:
18654716Ssklower case DVMRP_DEL_VIF:
18754716Ssklower case DVMRP_ADD_LGRP:
18854716Ssklower case DVMRP_DEL_LGRP:
18954716Ssklower case DVMRP_ADD_MRT:
19054716Ssklower case DVMRP_DEL_MRT:
19154716Ssklower #ifdef MROUTING
19254716Ssklower if (op == PRCO_SETOPT) {
19354716Ssklower error = ip_mrouter_cmd(optname, so, *m);
19454716Ssklower if (*m)
19554716Ssklower (void)m_free(*m);
19654716Ssklower } else
19726037Skarels error = EINVAL;
19854716Ssklower return (error);
19954716Ssklower #else
20054716Ssklower if (op == PRCO_SETOPT && *m)
20154716Ssklower (void)m_free(*m);
20254716Ssklower return (EOPNOTSUPP);
20354716Ssklower #endif
20469149Smckusick
20569149Smckusick default:
20669149Smckusick if (optname >= DVMRP_INIT) {
207*69479Smckusick #ifdef MROUTING
20869149Smckusick if (op == PRCO_SETOPT) {
20969149Smckusick error = ip_mrouter_cmd(optname, so, *m);
21069149Smckusick if (*m)
21169149Smckusick (void)m_free(*m);
21269149Smckusick } else
21369149Smckusick error = EINVAL;
21469149Smckusick return (error);
215*69479Smckusick #else
216*69479Smckusick if (op == PRCO_SETOPT && *m)
217*69479Smckusick (void)m_free(*m);
218*69479Smckusick return (EOPNOTSUPP);
219*69479Smckusick #endif
22069149Smckusick }
22169149Smckusick
22226037Skarels }
22354716Ssklower return (ip_ctloutput(op, so, level, optname, m));
22426037Skarels }
22537322Skarels
22654716Ssklower u_long rip_sendspace = RIPSNDQ;
22754716Ssklower u_long rip_recvspace = RIPRCVQ;
22854716Ssklower
22937322Skarels /*ARGSUSED*/
23061335Sbostic int
rip_usrreq(so,req,m,nam,control)23154716Ssklower rip_usrreq(so, req, m, nam, control)
23237322Skarels register struct socket *so;
23337322Skarels int req;
23454716Ssklower struct mbuf *m, *nam, *control;
23537322Skarels {
23637322Skarels register int error = 0;
23754716Ssklower register struct inpcb *inp = sotoinpcb(so);
23857433Sandrew #ifdef MROUTING
23954716Ssklower extern struct socket *ip_mrouter;
24054716Ssklower #endif
24137322Skarels switch (req) {
24237322Skarels
24337322Skarels case PRU_ATTACH:
24454716Ssklower if (inp)
24537322Skarels panic("rip_attach");
24654716Ssklower if ((so->so_state & SS_PRIV) == 0) {
24754716Ssklower error = EACCES;
24854716Ssklower break;
24954716Ssklower }
25054716Ssklower if ((error = soreserve(so, rip_sendspace, rip_recvspace)) ||
25154716Ssklower (error = in_pcballoc(so, &rawinpcb)))
25254716Ssklower break;
25354716Ssklower inp = (struct inpcb *)so->so_pcb;
25454716Ssklower inp->inp_ip.ip_p = (int)nam;
25537322Skarels break;
25637322Skarels
25754716Ssklower case PRU_DISCONNECT:
25854716Ssklower if ((so->so_state & SS_ISCONNECTED) == 0) {
25954716Ssklower error = ENOTCONN;
26054716Ssklower break;
26154716Ssklower }
26254716Ssklower /* FALLTHROUGH */
26354716Ssklower case PRU_ABORT:
26454716Ssklower soisdisconnected(so);
26554716Ssklower /* FALLTHROUGH */
26637322Skarels case PRU_DETACH:
26754716Ssklower if (inp == 0)
26837322Skarels panic("rip_detach");
26957433Sandrew #ifdef MROUTING
27054716Ssklower if (so == ip_mrouter)
27154716Ssklower ip_mrouter_done();
27254716Ssklower #endif
27354716Ssklower in_pcbdetach(inp);
27437322Skarels break;
27537322Skarels
27637322Skarels case PRU_BIND:
27737322Skarels {
27837322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
27937322Skarels
28054716Ssklower if (nam->m_len != sizeof(*addr)) {
28154716Ssklower error = EINVAL;
28254716Ssklower break;
28354716Ssklower }
28437322Skarels if ((ifnet == 0) ||
28537322Skarels ((addr->sin_family != AF_INET) &&
28637322Skarels (addr->sin_family != AF_IMPLINK)) ||
28737322Skarels (addr->sin_addr.s_addr &&
28854716Ssklower ifa_ifwithaddr((struct sockaddr *)addr) == 0)) {
28954716Ssklower error = EADDRNOTAVAIL;
29054716Ssklower break;
29154716Ssklower }
29254716Ssklower inp->inp_laddr = addr->sin_addr;
29354716Ssklower break;
29437322Skarels }
29537322Skarels case PRU_CONNECT:
29637322Skarels {
29737322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
29837322Skarels
29954716Ssklower if (nam->m_len != sizeof(*addr)) {
30054716Ssklower error = EINVAL;
30154716Ssklower break;
30254716Ssklower }
30354716Ssklower if (ifnet == 0) {
30454716Ssklower error = EADDRNOTAVAIL;
30554716Ssklower break;
30654716Ssklower }
30737322Skarels if ((addr->sin_family != AF_INET) &&
30854716Ssklower (addr->sin_family != AF_IMPLINK)) {
30954716Ssklower error = EAFNOSUPPORT;
31054716Ssklower break;
31154716Ssklower }
31254716Ssklower inp->inp_faddr = addr->sin_addr;
31337322Skarels soisconnected(so);
31454716Ssklower break;
31554716Ssklower }
31654716Ssklower
31754716Ssklower case PRU_CONNECT2:
31854716Ssklower error = EOPNOTSUPP;
31954716Ssklower break;
32054716Ssklower
32154716Ssklower /*
32254716Ssklower * Mark the connection as being incapable of further input.
32354716Ssklower */
32454716Ssklower case PRU_SHUTDOWN:
32554716Ssklower socantsendmore(so);
32654716Ssklower break;
32754716Ssklower
32854716Ssklower /*
32954716Ssklower * Ship a packet out. The appropriate raw output
33054716Ssklower * routine handles any massaging necessary.
33154716Ssklower */
33254716Ssklower case PRU_SEND:
33354716Ssklower {
33454716Ssklower register u_long dst;
33554716Ssklower
33654716Ssklower if (so->so_state & SS_ISCONNECTED) {
33754716Ssklower if (nam) {
33854716Ssklower error = EISCONN;
33954716Ssklower break;
34054716Ssklower }
34154716Ssklower dst = inp->inp_faddr.s_addr;
34254716Ssklower } else {
34354716Ssklower if (nam == NULL) {
34454716Ssklower error = ENOTCONN;
34554716Ssklower break;
34654716Ssklower }
34754716Ssklower dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
34854716Ssklower }
34954716Ssklower error = rip_output(m, so, dst);
35054716Ssklower m = NULL;
35154716Ssklower break;
35254716Ssklower }
35354716Ssklower
35454716Ssklower case PRU_SENSE:
35554716Ssklower /*
35654716Ssklower * stat: don't bother with a blocksize.
35754716Ssklower */
35837322Skarels return (0);
35954716Ssklower
36054716Ssklower /*
36154716Ssklower * Not supported.
36254716Ssklower */
36354716Ssklower case PRU_RCVOOB:
36454716Ssklower case PRU_RCVD:
36554716Ssklower case PRU_LISTEN:
36654716Ssklower case PRU_ACCEPT:
36754716Ssklower case PRU_SENDOOB:
36854716Ssklower error = EOPNOTSUPP;
36954716Ssklower break;
37054716Ssklower
37154716Ssklower case PRU_SOCKADDR:
37254716Ssklower in_setsockaddr(inp, nam);
37354716Ssklower break;
37454716Ssklower
37554716Ssklower case PRU_PEERADDR:
37654716Ssklower in_setpeeraddr(inp, nam);
37754716Ssklower break;
37854716Ssklower
37954716Ssklower default:
38054716Ssklower panic("rip_usrreq");
38137322Skarels }
38254716Ssklower if (m != NULL)
38354716Ssklower m_freem(m);
38437322Skarels return (error);
38537322Skarels }
386