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