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