1 /* $OpenBSD: raw_ip.c,v 1.24 2001/06/23 16:15:56 fgsch Exp $ */ 2 /* $NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1982, 1986, 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995 37 * 38 * NRL grants permission for redistribution and use in source and binary 39 * forms, with or without modification, of the software and documentation 40 * created at NRL provided that the following conditions are met: 41 * 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. All advertising materials mentioning features or use of this software 48 * must display the following acknowledgements: 49 * This product includes software developed by the University of 50 * California, Berkeley and its contributors. 51 * This product includes software developed at the Information 52 * Technology Division, US Naval Research Laboratory. 53 * 4. Neither the name of the NRL nor the names of its contributors 54 * may be used to endorse or promote products derived from this software 55 * without specific prior written permission. 56 * 57 * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS 58 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 59 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 60 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR 61 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 62 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 63 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 64 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 65 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 66 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 67 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 68 * 69 * The views and conclusions contained in the software and documentation 70 * are those of the authors and should not be interpreted as representing 71 * official policies, either expressed or implied, of the US Naval 72 * Research Laboratory (NRL). 73 */ 74 75 #include <sys/param.h> 76 #include <sys/systm.h> 77 #include <sys/mbuf.h> 78 #include <sys/socket.h> 79 #include <sys/protosw.h> 80 #include <sys/socketvar.h> 81 82 #include <net/if.h> 83 #include <net/route.h> 84 85 #include <netinet/in.h> 86 #include <netinet/in_systm.h> 87 #include <netinet/ip.h> 88 #include <netinet/ip_mroute.h> 89 #include <netinet/ip_var.h> 90 #include <netinet/in_pcb.h> 91 #include <netinet/in_var.h> 92 #include <netinet/ip_icmp.h> 93 94 struct inpcbtable rawcbtable; 95 96 /* 97 * Nominal space allocated to a raw ip socket. 98 */ 99 #define RIPSNDQ 8192 100 #define RIPRCVQ 8192 101 102 /* 103 * Raw interface to IP protocol. 104 */ 105 106 /* 107 * Initialize raw connection block q. 108 */ 109 void 110 rip_init() 111 { 112 113 in_pcbinit(&rawcbtable, 1); 114 } 115 116 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 117 118 /* 119 * Setup generic address and protocol structures 120 * for raw_input routine, then pass them along with 121 * mbuf chain. 122 */ 123 void 124 #if __STDC__ 125 rip_input(struct mbuf *m, ...) 126 #else 127 rip_input(m, va_alist) 128 struct mbuf *m; 129 va_dcl 130 #endif 131 { 132 register struct ip *ip = mtod(m, struct ip *); 133 register struct inpcb *inp; 134 struct socket *last = 0; 135 136 ripsrc.sin_addr = ip->ip_src; 137 for (inp = rawcbtable.inpt_queue.cqh_first; 138 inp != (struct inpcb *)&rawcbtable.inpt_queue; 139 inp = inp->inp_queue.cqe_next) { 140 #ifdef INET6 141 if (inp->inp_flags & INP_IPV6) 142 continue; 143 #endif 144 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 145 continue; 146 if (inp->inp_laddr.s_addr && 147 inp->inp_laddr.s_addr != ip->ip_dst.s_addr) 148 continue; 149 if (inp->inp_faddr.s_addr && 150 inp->inp_faddr.s_addr != ip->ip_src.s_addr) 151 continue; 152 if (last) { 153 struct mbuf *n; 154 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 155 if (sbappendaddr(&last->so_rcv, 156 sintosa(&ripsrc), n, 157 (struct mbuf *)0) == 0) 158 /* should notify about lost packet */ 159 m_freem(n); 160 else 161 sorwakeup(last); 162 } 163 } 164 last = inp->inp_socket; 165 } 166 if (last) { 167 if (sbappendaddr(&last->so_rcv, sintosa(&ripsrc), m, 168 (struct mbuf *)0) == 0) 169 m_freem(m); 170 else 171 sorwakeup(last); 172 } else { 173 if (ip->ip_p != IPPROTO_ICMP) 174 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0); 175 else 176 m_freem(m); 177 ipstat.ips_noproto++; 178 ipstat.ips_delivered--; 179 } 180 } 181 182 /* 183 * Generate IP header and pass packet to ip_output. 184 * Tack on options user may have setup with control call. 185 */ 186 int 187 #if __STDC__ 188 rip_output(struct mbuf *m, ...) 189 #else 190 rip_output(m, va_alist) 191 struct mbuf *m; 192 va_dcl 193 #endif 194 { 195 struct socket *so; 196 u_long dst; 197 register struct ip *ip; 198 register struct inpcb *inp; 199 int flags; 200 va_list ap; 201 202 va_start(ap, m); 203 so = va_arg(ap, struct socket *); 204 dst = va_arg(ap, u_long); 205 va_end(ap); 206 207 inp = sotoinpcb(so); 208 flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 209 210 /* 211 * If the user handed us a complete IP packet, use it. 212 * Otherwise, allocate an mbuf for a header and fill it in. 213 */ 214 if ((inp->inp_flags & INP_HDRINCL) == 0) { 215 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { 216 m_freem(m); 217 return (EMSGSIZE); 218 } 219 M_PREPEND(m, sizeof(struct ip), M_WAIT); 220 ip = mtod(m, struct ip *); 221 ip->ip_tos = 0; 222 ip->ip_off = 0; 223 ip->ip_p = inp->inp_ip.ip_p; 224 ip->ip_len = m->m_pkthdr.len; 225 ip->ip_src = inp->inp_laddr; 226 ip->ip_dst.s_addr = dst; 227 ip->ip_ttl = MAXTTL; 228 } else { 229 if (m->m_pkthdr.len > IP_MAXPACKET) { 230 m_freem(m); 231 return (EMSGSIZE); 232 } 233 ip = mtod(m, struct ip *); 234 NTOHS(ip->ip_len); 235 NTOHS(ip->ip_off); 236 /* 237 * don't allow both user specified and setsockopt options, 238 * and don't allow packet length sizes that will crash 239 */ 240 if ((ip->ip_hl != (sizeof (*ip) >> 2) && inp->inp_options) || 241 ip->ip_len > m->m_pkthdr.len || 242 ip->ip_len < ip->ip_hl << 2) { 243 m_freem(m); 244 return (EINVAL); 245 } 246 if (ip->ip_id == 0) { 247 ip->ip_id = htons(ip_randomid()); 248 } 249 /* XXX prevent ip_output from overwriting header fields */ 250 flags |= IP_RAWOUTPUT; 251 ipstat.ips_rawout++; 252 } 253 #ifdef INET6 254 /* 255 * A thought: Even though raw IP shouldn't be able to set IPv6 256 * multicast options, if it does, the last parameter to 257 * ip_output should be guarded against v6/v4 problems. 258 */ 259 #endif 260 return (ip_output(m, inp->inp_options, &inp->inp_route, flags, 261 inp->inp_moptions, inp)); 262 } 263 264 /* 265 * Raw IP socket option processing. 266 */ 267 int 268 rip_ctloutput(op, so, level, optname, m) 269 int op; 270 struct socket *so; 271 int level, optname; 272 struct mbuf **m; 273 { 274 register struct inpcb *inp = sotoinpcb(so); 275 register int error; 276 277 if (level != IPPROTO_IP) { 278 if (op == PRCO_SETOPT && *m) 279 (void) m_free(*m); 280 return (EINVAL); 281 } 282 283 switch (optname) { 284 285 case IP_HDRINCL: 286 error = 0; 287 if (op == PRCO_SETOPT) { 288 if (*m == 0 || (*m)->m_len < sizeof (int)) 289 error = EINVAL; 290 else if (*mtod(*m, int *)) 291 inp->inp_flags |= INP_HDRINCL; 292 else 293 inp->inp_flags &= ~INP_HDRINCL; 294 if (*m) 295 (void)m_free(*m); 296 } else { 297 *m = m_get(M_WAIT, M_SOOPTS); 298 (*m)->m_len = sizeof(int); 299 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 300 } 301 return (error); 302 303 case MRT_INIT: 304 case MRT_DONE: 305 case MRT_ADD_VIF: 306 case MRT_DEL_VIF: 307 case MRT_ADD_MFC: 308 case MRT_DEL_MFC: 309 case MRT_VERSION: 310 case MRT_ASSERT: 311 #ifdef MROUTING 312 switch (op) { 313 case PRCO_SETOPT: 314 error = ip_mrouter_set(optname, so, m); 315 break; 316 case PRCO_GETOPT: 317 error = ip_mrouter_get(optname, so, m); 318 break; 319 default: 320 error = EINVAL; 321 break; 322 } 323 return (error); 324 #else 325 if (op == PRCO_SETOPT && *m) 326 m_free(*m); 327 return (EOPNOTSUPP); 328 #endif 329 } 330 return (ip_ctloutput(op, so, level, optname, m)); 331 } 332 333 u_long rip_sendspace = RIPSNDQ; 334 u_long rip_recvspace = RIPRCVQ; 335 336 /*ARGSUSED*/ 337 int 338 rip_usrreq(so, req, m, nam, control) 339 register struct socket *so; 340 int req; 341 struct mbuf *m, *nam, *control; 342 { 343 register int error = 0; 344 register struct inpcb *inp = sotoinpcb(so); 345 #ifdef MROUTING 346 extern struct socket *ip_mrouter; 347 #endif 348 if (req == PRU_CONTROL) 349 return (in_control(so, (u_long)m, (caddr_t)nam, 350 (struct ifnet *)control)); 351 352 if (inp == NULL && req != PRU_ATTACH) { 353 error = EINVAL; 354 goto release; 355 } 356 357 switch (req) { 358 359 case PRU_ATTACH: 360 if (inp) 361 panic("rip_attach"); 362 if ((so->so_state & SS_PRIV) == 0) { 363 error = EACCES; 364 break; 365 } 366 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 367 (error = in_pcballoc(so, &rawcbtable))) 368 break; 369 inp = (struct inpcb *)so->so_pcb; 370 inp->inp_ip.ip_p = (long)nam; 371 break; 372 373 case PRU_DISCONNECT: 374 if ((so->so_state & SS_ISCONNECTED) == 0) { 375 error = ENOTCONN; 376 break; 377 } 378 /* FALLTHROUGH */ 379 case PRU_ABORT: 380 soisdisconnected(so); 381 /* FALLTHROUGH */ 382 case PRU_DETACH: 383 if (inp == 0) 384 panic("rip_detach"); 385 #ifdef MROUTING 386 if (so == ip_mrouter) 387 ip_mrouter_done(); 388 #endif 389 in_pcbdetach(inp); 390 break; 391 392 case PRU_BIND: 393 { 394 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 395 396 if (nam->m_len != sizeof(*addr)) { 397 error = EINVAL; 398 break; 399 } 400 if ((ifnet.tqh_first == 0) || 401 ((addr->sin_family != AF_INET) && 402 (addr->sin_family != AF_IMPLINK)) || 403 (addr->sin_addr.s_addr && 404 ifa_ifwithaddr(sintosa(addr)) == 0)) { 405 error = EADDRNOTAVAIL; 406 break; 407 } 408 inp->inp_laddr = addr->sin_addr; 409 break; 410 } 411 case PRU_CONNECT: 412 { 413 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 414 415 if (nam->m_len != sizeof(*addr)) { 416 error = EINVAL; 417 break; 418 } 419 if (ifnet.tqh_first == 0) { 420 error = EADDRNOTAVAIL; 421 break; 422 } 423 if ((addr->sin_family != AF_INET) && 424 (addr->sin_family != AF_IMPLINK)) { 425 error = EAFNOSUPPORT; 426 break; 427 } 428 inp->inp_faddr = addr->sin_addr; 429 soisconnected(so); 430 break; 431 } 432 433 case PRU_CONNECT2: 434 error = EOPNOTSUPP; 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 /* 445 * Ship a packet out. The appropriate raw output 446 * routine handles any massaging necessary. 447 */ 448 case PRU_SEND: 449 { 450 register u_int32_t dst; 451 452 if (so->so_state & SS_ISCONNECTED) { 453 if (nam) { 454 error = EISCONN; 455 break; 456 } 457 dst = inp->inp_faddr.s_addr; 458 } else { 459 if (nam == NULL) { 460 error = ENOTCONN; 461 break; 462 } 463 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 464 } 465 #ifdef IPSEC 466 /* XXX Find an IPsec TDB */ 467 #endif 468 error = rip_output(m, so, dst); 469 m = NULL; 470 break; 471 } 472 473 case PRU_SENSE: 474 /* 475 * stat: don't bother with a blocksize. 476 */ 477 return (0); 478 479 /* 480 * Not supported. 481 */ 482 case PRU_RCVOOB: 483 case PRU_RCVD: 484 case PRU_LISTEN: 485 case PRU_ACCEPT: 486 case PRU_SENDOOB: 487 error = EOPNOTSUPP; 488 break; 489 490 case PRU_SOCKADDR: 491 in_setsockaddr(inp, nam); 492 break; 493 494 case PRU_PEERADDR: 495 in_setpeeraddr(inp, nam); 496 break; 497 498 default: 499 panic("rip_usrreq"); 500 } 501 release: 502 if (m != NULL) 503 m_freem(m); 504 return (error); 505 } 506