1 /* $NetBSD: raw_ip.c,v 1.36 1997/01/11 05:21:13 thorpej 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 #include <sys/proc.h> 47 48 #include <net/if.h> 49 #include <net/route.h> 50 51 #include <netinet/in.h> 52 #include <netinet/in_systm.h> 53 #include <netinet/ip.h> 54 #include <netinet/ip_var.h> 55 #include <netinet/ip_mroute.h> 56 #include <netinet/in_pcb.h> 57 #include <netinet/in_var.h> 58 59 #include <machine/stdarg.h> 60 61 struct inpcbtable rawcbtable; 62 63 int rip_bind __P((struct inpcb *, struct mbuf *)); 64 int rip_connect __P((struct inpcb *, struct mbuf *)); 65 void rip_disconnect __P((struct inpcb *)); 66 67 /* 68 * Nominal space allocated to a raw ip socket. 69 */ 70 #define RIPSNDQ 8192 71 #define RIPRCVQ 8192 72 73 /* 74 * Raw interface to IP protocol. 75 */ 76 77 /* 78 * Initialize raw connection block q. 79 */ 80 void 81 rip_init() 82 { 83 84 in_pcbinit(&rawcbtable, 1, 1); 85 } 86 87 /* 88 * Setup generic address and protocol structures 89 * for raw_input routine, then pass them along with 90 * mbuf chain. 91 */ 92 void 93 #if __STDC__ 94 rip_input(struct mbuf *m, ...) 95 #else 96 rip_input(m, va_alist) 97 struct mbuf *m; 98 va_dcl 99 #endif 100 { 101 register struct ip *ip = mtod(m, struct ip *); 102 register struct inpcb *inp; 103 struct inpcb *last = 0; 104 struct mbuf *opts = 0; 105 struct sockaddr_in ripsrc; 106 107 ripsrc.sin_family = AF_INET; 108 ripsrc.sin_len = sizeof(struct sockaddr_in); 109 ripsrc.sin_addr = ip->ip_src; 110 ripsrc.sin_port = 0; 111 bzero((caddr_t)ripsrc.sin_zero, sizeof(ripsrc.sin_zero)); 112 113 for (inp = rawcbtable.inpt_queue.cqh_first; 114 inp != (struct inpcb *)&rawcbtable.inpt_queue; 115 inp = inp->inp_queue.cqe_next) { 116 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 117 continue; 118 if (!in_nullhost(inp->inp_laddr) && 119 !in_hosteq(inp->inp_laddr, ip->ip_dst)) 120 continue; 121 if (!in_nullhost(inp->inp_faddr) && 122 !in_hosteq(inp->inp_faddr, ip->ip_src)) 123 continue; 124 if (last) { 125 struct mbuf *n; 126 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 127 if (last->inp_flags & INP_CONTROLOPTS || 128 last->inp_socket->so_options & SO_TIMESTAMP) 129 ip_savecontrol(last, &opts, ip, n); 130 if (sbappendaddr(&last->inp_socket->so_rcv, 131 sintosa(&ripsrc), n, opts) == 0) { 132 /* should notify about lost packet */ 133 m_freem(n); 134 if (opts) 135 m_freem(opts); 136 } else 137 sorwakeup(last->inp_socket); 138 } 139 } 140 last = inp; 141 } 142 if (last) { 143 if (last->inp_flags & INP_CONTROLOPTS || 144 last->inp_socket->so_options & SO_TIMESTAMP) 145 ip_savecontrol(last, &opts, ip, m); 146 if (sbappendaddr(&last->inp_socket->so_rcv, 147 sintosa(&ripsrc), m, opts) == 0) { 148 m_freem(m); 149 if (opts) 150 m_freem(opts); 151 } else 152 sorwakeup(last->inp_socket); 153 } else { 154 m_freem(m); 155 ipstat.ips_noproto++; 156 ipstat.ips_delivered--; 157 } 158 } 159 160 /* 161 * Generate IP header and pass packet to ip_output. 162 * Tack on options user may have setup with control call. 163 */ 164 int 165 #if __STDC__ 166 rip_output(struct mbuf *m, ...) 167 #else 168 rip_output(m, va_alist) 169 struct mbuf *m; 170 va_dcl 171 #endif 172 { 173 register struct inpcb *inp; 174 register struct ip *ip; 175 struct mbuf *opts; 176 int flags; 177 va_list ap; 178 179 va_start(ap, m); 180 inp = va_arg(ap, struct inpcb *); 181 va_end(ap); 182 183 flags = 184 (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 185 186 /* 187 * If the user handed us a complete IP packet, use it. 188 * Otherwise, allocate an mbuf for a header and fill it in. 189 */ 190 if ((inp->inp_flags & INP_HDRINCL) == 0) { 191 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { 192 m_freem(m); 193 return (EMSGSIZE); 194 } 195 M_PREPEND(m, sizeof(struct ip), M_WAIT); 196 ip = mtod(m, struct ip *); 197 ip->ip_tos = 0; 198 ip->ip_off = 0; 199 ip->ip_p = inp->inp_ip.ip_p; 200 ip->ip_len = m->m_pkthdr.len; 201 ip->ip_src = inp->inp_laddr; 202 ip->ip_dst = inp->inp_faddr; 203 ip->ip_ttl = MAXTTL; 204 opts = inp->inp_options; 205 } else { 206 if (m->m_pkthdr.len > IP_MAXPACKET) { 207 m_freem(m); 208 return (EMSGSIZE); 209 } 210 ip = mtod(m, struct ip *); 211 if (ip->ip_id == 0) 212 ip->ip_id = htons(ip_id++); 213 opts = NULL; 214 /* XXX prevent ip_output from overwriting header fields */ 215 flags |= IP_RAWOUTPUT; 216 ipstat.ips_rawout++; 217 } 218 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions)); 219 } 220 221 /* 222 * Raw IP socket option processing. 223 */ 224 int 225 rip_ctloutput(op, so, level, optname, m) 226 int op; 227 struct socket *so; 228 int level, optname; 229 struct mbuf **m; 230 { 231 register struct inpcb *inp = sotoinpcb(so); 232 int error = 0; 233 234 if (level != IPPROTO_IP) { 235 error = ENOPROTOOPT; 236 if (op == PRCO_SETOPT && *m != 0) 237 (void) m_free(*m); 238 } else switch (op) { 239 240 case PRCO_SETOPT: 241 switch (optname) { 242 case IP_HDRINCL: 243 if (*m == 0 || (*m)->m_len < sizeof (int)) 244 error = EINVAL; 245 else { 246 if (*mtod(*m, int *)) 247 inp->inp_flags |= INP_HDRINCL; 248 else 249 inp->inp_flags &= ~INP_HDRINCL; 250 } 251 if (*m != 0) 252 (void) m_free(*m); 253 break; 254 255 #ifdef MROUTING 256 case MRT_INIT: 257 case MRT_DONE: 258 case MRT_ADD_VIF: 259 case MRT_DEL_VIF: 260 case MRT_ADD_MFC: 261 case MRT_DEL_MFC: 262 case MRT_ASSERT: 263 error = ip_mrouter_set(so, optname, m); 264 break; 265 #endif 266 267 default: 268 error = ip_ctloutput(op, so, level, optname, m); 269 break; 270 } 271 break; 272 273 case PRCO_GETOPT: 274 switch (optname) { 275 case IP_HDRINCL: 276 *m = m_get(M_WAIT, M_SOOPTS); 277 (*m)->m_len = sizeof (int); 278 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0; 279 break; 280 281 #ifdef MROUTING 282 case MRT_VERSION: 283 case MRT_ASSERT: 284 error = ip_mrouter_get(so, optname, m); 285 break; 286 #endif 287 288 default: 289 error = ip_ctloutput(op, so, level, optname, m); 290 break; 291 } 292 break; 293 } 294 return (error); 295 } 296 297 int 298 rip_bind(inp, nam) 299 struct inpcb *inp; 300 struct mbuf *nam; 301 { 302 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 303 304 if (nam->m_len != sizeof(*addr)) 305 return (EINVAL); 306 if (ifnet.tqh_first == 0) 307 return (EADDRNOTAVAIL); 308 if (addr->sin_family != AF_INET && 309 addr->sin_family != AF_IMPLINK) 310 return (EAFNOSUPPORT); 311 if (!in_nullhost(addr->sin_addr) && 312 ifa_ifwithaddr(sintosa(addr)) == 0) 313 return (EADDRNOTAVAIL); 314 inp->inp_laddr = addr->sin_addr; 315 return (0); 316 } 317 318 int 319 rip_connect(inp, nam) 320 struct inpcb *inp; 321 struct mbuf *nam; 322 { 323 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 324 325 if (nam->m_len != sizeof(*addr)) 326 return (EINVAL); 327 if (ifnet.tqh_first == 0) 328 return (EADDRNOTAVAIL); 329 if (addr->sin_family != AF_INET && 330 addr->sin_family != AF_IMPLINK) 331 return (EAFNOSUPPORT); 332 inp->inp_faddr = addr->sin_addr; 333 return (0); 334 } 335 336 void 337 rip_disconnect(inp) 338 struct inpcb *inp; 339 { 340 341 inp->inp_faddr = zeroin_addr; 342 } 343 344 u_long rip_sendspace = RIPSNDQ; 345 u_long rip_recvspace = RIPRCVQ; 346 347 /*ARGSUSED*/ 348 int 349 rip_usrreq(so, req, m, nam, control, p) 350 register struct socket *so; 351 int req; 352 struct mbuf *m, *nam, *control; 353 struct proc *p; 354 { 355 register struct inpcb *inp; 356 int s; 357 register int error = 0; 358 #ifdef MROUTING 359 extern struct socket *ip_mrouter; 360 #endif 361 362 if (req == PRU_CONTROL) 363 return (in_control(so, (long)m, (caddr_t)nam, 364 (struct ifnet *)control, p)); 365 366 s = splsoftnet(); 367 inp = sotoinpcb(so); 368 #ifdef DIAGNOSTIC 369 if (req != PRU_SEND && req != PRU_SENDOOB && control) 370 panic("rip_usrreq: unexpected control mbuf"); 371 #endif 372 if (inp == 0 && req != PRU_ATTACH) { 373 error = EINVAL; 374 goto release; 375 } 376 377 switch (req) { 378 379 case PRU_ATTACH: 380 if (inp != 0) { 381 error = EISCONN; 382 break; 383 } 384 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) { 385 error = EACCES; 386 break; 387 } 388 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 389 error = soreserve(so, rip_sendspace, rip_recvspace); 390 if (error) 391 break; 392 } 393 error = in_pcballoc(so, &rawcbtable); 394 if (error) 395 break; 396 inp = sotoinpcb(so); 397 inp->inp_ip.ip_p = (long)nam; 398 break; 399 400 case PRU_DETACH: 401 #ifdef MROUTING 402 if (so == ip_mrouter) 403 ip_mrouter_done(); 404 #endif 405 in_pcbdetach(inp); 406 break; 407 408 case PRU_BIND: 409 error = rip_bind(inp, nam); 410 break; 411 412 case PRU_LISTEN: 413 error = EOPNOTSUPP; 414 break; 415 416 case PRU_CONNECT: 417 error = rip_connect(inp, nam); 418 if (error) 419 break; 420 soisconnected(so); 421 break; 422 423 case PRU_CONNECT2: 424 error = EOPNOTSUPP; 425 break; 426 427 case PRU_DISCONNECT: 428 soisdisconnected(so); 429 rip_disconnect(inp); 430 break; 431 432 /* 433 * Mark the connection as being incapable of further input. 434 */ 435 case PRU_SHUTDOWN: 436 socantsendmore(so); 437 break; 438 439 case PRU_RCVD: 440 error = EOPNOTSUPP; 441 break; 442 443 /* 444 * Ship a packet out. The appropriate raw output 445 * routine handles any massaging necessary. 446 */ 447 case PRU_SEND: 448 if (control && control->m_len) { 449 m_freem(control); 450 m_freem(m); 451 error = EINVAL; 452 break; 453 } 454 { 455 if (nam) { 456 if ((so->so_state & SS_ISCONNECTED) != 0) { 457 error = EISCONN; 458 goto die; 459 } 460 error = rip_connect(inp, nam); 461 if (error) { 462 die: 463 m_freem(m); 464 break; 465 } 466 } else { 467 if ((so->so_state & SS_ISCONNECTED) == 0) { 468 error = ENOTCONN; 469 goto die; 470 } 471 } 472 error = rip_output(m, inp); 473 if (nam) 474 rip_disconnect(inp); 475 } 476 break; 477 478 case PRU_SENSE: 479 /* 480 * stat: don't bother with a blocksize. 481 */ 482 splx(s); 483 return (0); 484 485 case PRU_RCVOOB: 486 error = EOPNOTSUPP; 487 break; 488 489 case PRU_SENDOOB: 490 m_freem(control); 491 m_freem(m); 492 error = EOPNOTSUPP; 493 break; 494 495 case PRU_SOCKADDR: 496 in_setsockaddr(inp, nam); 497 break; 498 499 case PRU_PEERADDR: 500 in_setpeeraddr(inp, nam); 501 break; 502 503 default: 504 panic("rip_usrreq"); 505 } 506 507 release: 508 splx(s); 509 return (error); 510 } 511