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*56531Sbostic * @(#)raw_ip.c 7.10 (Berkeley) 10/11/92 823186Smckusick */ 95123Swnj 10*56531Sbostic #include <sys/param.h> 11*56531Sbostic #include <sys/malloc.h> 12*56531Sbostic #include <sys/mbuf.h> 13*56531Sbostic #include <sys/socket.h> 14*56531Sbostic #include <sys/protosw.h> 15*56531Sbostic #include <sys/socketvar.h> 16*56531Sbostic #include <sys/errno.h> 17*56531Sbostic #include <sys/systm.h> 1810894Ssam 19*56531Sbostic #include <net/if.h> 20*56531Sbostic #include <net/route.h> 2110894Ssam 22*56531Sbostic #include <netinet/in.h> 23*56531Sbostic #include <netinet/in_systm.h> 24*56531Sbostic #include <netinet/ip.h> 25*56531Sbostic #include <netinet/ip_var.h> 26*56531Sbostic #include <netinet/ip_mroute.h> 27*56531Sbostic #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 */ 4454716Ssklower rip_init() 4554716Ssklower { 4654716Ssklower 4754716Ssklower rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb; 4854716Ssklower } 4954716Ssklower 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 *); 6054716Ssklower register struct inpcb *inp; 6154716Ssklower struct socket *last = 0; 625123Swnj 635646Ssam ripsrc.sin_addr = ip->ip_src; 6454716Ssklower for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) { 6554716Ssklower if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 6654716Ssklower continue; 6754716Ssklower if (inp->inp_laddr.s_addr && 6854716Ssklower inp->inp_laddr.s_addr == ip->ip_dst.s_addr) 6954716Ssklower continue; 7054716Ssklower if (inp->inp_faddr.s_addr && 7154716Ssklower inp->inp_faddr.s_addr == ip->ip_src.s_addr) 7254716Ssklower continue; 7354716Ssklower if (last) { 7454716Ssklower struct mbuf *n; 7554716Ssklower if (n = m_copy(m, 0, (int)M_COPYALL)) { 7654716Ssklower if (sbappendaddr(&last->so_rcv, &ripsrc, 7754716Ssklower n, (struct mbuf *)0) == 0) 7854716Ssklower /* should notify about lost packet */ 7954716Ssklower m_freem(n); 8054716Ssklower else 8154716Ssklower sorwakeup(last); 8254716Ssklower } 8354716Ssklower } 8454716Ssklower last = inp->inp_socket; 8554716Ssklower } 8654716Ssklower if (last) { 8754716Ssklower if (sbappendaddr(&last->so_rcv, &ripsrc, 8854716Ssklower m, (struct mbuf *)0) == 0) 8954716Ssklower m_freem(m); 9054716Ssklower else 9154716Ssklower sorwakeup(last); 9254716Ssklower } else { 9354716Ssklower 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 */ 10354716Ssklower rip_output(m, so, dst) 10437322Skarels register struct mbuf *m; 1055612Swnj struct socket *so; 10654716Ssklower u_long dst; 1075123Swnj { 1085612Swnj register struct ip *ip; 10954716Ssklower 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 */ 11654716Ssklower 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; 12154716Ssklower ip->ip_p = inp->inp_ip.ip_p; 12237322Skarels ip->ip_len = m->m_pkthdr.len; 12354716Ssklower ip->ip_src = inp->inp_laddr; 12454716Ssklower ip->ip_dst.s_addr = dst; 12537322Skarels ip->ip_ttl = MAXTTL; 1265612Swnj } 12737322Skarels return (ip_output(m, 12854716Ssklower (inp->inp_flags & INP_HDRINCL)? (struct mbuf *)0: inp->inp_options, 12954716Ssklower &inp->inp_route, 13054716Ssklower (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST 13154716Ssklower #ifdef MULTICAST 13254716Ssklower , inp->inp_moptions 13354716Ssklower #endif 13454716Ssklower )); 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 { 14654716Ssklower register struct inpcb *inp = sotoinpcb(so); 14754716Ssklower register int error; 14826037Skarels 14926037Skarels if (level != IPPROTO_IP) 15054716Ssklower return (EINVAL); 15126037Skarels 15254716Ssklower switch (optname) { 15337322Skarels 15454716Ssklower case IP_HDRINCL: 15554716Ssklower if (op == PRCO_SETOPT || op == PRCO_GETOPT) { 15654716Ssklower if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 15754716Ssklower return (EINVAL); 15854716Ssklower if (op == PRCO_SETOPT) { 15954716Ssklower if (*mtod(*m, int *)) 16054716Ssklower inp->inp_flags |= INP_HDRINCL; 16154716Ssklower else 16254716Ssklower inp->inp_flags &= ~INP_HDRINCL; 16354716Ssklower (void)m_free(*m); 16454716Ssklower } else { 16554716Ssklower (*m)->m_len = sizeof (int); 16654716Ssklower *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 16737322Skarels } 16854716Ssklower return (0); 16926037Skarels } 17026037Skarels break; 17126037Skarels 17254716Ssklower case DVMRP_INIT: 17354716Ssklower case DVMRP_DONE: 17454716Ssklower case DVMRP_ADD_VIF: 17554716Ssklower case DVMRP_DEL_VIF: 17654716Ssklower case DVMRP_ADD_LGRP: 17754716Ssklower case DVMRP_DEL_LGRP: 17854716Ssklower case DVMRP_ADD_MRT: 17954716Ssklower case DVMRP_DEL_MRT: 18054716Ssklower #ifdef MROUTING 18154716Ssklower if (op == PRCO_SETOPT) { 18254716Ssklower error = ip_mrouter_cmd(optname, so, *m); 18354716Ssklower if (*m) 18454716Ssklower (void)m_free(*m); 18554716Ssklower } else 18626037Skarels error = EINVAL; 18754716Ssklower return (error); 18854716Ssklower #else 18954716Ssklower if (op == PRCO_SETOPT && *m) 19054716Ssklower (void)m_free(*m); 19154716Ssklower return (EOPNOTSUPP); 19254716Ssklower #endif 19326037Skarels } 19454716Ssklower return (ip_ctloutput(op, so, level, optname, m)); 19526037Skarels } 19637322Skarels 19754716Ssklower u_long rip_sendspace = RIPSNDQ; 19854716Ssklower u_long rip_recvspace = RIPRCVQ; 19954716Ssklower 20037322Skarels /*ARGSUSED*/ 20154716Ssklower rip_usrreq(so, req, m, nam, control) 20237322Skarels register struct socket *so; 20337322Skarels int req; 20454716Ssklower struct mbuf *m, *nam, *control; 20537322Skarels { 20637322Skarels register int error = 0; 20754716Ssklower register struct inpcb *inp = sotoinpcb(so); 20854716Ssklower #if defined(MULTICAST) && defined(MROUTING) 20954716Ssklower extern struct socket *ip_mrouter; 21054716Ssklower #endif 21137322Skarels 21237322Skarels switch (req) { 21337322Skarels 21437322Skarels case PRU_ATTACH: 21554716Ssklower if (inp) 21637322Skarels panic("rip_attach"); 21754716Ssklower if ((so->so_state & SS_PRIV) == 0) { 21854716Ssklower error = EACCES; 21954716Ssklower break; 22054716Ssklower } 22154716Ssklower if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 22254716Ssklower (error = in_pcballoc(so, &rawinpcb))) 22354716Ssklower break; 22454716Ssklower inp = (struct inpcb *)so->so_pcb; 22554716Ssklower inp->inp_ip.ip_p = (int)nam; 22637322Skarels break; 22737322Skarels 22854716Ssklower case PRU_DISCONNECT: 22954716Ssklower if ((so->so_state & SS_ISCONNECTED) == 0) { 23054716Ssklower error = ENOTCONN; 23154716Ssklower break; 23254716Ssklower } 23354716Ssklower /* FALLTHROUGH */ 23454716Ssklower case PRU_ABORT: 23554716Ssklower soisdisconnected(so); 23654716Ssklower /* FALLTHROUGH */ 23737322Skarels case PRU_DETACH: 23854716Ssklower if (inp == 0) 23937322Skarels panic("rip_detach"); 24054716Ssklower #if defined(MULTICAST) && defined(MROUTING) 24154716Ssklower if (so == ip_mrouter) 24254716Ssklower ip_mrouter_done(); 24354716Ssklower #endif 24454716Ssklower in_pcbdetach(inp); 24537322Skarels break; 24637322Skarels 24737322Skarels case PRU_BIND: 24837322Skarels { 24937322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 25037322Skarels 25154716Ssklower if (nam->m_len != sizeof(*addr)) { 25254716Ssklower error = EINVAL; 25354716Ssklower break; 25454716Ssklower } 25537322Skarels if ((ifnet == 0) || 25637322Skarels ((addr->sin_family != AF_INET) && 25737322Skarels (addr->sin_family != AF_IMPLINK)) || 25837322Skarels (addr->sin_addr.s_addr && 25954716Ssklower ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 26054716Ssklower error = EADDRNOTAVAIL; 26154716Ssklower break; 26254716Ssklower } 26354716Ssklower inp->inp_laddr = addr->sin_addr; 26454716Ssklower break; 26537322Skarels } 26637322Skarels case PRU_CONNECT: 26737322Skarels { 26837322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 26937322Skarels 27054716Ssklower if (nam->m_len != sizeof(*addr)) { 27154716Ssklower error = EINVAL; 27254716Ssklower break; 27354716Ssklower } 27454716Ssklower if (ifnet == 0) { 27554716Ssklower error = EADDRNOTAVAIL; 27654716Ssklower break; 27754716Ssklower } 27837322Skarels if ((addr->sin_family != AF_INET) && 27954716Ssklower (addr->sin_family != AF_IMPLINK)) { 28054716Ssklower error = EAFNOSUPPORT; 28154716Ssklower break; 28254716Ssklower } 28354716Ssklower inp->inp_faddr = addr->sin_addr; 28437322Skarels soisconnected(so); 28554716Ssklower break; 28654716Ssklower } 28754716Ssklower 28854716Ssklower case PRU_CONNECT2: 28954716Ssklower error = EOPNOTSUPP; 29054716Ssklower break; 29154716Ssklower 29254716Ssklower /* 29354716Ssklower * Mark the connection as being incapable of further input. 29454716Ssklower */ 29554716Ssklower case PRU_SHUTDOWN: 29654716Ssklower socantsendmore(so); 29754716Ssklower break; 29854716Ssklower 29954716Ssklower /* 30054716Ssklower * Ship a packet out. The appropriate raw output 30154716Ssklower * routine handles any massaging necessary. 30254716Ssklower */ 30354716Ssklower case PRU_SEND: 30454716Ssklower { 30554716Ssklower register u_long dst; 30654716Ssklower 30754716Ssklower if (so->so_state & SS_ISCONNECTED) { 30854716Ssklower if (nam) { 30954716Ssklower error = EISCONN; 31054716Ssklower break; 31154716Ssklower } 31254716Ssklower dst = inp->inp_faddr.s_addr; 31354716Ssklower } else { 31454716Ssklower if (nam == NULL) { 31554716Ssklower error = ENOTCONN; 31654716Ssklower break; 31754716Ssklower } 31854716Ssklower dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 31954716Ssklower } 32054716Ssklower error = rip_output(m, so, dst); 32154716Ssklower m = NULL; 32254716Ssklower break; 32354716Ssklower } 32454716Ssklower 32554716Ssklower case PRU_SENSE: 32654716Ssklower /* 32754716Ssklower * stat: don't bother with a blocksize. 32854716Ssklower */ 32937322Skarels return (0); 33054716Ssklower 33154716Ssklower /* 33254716Ssklower * Not supported. 33354716Ssklower */ 33454716Ssklower case PRU_RCVOOB: 33554716Ssklower case PRU_RCVD: 33654716Ssklower case PRU_LISTEN: 33754716Ssklower case PRU_ACCEPT: 33854716Ssklower case PRU_SENDOOB: 33954716Ssklower error = EOPNOTSUPP; 34054716Ssklower break; 34154716Ssklower 34254716Ssklower case PRU_SOCKADDR: 34354716Ssklower in_setsockaddr(inp, nam); 34454716Ssklower break; 34554716Ssklower 34654716Ssklower case PRU_PEERADDR: 34754716Ssklower in_setpeeraddr(inp, nam); 34854716Ssklower break; 34954716Ssklower 35054716Ssklower default: 35154716Ssklower panic("rip_usrreq"); 35237322Skarels } 35354716Ssklower if (m != NULL) 35454716Ssklower m_freem(m); 35537322Skarels return (error); 35637322Skarels } 357