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