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