raw_ip.c revision 19183
1/* 2 * Copyright (c) 1982, 1986, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 34 * $Id: raw_ip.c,v 1.36 1996/10/07 19:21:46 wollman Exp $ 35 */ 36 37#include <sys/param.h> 38#include <sys/queue.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 47#include <net/if.h> 48#include <net/route.h> 49 50#define _IP_VHL 51#include <netinet/in.h> 52#include <netinet/in_systm.h> 53#include <netinet/ip.h> 54#include <netinet/in_pcb.h> 55#include <netinet/in_var.h> 56#include <netinet/ip_var.h> 57#include <netinet/ip_mroute.h> 58 59#include <netinet/ip_fw.h> 60 61#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1 62#undef COMPAT_IPFW 63#define COMPAT_IPFW 1 64#else 65#undef COMPAT_IPFW 66#endif 67 68static struct inpcbhead ripcb; 69static struct inpcbinfo ripcbinfo; 70 71/* 72 * Nominal space allocated to a raw ip socket. 73 */ 74#define RIPSNDQ 8192 75#define RIPRCVQ 8192 76 77/* 78 * Raw interface to IP protocol. 79 */ 80 81/* 82 * Initialize raw connection block q. 83 */ 84void 85rip_init() 86{ 87 LIST_INIT(&ripcb); 88 ripcbinfo.listhead = &ripcb; 89 /* 90 * XXX We don't use the hash list for raw IP, but it's easier 91 * to allocate a one entry hash list than it is to check all 92 * over the place for hashbase == NULL. 93 */ 94 ripcbinfo.hashbase = phashinit(1, M_PCB, &ripcbinfo.hashsize); 95} 96 97static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 98/* 99 * Setup generic address and protocol structures 100 * for raw_input routine, then pass them along with 101 * mbuf chain. 102 */ 103void 104rip_input(m, iphlen) 105 struct mbuf *m; 106 int iphlen; 107{ 108 register struct ip *ip = mtod(m, struct ip *); 109 register struct inpcb *inp; 110 struct socket *last = 0; 111 112 ripsrc.sin_addr = ip->ip_src; 113 for (inp = ripcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { 114 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 115 continue; 116 if (inp->inp_laddr.s_addr && 117 inp->inp_laddr.s_addr != ip->ip_dst.s_addr) 118 continue; 119 if (inp->inp_faddr.s_addr && 120 inp->inp_faddr.s_addr != ip->ip_src.s_addr) 121 continue; 122 if (last) { 123 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 124 if (n) { 125 if (sbappendaddr(&last->so_rcv, 126 (struct sockaddr *)&ripsrc, n, 127 (struct mbuf *)0) == 0) 128 /* should notify about lost packet */ 129 m_freem(n); 130 else 131 sorwakeup(last); 132 } 133 } 134 last = inp->inp_socket; 135 } 136 if (last) { 137 if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc, 138 m, (struct mbuf *)0) == 0) 139 m_freem(m); 140 else 141 sorwakeup(last); 142 } else { 143 m_freem(m); 144 ipstat.ips_noproto++; 145 ipstat.ips_delivered--; 146 } 147} 148 149/* 150 * Generate IP header and pass packet to ip_output. 151 * Tack on options user may have setup with control call. 152 */ 153int 154rip_output(m, so, dst) 155 register struct mbuf *m; 156 struct socket *so; 157 u_long dst; 158{ 159 register struct ip *ip; 160 register struct inpcb *inp = sotoinpcb(so); 161 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 162 163 /* 164 * If the user handed us a complete IP packet, use it. 165 * Otherwise, allocate an mbuf for a header and fill it in. 166 */ 167 if ((inp->inp_flags & INP_HDRINCL) == 0) { 168 if (m->m_pkthdr.len + sizeof(struct ip) > IP_MAXPACKET) { 169 m_freem(m); 170 return(EMSGSIZE); 171 } 172 M_PREPEND(m, sizeof(struct ip), M_WAIT); 173 ip = mtod(m, struct ip *); 174 ip->ip_tos = 0; 175 ip->ip_off = 0; 176 ip->ip_p = inp->inp_ip.ip_p; 177 ip->ip_len = m->m_pkthdr.len; 178 ip->ip_src = inp->inp_laddr; 179 ip->ip_dst.s_addr = dst; 180 ip->ip_ttl = MAXTTL; 181 } else { 182 if (m->m_pkthdr.len > IP_MAXPACKET) { 183 m_freem(m); 184 return(EMSGSIZE); 185 } 186 ip = mtod(m, struct ip *); 187 /* don't allow both user specified and setsockopt options, 188 and don't allow packet length sizes that will crash */ 189 if (((IP_VHL_HL(ip->ip_vhl) != (sizeof (*ip) >> 2)) 190 && inp->inp_options) 191 || (ip->ip_len > m->m_pkthdr.len)) { 192 m_freem(m); 193 return EINVAL; 194 } 195 if (ip->ip_id == 0) 196 ip->ip_id = htons(ip_id++); 197 /* XXX prevent ip_output from overwriting header fields */ 198 flags |= IP_RAWOUTPUT; 199 ipstat.ips_rawout++; 200 } 201 return (ip_output(m, inp->inp_options, &inp->inp_route, flags, 202 inp->inp_moptions)); 203} 204 205/* 206 * Raw IP socket option processing. 207 */ 208int 209rip_ctloutput(op, so, level, optname, m) 210 int op; 211 struct socket *so; 212 int level, optname; 213 struct mbuf **m; 214{ 215 register struct inpcb *inp = sotoinpcb(so); 216 register int error; 217 218 if (level != IPPROTO_IP) { 219 if (op == PRCO_SETOPT && *m) 220 (void)m_free(*m); 221 return (EINVAL); 222 } 223 224 switch (optname) { 225 226 case IP_HDRINCL: 227 error = 0; 228 if (op == PRCO_SETOPT) { 229 if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 230 error = EINVAL; 231 else if (*mtod(*m, int *)) 232 inp->inp_flags |= INP_HDRINCL; 233 else 234 inp->inp_flags &= ~INP_HDRINCL; 235 if (*m) 236 (void)m_free(*m); 237 } else { 238 *m = m_get(M_WAIT, MT_SOOPTS); 239 (*m)->m_len = sizeof (int); 240 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 241 } 242 return (error); 243 244#ifdef COMPAT_IPFW 245 case IP_FW_GET: 246 if (ip_fw_ctl_ptr == NULL || op == PRCO_SETOPT) { 247 if (*m) (void)m_free(*m); 248 return(EINVAL); 249 } 250 return (*ip_fw_ctl_ptr)(optname, m); 251 252 case IP_FW_ADD: 253 case IP_FW_DEL: 254 case IP_FW_FLUSH: 255 case IP_FW_ZERO: 256 if (ip_fw_ctl_ptr == NULL || op != PRCO_SETOPT) { 257 if (*m) (void)m_free(*m); 258 return(EINVAL); 259 } 260 return (*ip_fw_ctl_ptr)(optname, m); 261 262 case IP_NAT: 263 if (ip_nat_ctl_ptr == NULL) { 264 if (*m) (void)m_free(*m); 265 return(EINVAL); 266 } 267 return (*ip_nat_ctl_ptr)(op, m); 268 269#endif 270 case IP_RSVP_ON: 271 return ip_rsvp_init(so); 272 break; 273 274 case IP_RSVP_OFF: 275 return ip_rsvp_done(); 276 break; 277 278 case IP_RSVP_VIF_ON: 279 return ip_rsvp_vif_init(so, *m); 280 281 case IP_RSVP_VIF_OFF: 282 return ip_rsvp_vif_done(so, *m); 283 284 case MRT_INIT: 285 case MRT_DONE: 286 case MRT_ADD_VIF: 287 case MRT_DEL_VIF: 288 case MRT_ADD_MFC: 289 case MRT_DEL_MFC: 290 case MRT_VERSION: 291 case MRT_ASSERT: 292 if (op == PRCO_SETOPT) { 293 error = ip_mrouter_set(optname, so, *m); 294 if (*m) 295 (void)m_free(*m); 296 } else if (op == PRCO_GETOPT) { 297 error = ip_mrouter_get(optname, so, m); 298 } else 299 error = EINVAL; 300 return (error); 301 } 302 return (ip_ctloutput(op, so, level, optname, m)); 303} 304 305static u_long rip_sendspace = RIPSNDQ; /* XXX sysctl ? */ 306static u_long rip_recvspace = RIPRCVQ; /* XXX sysctl ? */ 307 308/*ARGSUSED*/ 309int 310rip_usrreq(so, req, m, nam, control) 311 register struct socket *so; 312 int req; 313 struct mbuf *m, *nam, *control; 314{ 315 register int error = 0; 316 register struct inpcb *inp = sotoinpcb(so); 317 318 if (req == PRU_CONTROL) 319 return (in_control(so, (u_long)m, (caddr_t)nam, 320 (struct ifnet *)control)); 321 322 switch (req) { 323 324 case PRU_ATTACH: 325 if (inp) 326 panic("rip_attach"); 327 if ((so->so_state & SS_PRIV) == 0) { 328 error = EACCES; 329 break; 330 } 331 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 332 (error = in_pcballoc(so, &ripcbinfo))) 333 break; 334 inp = (struct inpcb *)so->so_pcb; 335 inp->inp_ip.ip_p = (int)nam; 336 break; 337 338 case PRU_DISCONNECT: 339 if ((so->so_state & SS_ISCONNECTED) == 0) { 340 error = ENOTCONN; 341 break; 342 } 343 /* FALLTHROUGH */ 344 case PRU_ABORT: 345 soisdisconnected(so); 346 /* FALLTHROUGH */ 347 case PRU_DETACH: 348 if (inp == 0) 349 panic("rip_detach"); 350 if (so == ip_mrouter) 351 ip_mrouter_done(); 352 ip_rsvp_force_done(so); 353 if (so == ip_rsvpd) 354 ip_rsvp_done(); 355 in_pcbdetach(inp); 356 break; 357 358 case PRU_BIND: 359 { 360 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 361 362 if (nam->m_len != sizeof(*addr)) { 363 error = EINVAL; 364 break; 365 } 366 if ((ifnet == 0) || 367 ((addr->sin_family != AF_INET) && 368 (addr->sin_family != AF_IMPLINK)) || 369 (addr->sin_addr.s_addr && 370 ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 371 error = EADDRNOTAVAIL; 372 break; 373 } 374 inp->inp_laddr = addr->sin_addr; 375 break; 376 } 377 case PRU_CONNECT: 378 { 379 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 380 381 if (nam->m_len != sizeof(*addr)) { 382 error = EINVAL; 383 break; 384 } 385 if (ifnet == 0) { 386 error = EADDRNOTAVAIL; 387 break; 388 } 389 if ((addr->sin_family != AF_INET) && 390 (addr->sin_family != AF_IMPLINK)) { 391 error = EAFNOSUPPORT; 392 break; 393 } 394 inp->inp_faddr = addr->sin_addr; 395 soisconnected(so); 396 break; 397 } 398 399 case PRU_CONNECT2: 400 error = EOPNOTSUPP; 401 break; 402 403 /* 404 * Mark the connection as being incapable of further input. 405 */ 406 case PRU_SHUTDOWN: 407 socantsendmore(so); 408 break; 409 410 /* 411 * Ship a packet out. The appropriate raw output 412 * routine handles any massaging necessary. 413 */ 414 case PRU_SEND: 415 { 416 register u_long dst; 417 418 if (so->so_state & SS_ISCONNECTED) { 419 if (nam) { 420 error = EISCONN; 421 break; 422 } 423 dst = inp->inp_faddr.s_addr; 424 } else { 425 if (nam == NULL) { 426 error = ENOTCONN; 427 break; 428 } 429 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 430 } 431 error = rip_output(m, so, dst); 432 m = NULL; 433 break; 434 } 435 436 case PRU_SENSE: 437 /* 438 * stat: don't bother with a blocksize. 439 */ 440 return (0); 441 442 /* 443 * Not supported. 444 */ 445 case PRU_RCVOOB: 446 case PRU_RCVD: 447 case PRU_LISTEN: 448 case PRU_ACCEPT: 449 case PRU_SENDOOB: 450 error = EOPNOTSUPP; 451 break; 452 453 case PRU_SOCKADDR: 454 in_setsockaddr(inp, nam); 455 break; 456 457 case PRU_PEERADDR: 458 in_setpeeraddr(inp, nam); 459 break; 460 461 default: 462 panic("rip_usrreq"); 463 } 464 if (m != NULL) 465 m_freem(m); 466 return (error); 467} 468