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