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.13 (Berkeley) 04/09/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 ip = mtod(m, struct ip *); 131 if (ip->ip_id == 0) 132 ip->ip_id = htons(ip_id++); 133 opts = NULL; 134 /* XXX prevent ip_output from overwriting header fields */ 135 flags |= IP_RAWOUTPUT; 136 ipstat.ips_rawout++; 137 } 138 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions)); 139 } 140 141 /* 142 * Raw IP socket option processing. 143 */ 144 rip_ctloutput(op, so, level, optname, m) 145 int op; 146 struct socket *so; 147 int level, optname; 148 struct mbuf **m; 149 { 150 register struct inpcb *inp = sotoinpcb(so); 151 register int error; 152 153 if (level != IPPROTO_IP) 154 return (EINVAL); 155 156 switch (optname) { 157 158 case IP_HDRINCL: 159 if (op == PRCO_SETOPT || op == PRCO_GETOPT) { 160 if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 161 return (EINVAL); 162 if (op == PRCO_SETOPT) { 163 if (*mtod(*m, int *)) 164 inp->inp_flags |= INP_HDRINCL; 165 else 166 inp->inp_flags &= ~INP_HDRINCL; 167 (void)m_free(*m); 168 } else { 169 (*m)->m_len = sizeof (int); 170 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 171 } 172 return (0); 173 } 174 break; 175 176 case DVMRP_INIT: 177 case DVMRP_DONE: 178 case DVMRP_ADD_VIF: 179 case DVMRP_DEL_VIF: 180 case DVMRP_ADD_LGRP: 181 case DVMRP_DEL_LGRP: 182 case DVMRP_ADD_MRT: 183 case DVMRP_DEL_MRT: 184 #ifdef MROUTING 185 if (op == PRCO_SETOPT) { 186 error = ip_mrouter_cmd(optname, so, *m); 187 if (*m) 188 (void)m_free(*m); 189 } else 190 error = EINVAL; 191 return (error); 192 #else 193 if (op == PRCO_SETOPT && *m) 194 (void)m_free(*m); 195 return (EOPNOTSUPP); 196 #endif 197 } 198 return (ip_ctloutput(op, so, level, optname, m)); 199 } 200 201 u_long rip_sendspace = RIPSNDQ; 202 u_long rip_recvspace = RIPRCVQ; 203 204 /*ARGSUSED*/ 205 rip_usrreq(so, req, m, nam, control) 206 register struct socket *so; 207 int req; 208 struct mbuf *m, *nam, *control; 209 { 210 register int error = 0; 211 register struct inpcb *inp = sotoinpcb(so); 212 #ifdef MROUTING 213 extern struct socket *ip_mrouter; 214 #endif 215 216 switch (req) { 217 218 case PRU_ATTACH: 219 if (inp) 220 panic("rip_attach"); 221 if ((so->so_state & SS_PRIV) == 0) { 222 error = EACCES; 223 break; 224 } 225 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 226 (error = in_pcballoc(so, &rawinpcb))) 227 break; 228 inp = (struct inpcb *)so->so_pcb; 229 inp->inp_ip.ip_p = (int)nam; 230 break; 231 232 case PRU_DISCONNECT: 233 if ((so->so_state & SS_ISCONNECTED) == 0) { 234 error = ENOTCONN; 235 break; 236 } 237 /* FALLTHROUGH */ 238 case PRU_ABORT: 239 soisdisconnected(so); 240 /* FALLTHROUGH */ 241 case PRU_DETACH: 242 if (inp == 0) 243 panic("rip_detach"); 244 #ifdef MROUTING 245 if (so == ip_mrouter) 246 ip_mrouter_done(); 247 #endif 248 in_pcbdetach(inp); 249 break; 250 251 case PRU_BIND: 252 { 253 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 254 255 if (nam->m_len != sizeof(*addr)) { 256 error = EINVAL; 257 break; 258 } 259 if ((ifnet == 0) || 260 ((addr->sin_family != AF_INET) && 261 (addr->sin_family != AF_IMPLINK)) || 262 (addr->sin_addr.s_addr && 263 ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 264 error = EADDRNOTAVAIL; 265 break; 266 } 267 inp->inp_laddr = addr->sin_addr; 268 break; 269 } 270 case PRU_CONNECT: 271 { 272 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 273 274 if (nam->m_len != sizeof(*addr)) { 275 error = EINVAL; 276 break; 277 } 278 if (ifnet == 0) { 279 error = EADDRNOTAVAIL; 280 break; 281 } 282 if ((addr->sin_family != AF_INET) && 283 (addr->sin_family != AF_IMPLINK)) { 284 error = EAFNOSUPPORT; 285 break; 286 } 287 inp->inp_faddr = addr->sin_addr; 288 soisconnected(so); 289 break; 290 } 291 292 case PRU_CONNECT2: 293 error = EOPNOTSUPP; 294 break; 295 296 /* 297 * Mark the connection as being incapable of further input. 298 */ 299 case PRU_SHUTDOWN: 300 socantsendmore(so); 301 break; 302 303 /* 304 * Ship a packet out. The appropriate raw output 305 * routine handles any massaging necessary. 306 */ 307 case PRU_SEND: 308 { 309 register u_long dst; 310 311 if (so->so_state & SS_ISCONNECTED) { 312 if (nam) { 313 error = EISCONN; 314 break; 315 } 316 dst = inp->inp_faddr.s_addr; 317 } else { 318 if (nam == NULL) { 319 error = ENOTCONN; 320 break; 321 } 322 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 323 } 324 error = rip_output(m, so, dst); 325 m = NULL; 326 break; 327 } 328 329 case PRU_SENSE: 330 /* 331 * stat: don't bother with a blocksize. 332 */ 333 return (0); 334 335 /* 336 * Not supported. 337 */ 338 case PRU_RCVOOB: 339 case PRU_RCVD: 340 case PRU_LISTEN: 341 case PRU_ACCEPT: 342 case PRU_SENDOOB: 343 error = EOPNOTSUPP; 344 break; 345 346 case PRU_SOCKADDR: 347 in_setsockaddr(inp, nam); 348 break; 349 350 case PRU_PEERADDR: 351 in_setpeeraddr(inp, nam); 352 break; 353 354 default: 355 panic("rip_usrreq"); 356 } 357 if (m != NULL) 358 m_freem(m); 359 return (error); 360 } 361