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