1 /* $NetBSD: raw_ip.c,v 1.16 1995/03/02 09:33:40 glass 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 47 #include <net/if.h> 48 #include <net/route.h> 49 50 #include <netinet/in.h> 51 #include <netinet/in_systm.h> 52 #include <netinet/ip.h> 53 #include <netinet/ip_var.h> 54 #include <netinet/ip_mroute.h> 55 #include <netinet/in_pcb.h> 56 57 struct inpcb rawinpcb; 58 59 /* 60 * Nominal space allocated to a raw ip socket. 61 */ 62 #define RIPSNDQ 8192 63 #define RIPRCVQ 8192 64 65 /* 66 * Raw interface to IP protocol. 67 */ 68 69 /* 70 * Initialize raw connection block q. 71 */ 72 void 73 rip_init() 74 { 75 76 rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb; 77 } 78 79 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 80 /* 81 * Setup generic address and protocol structures 82 * for raw_input routine, then pass them along with 83 * mbuf chain. 84 */ 85 void 86 rip_input(m) 87 struct mbuf *m; 88 { 89 register struct ip *ip = mtod(m, struct ip *); 90 register struct inpcb *inp; 91 struct socket *last = 0; 92 93 ripsrc.sin_addr = ip->ip_src; 94 for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) { 95 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 96 continue; 97 if (inp->inp_laddr.s_addr && 98 inp->inp_laddr.s_addr != ip->ip_dst.s_addr) 99 continue; 100 if (inp->inp_faddr.s_addr && 101 inp->inp_faddr.s_addr != ip->ip_src.s_addr) 102 continue; 103 if (last) { 104 struct mbuf *n; 105 if (n = m_copy(m, 0, (int)M_COPYALL)) { 106 if (sbappendaddr(&last->so_rcv, 107 (struct sockaddr *)&ripsrc, 108 n, (struct mbuf *)0) == 0) 109 /* should notify about lost packet */ 110 m_freem(n); 111 else 112 sorwakeup(last); 113 } 114 } 115 last = inp->inp_socket; 116 } 117 if (last) { 118 if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc, 119 m, (struct mbuf *)0) == 0) 120 m_freem(m); 121 else 122 sorwakeup(last); 123 } else { 124 m_freem(m); 125 ipstat.ips_noproto++; 126 ipstat.ips_delivered--; 127 } 128 } 129 130 /* 131 * Generate IP header and pass packet to ip_output. 132 * Tack on options user may have setup with control call. 133 */ 134 int 135 rip_output(m, so, dst) 136 register struct mbuf *m; 137 struct socket *so; 138 u_long dst; 139 { 140 register struct ip *ip; 141 register struct inpcb *inp = sotoinpcb(so); 142 struct mbuf *opts; 143 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 144 145 /* 146 * If the user handed us a complete IP packet, use it. 147 * Otherwise, allocate an mbuf for a header and fill it in. 148 */ 149 if ((inp->inp_flags & INP_HDRINCL) == 0) { 150 M_PREPEND(m, sizeof(struct ip), M_WAIT); 151 ip = mtod(m, struct ip *); 152 ip->ip_tos = 0; 153 ip->ip_off = 0; 154 ip->ip_p = inp->inp_ip.ip_p; 155 ip->ip_len = m->m_pkthdr.len; 156 ip->ip_src = inp->inp_laddr; 157 ip->ip_dst.s_addr = dst; 158 ip->ip_ttl = MAXTTL; 159 opts = inp->inp_options; 160 } else { 161 ip = mtod(m, struct ip *); 162 if (ip->ip_id == 0) 163 ip->ip_id = htons(ip_id++); 164 opts = NULL; 165 /* XXX prevent ip_output from overwriting header fields */ 166 flags |= IP_RAWOUTPUT; 167 ipstat.ips_rawout++; 168 } 169 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions)); 170 } 171 172 /* 173 * Raw IP socket option processing. 174 */ 175 int 176 rip_ctloutput(op, so, level, optname, m) 177 int op; 178 struct socket *so; 179 int level, optname; 180 struct mbuf **m; 181 { 182 register struct inpcb *inp = sotoinpcb(so); 183 register int error; 184 185 if (level != IPPROTO_IP) { 186 if (m != 0 && *m != 0) 187 (void)m_free(*m); 188 return (EINVAL); 189 } 190 191 switch (optname) { 192 193 case IP_HDRINCL: 194 if (op == PRCO_SETOPT || op == PRCO_GETOPT) { 195 if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 196 return (EINVAL); 197 if (op == PRCO_SETOPT) { 198 if (*mtod(*m, int *)) 199 inp->inp_flags |= INP_HDRINCL; 200 else 201 inp->inp_flags &= ~INP_HDRINCL; 202 (void)m_free(*m); 203 } else { 204 (*m)->m_len = sizeof (int); 205 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 206 } 207 return (0); 208 } 209 break; 210 211 case DVMRP_INIT: 212 case DVMRP_DONE: 213 case DVMRP_ADD_VIF: 214 case DVMRP_DEL_VIF: 215 case DVMRP_ADD_LGRP: 216 case DVMRP_DEL_LGRP: 217 case DVMRP_ADD_MRT: 218 case DVMRP_DEL_MRT: 219 #ifdef MROUTING 220 if (op == PRCO_SETOPT) { 221 error = ip_mrouter_cmd(optname, so, *m); 222 if (*m) 223 (void)m_free(*m); 224 } else 225 error = EINVAL; 226 return (error); 227 #else 228 if (op == PRCO_SETOPT && *m) 229 (void)m_free(*m); 230 return (EOPNOTSUPP); 231 #endif 232 } 233 return (ip_ctloutput(op, so, level, optname, m)); 234 } 235 236 u_long rip_sendspace = RIPSNDQ; 237 u_long rip_recvspace = RIPRCVQ; 238 239 /*ARGSUSED*/ 240 int 241 rip_usrreq(so, req, m, nam, control) 242 register struct socket *so; 243 int req; 244 struct mbuf *m, *nam, *control; 245 { 246 register int error = 0; 247 register struct inpcb *inp = sotoinpcb(so); 248 #ifdef MROUTING 249 extern struct socket *ip_mrouter; 250 #endif 251 switch (req) { 252 253 case PRU_ATTACH: 254 if (inp) 255 panic("rip_attach"); 256 if ((so->so_state & SS_PRIV) == 0) { 257 error = EACCES; 258 break; 259 } 260 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 261 (error = in_pcballoc(so, &rawinpcb))) 262 break; 263 inp = (struct inpcb *)so->so_pcb; 264 inp->inp_ip.ip_p = (int)nam; 265 break; 266 267 case PRU_DISCONNECT: 268 if ((so->so_state & SS_ISCONNECTED) == 0) { 269 error = ENOTCONN; 270 break; 271 } 272 /* FALLTHROUGH */ 273 case PRU_ABORT: 274 soisdisconnected(so); 275 /* FALLTHROUGH */ 276 case PRU_DETACH: 277 if (inp == 0) 278 panic("rip_detach"); 279 #ifdef MROUTING 280 if (so == ip_mrouter) 281 ip_mrouter_done(); 282 #endif 283 in_pcbdetach(inp); 284 break; 285 286 case PRU_BIND: 287 { 288 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 289 290 if (nam->m_len != sizeof(*addr)) { 291 error = EINVAL; 292 break; 293 } 294 if ((ifnet == 0) || 295 ((addr->sin_family != AF_INET) && 296 (addr->sin_family != AF_IMPLINK)) || 297 (addr->sin_addr.s_addr && 298 ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 299 error = EADDRNOTAVAIL; 300 break; 301 } 302 inp->inp_laddr = addr->sin_addr; 303 break; 304 } 305 case PRU_CONNECT: 306 { 307 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 308 309 if (nam->m_len != sizeof(*addr)) { 310 error = EINVAL; 311 break; 312 } 313 if (ifnet == 0) { 314 error = EADDRNOTAVAIL; 315 break; 316 } 317 if ((addr->sin_family != AF_INET) && 318 (addr->sin_family != AF_IMPLINK)) { 319 error = EAFNOSUPPORT; 320 break; 321 } 322 inp->inp_faddr = addr->sin_addr; 323 soisconnected(so); 324 break; 325 } 326 327 case PRU_CONNECT2: 328 error = EOPNOTSUPP; 329 break; 330 331 /* 332 * Mark the connection as being incapable of further input. 333 */ 334 case PRU_SHUTDOWN: 335 socantsendmore(so); 336 break; 337 338 /* 339 * Ship a packet out. The appropriate raw output 340 * routine handles any massaging necessary. 341 */ 342 case PRU_SEND: 343 { 344 register u_long dst; 345 346 if (so->so_state & SS_ISCONNECTED) { 347 if (nam) { 348 error = EISCONN; 349 break; 350 } 351 dst = inp->inp_faddr.s_addr; 352 } else { 353 if (nam == NULL) { 354 error = ENOTCONN; 355 break; 356 } 357 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 358 } 359 error = rip_output(m, so, dst); 360 m = NULL; 361 break; 362 } 363 364 case PRU_SENSE: 365 /* 366 * stat: don't bother with a blocksize. 367 */ 368 return (0); 369 370 /* 371 * Not supported. 372 */ 373 case PRU_RCVOOB: 374 case PRU_RCVD: 375 case PRU_LISTEN: 376 case PRU_ACCEPT: 377 case PRU_SENDOOB: 378 error = EOPNOTSUPP; 379 break; 380 381 case PRU_SOCKADDR: 382 in_setsockaddr(inp, nam); 383 break; 384 385 case PRU_PEERADDR: 386 in_setpeeraddr(inp, nam); 387 break; 388 389 default: 390 panic("rip_usrreq"); 391 } 392 if (m != NULL) 393 m_freem(m); 394 return (error); 395 } 396