1 /* $NetBSD: raw_ip.c,v 1.14 1994/06/29 06:38:31 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 36 */ 37 38 #include <sys/param.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/socket.h> 42 #include <sys/protosw.h> 43 #include <sys/socketvar.h> 44 #include <sys/errno.h> 45 #include <sys/systm.h> 46 47 #include <net/if.h> 48 #include <net/route.h> 49 50 #include <netinet/in.h> 51 #include <netinet/in_systm.h> 52 #include <netinet/ip.h> 53 #include <netinet/ip_var.h> 54 #include <netinet/ip_mroute.h> 55 #include <netinet/in_pcb.h> 56 57 struct inpcb rawinpcb; 58 59 /* 60 * Nominal space allocated to a raw ip socket. 61 */ 62 #define RIPSNDQ 8192 63 #define RIPRCVQ 8192 64 65 /* 66 * Raw interface to IP protocol. 67 */ 68 69 /* 70 * Initialize raw connection block q. 71 */ 72 void 73 rip_init() 74 { 75 76 rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb; 77 } 78 79 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 80 /* 81 * Setup generic address and protocol structures 82 * for raw_input routine, then pass them along with 83 * mbuf chain. 84 */ 85 void 86 rip_input(m) 87 struct mbuf *m; 88 { 89 register struct ip *ip = mtod(m, struct ip *); 90 register struct inpcb *inp; 91 struct socket *last = 0; 92 93 ripsrc.sin_addr = ip->ip_src; 94 for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) { 95 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 96 continue; 97 if (inp->inp_laddr.s_addr && 98 inp->inp_laddr.s_addr == ip->ip_dst.s_addr) 99 continue; 100 if (inp->inp_faddr.s_addr && 101 inp->inp_faddr.s_addr == ip->ip_src.s_addr) 102 continue; 103 if (last) { 104 struct mbuf *n; 105 if (n = m_copy(m, 0, (int)M_COPYALL)) { 106 if (sbappendaddr(&last->so_rcv, 107 (struct sockaddr *)&ripsrc, 108 n, (struct mbuf *)0) == 0) 109 /* should notify about lost packet */ 110 m_freem(n); 111 else 112 sorwakeup(last); 113 } 114 } 115 last = inp->inp_socket; 116 } 117 if (last) { 118 if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc, 119 m, (struct mbuf *)0) == 0) 120 m_freem(m); 121 else 122 sorwakeup(last); 123 } else { 124 m_freem(m); 125 ipstat.ips_noproto++; 126 ipstat.ips_delivered--; 127 } 128 } 129 130 /* 131 * Generate IP header and pass packet to ip_output. 132 * Tack on options user may have setup with control call. 133 */ 134 int 135 rip_output(m, so, dst) 136 register struct mbuf *m; 137 struct socket *so; 138 u_long dst; 139 { 140 register struct ip *ip; 141 register struct inpcb *inp = sotoinpcb(so); 142 struct mbuf *opts; 143 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 144 145 /* 146 * If the user handed us a complete IP packet, use it. 147 * Otherwise, allocate an mbuf for a header and fill it in. 148 */ 149 if ((inp->inp_flags & INP_HDRINCL) == 0) { 150 M_PREPEND(m, sizeof(struct ip), M_WAIT); 151 ip = mtod(m, struct ip *); 152 ip->ip_tos = 0; 153 ip->ip_off = 0; 154 ip->ip_p = inp->inp_ip.ip_p; 155 ip->ip_len = m->m_pkthdr.len; 156 ip->ip_src = inp->inp_laddr; 157 ip->ip_dst.s_addr = dst; 158 ip->ip_ttl = MAXTTL; 159 opts = inp->inp_options; 160 } else { 161 ip = mtod(m, struct ip *); 162 if (ip->ip_id == 0) 163 ip->ip_id = htons(ip_id++); 164 opts = NULL; 165 /* XXX prevent ip_output from overwriting header fields */ 166 flags |= IP_RAWOUTPUT; 167 ipstat.ips_rawout++; 168 } 169 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions)); 170 } 171 172 /* 173 * Raw IP socket option processing. 174 */ 175 int 176 rip_ctloutput(op, so, level, optname, m) 177 int op; 178 struct socket *so; 179 int level, optname; 180 struct mbuf **m; 181 { 182 register struct inpcb *inp = sotoinpcb(so); 183 register int error; 184 185 if (level != IPPROTO_IP) 186 return (EINVAL); 187 188 switch (optname) { 189 190 case IP_HDRINCL: 191 if (op == PRCO_SETOPT || op == PRCO_GETOPT) { 192 if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 193 return (EINVAL); 194 if (op == PRCO_SETOPT) { 195 if (*mtod(*m, int *)) 196 inp->inp_flags |= INP_HDRINCL; 197 else 198 inp->inp_flags &= ~INP_HDRINCL; 199 (void)m_free(*m); 200 } else { 201 (*m)->m_len = sizeof (int); 202 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 203 } 204 return (0); 205 } 206 break; 207 208 case DVMRP_INIT: 209 case DVMRP_DONE: 210 case DVMRP_ADD_VIF: 211 case DVMRP_DEL_VIF: 212 case DVMRP_ADD_LGRP: 213 case DVMRP_DEL_LGRP: 214 case DVMRP_ADD_MRT: 215 case DVMRP_DEL_MRT: 216 #ifdef MROUTING 217 if (op == PRCO_SETOPT) { 218 error = ip_mrouter_cmd(optname, so, *m); 219 if (*m) 220 (void)m_free(*m); 221 } else 222 error = EINVAL; 223 return (error); 224 #else 225 if (op == PRCO_SETOPT && *m) 226 (void)m_free(*m); 227 return (EOPNOTSUPP); 228 #endif 229 } 230 return (ip_ctloutput(op, so, level, optname, m)); 231 } 232 233 u_long rip_sendspace = RIPSNDQ; 234 u_long rip_recvspace = RIPRCVQ; 235 236 /*ARGSUSED*/ 237 int 238 rip_usrreq(so, req, m, nam, control) 239 register struct socket *so; 240 int req; 241 struct mbuf *m, *nam, *control; 242 { 243 register int error = 0; 244 register struct inpcb *inp = sotoinpcb(so); 245 #ifdef MROUTING 246 extern struct socket *ip_mrouter; 247 #endif 248 switch (req) { 249 250 case PRU_ATTACH: 251 if (inp) 252 panic("rip_attach"); 253 if ((so->so_state & SS_PRIV) == 0) { 254 error = EACCES; 255 break; 256 } 257 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 258 (error = in_pcballoc(so, &rawinpcb))) 259 break; 260 inp = (struct inpcb *)so->so_pcb; 261 inp->inp_ip.ip_p = (int)nam; 262 break; 263 264 case PRU_DISCONNECT: 265 if ((so->so_state & SS_ISCONNECTED) == 0) { 266 error = ENOTCONN; 267 break; 268 } 269 /* FALLTHROUGH */ 270 case PRU_ABORT: 271 soisdisconnected(so); 272 /* FALLTHROUGH */ 273 case PRU_DETACH: 274 if (inp == 0) 275 panic("rip_detach"); 276 #ifdef MROUTING 277 if (so == ip_mrouter) 278 ip_mrouter_done(); 279 #endif 280 in_pcbdetach(inp); 281 break; 282 283 case PRU_BIND: 284 { 285 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 286 287 if (nam->m_len != sizeof(*addr)) { 288 error = EINVAL; 289 break; 290 } 291 if ((ifnet == 0) || 292 ((addr->sin_family != AF_INET) && 293 (addr->sin_family != AF_IMPLINK)) || 294 (addr->sin_addr.s_addr && 295 ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 296 error = EADDRNOTAVAIL; 297 break; 298 } 299 inp->inp_laddr = addr->sin_addr; 300 break; 301 } 302 case PRU_CONNECT: 303 { 304 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 305 306 if (nam->m_len != sizeof(*addr)) { 307 error = EINVAL; 308 break; 309 } 310 if (ifnet == 0) { 311 error = EADDRNOTAVAIL; 312 break; 313 } 314 if ((addr->sin_family != AF_INET) && 315 (addr->sin_family != AF_IMPLINK)) { 316 error = EAFNOSUPPORT; 317 break; 318 } 319 inp->inp_faddr = addr->sin_addr; 320 soisconnected(so); 321 break; 322 } 323 324 case PRU_CONNECT2: 325 error = EOPNOTSUPP; 326 break; 327 328 /* 329 * Mark the connection as being incapable of further input. 330 */ 331 case PRU_SHUTDOWN: 332 socantsendmore(so); 333 break; 334 335 /* 336 * Ship a packet out. The appropriate raw output 337 * routine handles any massaging necessary. 338 */ 339 case PRU_SEND: 340 { 341 register u_long dst; 342 343 if (so->so_state & SS_ISCONNECTED) { 344 if (nam) { 345 error = EISCONN; 346 break; 347 } 348 dst = inp->inp_faddr.s_addr; 349 } else { 350 if (nam == NULL) { 351 error = ENOTCONN; 352 break; 353 } 354 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 355 } 356 error = rip_output(m, so, dst); 357 m = NULL; 358 break; 359 } 360 361 case PRU_SENSE: 362 /* 363 * stat: don't bother with a blocksize. 364 */ 365 return (0); 366 367 /* 368 * Not supported. 369 */ 370 case PRU_RCVOOB: 371 case PRU_RCVD: 372 case PRU_LISTEN: 373 case PRU_ACCEPT: 374 case PRU_SENDOOB: 375 error = EOPNOTSUPP; 376 break; 377 378 case PRU_SOCKADDR: 379 in_setsockaddr(inp, nam); 380 break; 381 382 case PRU_PEERADDR: 383 in_setpeeraddr(inp, nam); 384 break; 385 386 default: 387 panic("rip_usrreq"); 388 } 389 if (m != NULL) 390 m_freem(m); 391 return (error); 392 } 393