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