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*69149Smckusick * @(#)raw_ip.c 8.6 (Berkeley) 05/01/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 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 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 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 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) { 158*69149Smckusick if (op == PRCO_SETOPT && *m) 159*69149Smckusick (void) m_free(*m); 16054716Ssklower return (EINVAL); 16168185Smckusick } 16226037Skarels 16354716Ssklower switch (optname) { 16437322Skarels 16554716Ssklower case IP_HDRINCL: 166*69149Smckusick error = 0; 167*69149Smckusick if (op == PRCO_SETOPT) { 168*69149Smckusick if (*m == 0 || (*m)->m_len < sizeof (int)) 169*69149Smckusick error = EINVAL; 170*69149Smckusick else if (*mtod(*m, int *)) 171*69149Smckusick inp->inp_flags |= INP_HDRINCL; 172*69149Smckusick else 173*69149Smckusick inp->inp_flags &= ~INP_HDRINCL; 174*69149Smckusick if (*m) 17554716Ssklower (void)m_free(*m); 176*69149Smckusick } else { 177*69149Smckusick *m = m_get(M_WAIT, MT_SOOPTS); 178*69149Smckusick (*m)->m_len = sizeof (int); 179*69149Smckusick *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 18026037Skarels } 181*69149Smckusick 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 204*69149Smckusick 205*69149Smckusick default: 206*69149Smckusick if (optname >= DVMRP_INIT) { 207*69149Smckusick if (op == PRCO_SETOPT) { 208*69149Smckusick error = ip_mrouter_cmd(optname, so, *m); 209*69149Smckusick if (*m) 210*69149Smckusick (void)m_free(*m); 211*69149Smckusick } else 212*69149Smckusick error = EINVAL; 213*69149Smckusick return (error); 214*69149Smckusick } 215*69149Smckusick 21626037Skarels } 21754716Ssklower return (ip_ctloutput(op, so, level, optname, m)); 21826037Skarels } 21937322Skarels 22054716Ssklower u_long rip_sendspace = RIPSNDQ; 22154716Ssklower u_long rip_recvspace = RIPRCVQ; 22254716Ssklower 22337322Skarels /*ARGSUSED*/ 22461335Sbostic int 22554716Ssklower rip_usrreq(so, req, m, nam, control) 22637322Skarels register struct socket *so; 22737322Skarels int req; 22854716Ssklower struct mbuf *m, *nam, *control; 22937322Skarels { 23037322Skarels register int error = 0; 23154716Ssklower register struct inpcb *inp = sotoinpcb(so); 23257433Sandrew #ifdef MROUTING 23354716Ssklower extern struct socket *ip_mrouter; 23454716Ssklower #endif 23537322Skarels switch (req) { 23637322Skarels 23737322Skarels case PRU_ATTACH: 23854716Ssklower if (inp) 23937322Skarels panic("rip_attach"); 24054716Ssklower if ((so->so_state & SS_PRIV) == 0) { 24154716Ssklower error = EACCES; 24254716Ssklower break; 24354716Ssklower } 24454716Ssklower if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 24554716Ssklower (error = in_pcballoc(so, &rawinpcb))) 24654716Ssklower break; 24754716Ssklower inp = (struct inpcb *)so->so_pcb; 24854716Ssklower inp->inp_ip.ip_p = (int)nam; 24937322Skarels break; 25037322Skarels 25154716Ssklower case PRU_DISCONNECT: 25254716Ssklower if ((so->so_state & SS_ISCONNECTED) == 0) { 25354716Ssklower error = ENOTCONN; 25454716Ssklower break; 25554716Ssklower } 25654716Ssklower /* FALLTHROUGH */ 25754716Ssklower case PRU_ABORT: 25854716Ssklower soisdisconnected(so); 25954716Ssklower /* FALLTHROUGH */ 26037322Skarels case PRU_DETACH: 26154716Ssklower if (inp == 0) 26237322Skarels panic("rip_detach"); 26357433Sandrew #ifdef MROUTING 26454716Ssklower if (so == ip_mrouter) 26554716Ssklower ip_mrouter_done(); 26654716Ssklower #endif 26754716Ssklower in_pcbdetach(inp); 26837322Skarels break; 26937322Skarels 27037322Skarels case PRU_BIND: 27137322Skarels { 27237322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 27337322Skarels 27454716Ssklower if (nam->m_len != sizeof(*addr)) { 27554716Ssklower error = EINVAL; 27654716Ssklower break; 27754716Ssklower } 27837322Skarels if ((ifnet == 0) || 27937322Skarels ((addr->sin_family != AF_INET) && 28037322Skarels (addr->sin_family != AF_IMPLINK)) || 28137322Skarels (addr->sin_addr.s_addr && 28254716Ssklower ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 28354716Ssklower error = EADDRNOTAVAIL; 28454716Ssklower break; 28554716Ssklower } 28654716Ssklower inp->inp_laddr = addr->sin_addr; 28754716Ssklower break; 28837322Skarels } 28937322Skarels case PRU_CONNECT: 29037322Skarels { 29137322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 29237322Skarels 29354716Ssklower if (nam->m_len != sizeof(*addr)) { 29454716Ssklower error = EINVAL; 29554716Ssklower break; 29654716Ssklower } 29754716Ssklower if (ifnet == 0) { 29854716Ssklower error = EADDRNOTAVAIL; 29954716Ssklower break; 30054716Ssklower } 30137322Skarels if ((addr->sin_family != AF_INET) && 30254716Ssklower (addr->sin_family != AF_IMPLINK)) { 30354716Ssklower error = EAFNOSUPPORT; 30454716Ssklower break; 30554716Ssklower } 30654716Ssklower inp->inp_faddr = addr->sin_addr; 30737322Skarels soisconnected(so); 30854716Ssklower break; 30954716Ssklower } 31054716Ssklower 31154716Ssklower case PRU_CONNECT2: 31254716Ssklower error = EOPNOTSUPP; 31354716Ssklower break; 31454716Ssklower 31554716Ssklower /* 31654716Ssklower * Mark the connection as being incapable of further input. 31754716Ssklower */ 31854716Ssklower case PRU_SHUTDOWN: 31954716Ssklower socantsendmore(so); 32054716Ssklower break; 32154716Ssklower 32254716Ssklower /* 32354716Ssklower * Ship a packet out. The appropriate raw output 32454716Ssklower * routine handles any massaging necessary. 32554716Ssklower */ 32654716Ssklower case PRU_SEND: 32754716Ssklower { 32854716Ssklower register u_long dst; 32954716Ssklower 33054716Ssklower if (so->so_state & SS_ISCONNECTED) { 33154716Ssklower if (nam) { 33254716Ssklower error = EISCONN; 33354716Ssklower break; 33454716Ssklower } 33554716Ssklower dst = inp->inp_faddr.s_addr; 33654716Ssklower } else { 33754716Ssklower if (nam == NULL) { 33854716Ssklower error = ENOTCONN; 33954716Ssklower break; 34054716Ssklower } 34154716Ssklower dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 34254716Ssklower } 34354716Ssklower error = rip_output(m, so, dst); 34454716Ssklower m = NULL; 34554716Ssklower break; 34654716Ssklower } 34754716Ssklower 34854716Ssklower case PRU_SENSE: 34954716Ssklower /* 35054716Ssklower * stat: don't bother with a blocksize. 35154716Ssklower */ 35237322Skarels return (0); 35354716Ssklower 35454716Ssklower /* 35554716Ssklower * Not supported. 35654716Ssklower */ 35754716Ssklower case PRU_RCVOOB: 35854716Ssklower case PRU_RCVD: 35954716Ssklower case PRU_LISTEN: 36054716Ssklower case PRU_ACCEPT: 36154716Ssklower case PRU_SENDOOB: 36254716Ssklower error = EOPNOTSUPP; 36354716Ssklower break; 36454716Ssklower 36554716Ssklower case PRU_SOCKADDR: 36654716Ssklower in_setsockaddr(inp, nam); 36754716Ssklower break; 36854716Ssklower 36954716Ssklower case PRU_PEERADDR: 37054716Ssklower in_setpeeraddr(inp, nam); 37154716Ssklower break; 37254716Ssklower 37354716Ssklower default: 37454716Ssklower panic("rip_usrreq"); 37537322Skarels } 37654716Ssklower if (m != NULL) 37754716Ssklower m_freem(m); 37837322Skarels return (error); 37937322Skarels } 380