1 /* $NetBSD: raw_ip.c,v 1.37 1997/10/14 00:52:54 matt 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 | IP_RETURNMTU; 186 187 /* 188 * If the user handed us a complete IP packet, use it. 189 * Otherwise, allocate an mbuf for a header and fill it in. 190 */ 191 if ((inp->inp_flags & INP_HDRINCL) == 0) { 192 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { 193 m_freem(m); 194 return (EMSGSIZE); 195 } 196 M_PREPEND(m, sizeof(struct ip), M_WAIT); 197 ip = mtod(m, struct ip *); 198 ip->ip_tos = 0; 199 ip->ip_off = 0; 200 ip->ip_p = inp->inp_ip.ip_p; 201 ip->ip_len = m->m_pkthdr.len; 202 ip->ip_src = inp->inp_laddr; 203 ip->ip_dst = inp->inp_faddr; 204 ip->ip_ttl = MAXTTL; 205 opts = inp->inp_options; 206 } else { 207 if (m->m_pkthdr.len > IP_MAXPACKET) { 208 m_freem(m); 209 return (EMSGSIZE); 210 } 211 ip = mtod(m, struct ip *); 212 if (ip->ip_id == 0) 213 ip->ip_id = htons(ip_id++); 214 opts = NULL; 215 /* XXX prevent ip_output from overwriting header fields */ 216 flags |= IP_RAWOUTPUT; 217 ipstat.ips_rawout++; 218 } 219 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, &inp->inp_errormtu)); 220 } 221 222 /* 223 * Raw IP socket option processing. 224 */ 225 int 226 rip_ctloutput(op, so, level, optname, m) 227 int op; 228 struct socket *so; 229 int level, optname; 230 struct mbuf **m; 231 { 232 register struct inpcb *inp = sotoinpcb(so); 233 int error = 0; 234 235 if (level != IPPROTO_IP) { 236 error = ENOPROTOOPT; 237 if (op == PRCO_SETOPT && *m != 0) 238 (void) m_free(*m); 239 } else switch (op) { 240 241 case PRCO_SETOPT: 242 switch (optname) { 243 case IP_HDRINCL: 244 if (*m == 0 || (*m)->m_len < sizeof (int)) 245 error = EINVAL; 246 else { 247 if (*mtod(*m, int *)) 248 inp->inp_flags |= INP_HDRINCL; 249 else 250 inp->inp_flags &= ~INP_HDRINCL; 251 } 252 if (*m != 0) 253 (void) m_free(*m); 254 break; 255 256 #ifdef MROUTING 257 case MRT_INIT: 258 case MRT_DONE: 259 case MRT_ADD_VIF: 260 case MRT_DEL_VIF: 261 case MRT_ADD_MFC: 262 case MRT_DEL_MFC: 263 case MRT_ASSERT: 264 error = ip_mrouter_set(so, optname, m); 265 break; 266 #endif 267 268 default: 269 error = ip_ctloutput(op, so, level, optname, m); 270 break; 271 } 272 break; 273 274 case PRCO_GETOPT: 275 switch (optname) { 276 case IP_HDRINCL: 277 *m = m_get(M_WAIT, M_SOOPTS); 278 (*m)->m_len = sizeof (int); 279 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0; 280 break; 281 282 #ifdef MROUTING 283 case MRT_VERSION: 284 case MRT_ASSERT: 285 error = ip_mrouter_get(so, optname, m); 286 break; 287 #endif 288 289 default: 290 error = ip_ctloutput(op, so, level, optname, m); 291 break; 292 } 293 break; 294 } 295 return (error); 296 } 297 298 int 299 rip_bind(inp, nam) 300 struct inpcb *inp; 301 struct mbuf *nam; 302 { 303 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 304 305 if (nam->m_len != sizeof(*addr)) 306 return (EINVAL); 307 if (ifnet.tqh_first == 0) 308 return (EADDRNOTAVAIL); 309 if (addr->sin_family != AF_INET && 310 addr->sin_family != AF_IMPLINK) 311 return (EAFNOSUPPORT); 312 if (!in_nullhost(addr->sin_addr) && 313 ifa_ifwithaddr(sintosa(addr)) == 0) 314 return (EADDRNOTAVAIL); 315 inp->inp_laddr = addr->sin_addr; 316 return (0); 317 } 318 319 int 320 rip_connect(inp, nam) 321 struct inpcb *inp; 322 struct mbuf *nam; 323 { 324 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 325 326 if (nam->m_len != sizeof(*addr)) 327 return (EINVAL); 328 if (ifnet.tqh_first == 0) 329 return (EADDRNOTAVAIL); 330 if (addr->sin_family != AF_INET && 331 addr->sin_family != AF_IMPLINK) 332 return (EAFNOSUPPORT); 333 inp->inp_faddr = addr->sin_addr; 334 return (0); 335 } 336 337 void 338 rip_disconnect(inp) 339 struct inpcb *inp; 340 { 341 342 inp->inp_faddr = zeroin_addr; 343 } 344 345 u_long rip_sendspace = RIPSNDQ; 346 u_long rip_recvspace = RIPRCVQ; 347 348 /*ARGSUSED*/ 349 int 350 rip_usrreq(so, req, m, nam, control, p) 351 register struct socket *so; 352 int req; 353 struct mbuf *m, *nam, *control; 354 struct proc *p; 355 { 356 register struct inpcb *inp; 357 int s; 358 register int error = 0; 359 #ifdef MROUTING 360 extern struct socket *ip_mrouter; 361 #endif 362 363 if (req == PRU_CONTROL) 364 return (in_control(so, (long)m, (caddr_t)nam, 365 (struct ifnet *)control, p)); 366 367 s = splsoftnet(); 368 inp = sotoinpcb(so); 369 #ifdef DIAGNOSTIC 370 if (req != PRU_SEND && req != PRU_SENDOOB && control) 371 panic("rip_usrreq: unexpected control mbuf"); 372 #endif 373 if (inp == 0 && req != PRU_ATTACH) { 374 error = EINVAL; 375 goto release; 376 } 377 378 switch (req) { 379 380 case PRU_ATTACH: 381 if (inp != 0) { 382 error = EISCONN; 383 break; 384 } 385 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) { 386 error = EACCES; 387 break; 388 } 389 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 390 error = soreserve(so, rip_sendspace, rip_recvspace); 391 if (error) 392 break; 393 } 394 error = in_pcballoc(so, &rawcbtable); 395 if (error) 396 break; 397 inp = sotoinpcb(so); 398 inp->inp_ip.ip_p = (long)nam; 399 break; 400 401 case PRU_DETACH: 402 #ifdef MROUTING 403 if (so == ip_mrouter) 404 ip_mrouter_done(); 405 #endif 406 in_pcbdetach(inp); 407 break; 408 409 case PRU_BIND: 410 error = rip_bind(inp, nam); 411 break; 412 413 case PRU_LISTEN: 414 error = EOPNOTSUPP; 415 break; 416 417 case PRU_CONNECT: 418 error = rip_connect(inp, nam); 419 if (error) 420 break; 421 soisconnected(so); 422 break; 423 424 case PRU_CONNECT2: 425 error = EOPNOTSUPP; 426 break; 427 428 case PRU_DISCONNECT: 429 soisdisconnected(so); 430 rip_disconnect(inp); 431 break; 432 433 /* 434 * Mark the connection as being incapable of further input. 435 */ 436 case PRU_SHUTDOWN: 437 socantsendmore(so); 438 break; 439 440 case PRU_RCVD: 441 error = EOPNOTSUPP; 442 break; 443 444 /* 445 * Ship a packet out. The appropriate raw output 446 * routine handles any massaging necessary. 447 */ 448 case PRU_SEND: 449 if (control && control->m_len) { 450 m_freem(control); 451 m_freem(m); 452 error = EINVAL; 453 break; 454 } 455 { 456 if (nam) { 457 if ((so->so_state & SS_ISCONNECTED) != 0) { 458 error = EISCONN; 459 goto die; 460 } 461 error = rip_connect(inp, nam); 462 if (error) { 463 die: 464 m_freem(m); 465 break; 466 } 467 } else { 468 if ((so->so_state & SS_ISCONNECTED) == 0) { 469 error = ENOTCONN; 470 goto die; 471 } 472 } 473 error = rip_output(m, inp); 474 if (nam) 475 rip_disconnect(inp); 476 } 477 break; 478 479 case PRU_SENSE: 480 /* 481 * stat: don't bother with a blocksize. 482 */ 483 splx(s); 484 return (0); 485 486 case PRU_RCVOOB: 487 error = EOPNOTSUPP; 488 break; 489 490 case PRU_SENDOOB: 491 m_freem(control); 492 m_freem(m); 493 error = EOPNOTSUPP; 494 break; 495 496 case PRU_SOCKADDR: 497 in_setsockaddr(inp, nam); 498 break; 499 500 case PRU_PEERADDR: 501 in_setpeeraddr(inp, nam); 502 break; 503 504 default: 505 panic("rip_usrreq"); 506 } 507 508 release: 509 splx(s); 510 return (error); 511 } 512