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.14 (Berkeley) 06/04/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 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, &ripsrc, 79 n, (struct mbuf *)0) == 0) 80 /* should notify about lost packet */ 81 m_freem(n); 82 else 83 sorwakeup(last); 84 } 85 } 86 last = inp->inp_socket; 87 } 88 if (last) { 89 if (sbappendaddr(&last->so_rcv, &ripsrc, 90 m, (struct mbuf *)0) == 0) 91 m_freem(m); 92 else 93 sorwakeup(last); 94 } else { 95 m_freem(m); 96 ipstat.ips_noproto++; 97 ipstat.ips_delivered--; 98 } 99 } 100 101 /* 102 * Generate IP header and pass packet to ip_output. 103 * Tack on options user may have setup with control call. 104 */ 105 int 106 rip_output(m, so, dst) 107 register struct mbuf *m; 108 struct socket *so; 109 u_long dst; 110 { 111 register struct ip *ip; 112 register struct inpcb *inp = sotoinpcb(so); 113 register struct sockaddr_in *sin; 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 return (EINVAL); 159 160 switch (optname) { 161 162 case IP_HDRINCL: 163 if (op == PRCO_SETOPT || op == PRCO_GETOPT) { 164 if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 165 return (EINVAL); 166 if (op == PRCO_SETOPT) { 167 if (*mtod(*m, int *)) 168 inp->inp_flags |= INP_HDRINCL; 169 else 170 inp->inp_flags &= ~INP_HDRINCL; 171 (void)m_free(*m); 172 } else { 173 (*m)->m_len = sizeof (int); 174 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 175 } 176 return (0); 177 } 178 break; 179 180 case DVMRP_INIT: 181 case DVMRP_DONE: 182 case DVMRP_ADD_VIF: 183 case DVMRP_DEL_VIF: 184 case DVMRP_ADD_LGRP: 185 case DVMRP_DEL_LGRP: 186 case DVMRP_ADD_MRT: 187 case DVMRP_DEL_MRT: 188 #ifdef MROUTING 189 if (op == PRCO_SETOPT) { 190 error = ip_mrouter_cmd(optname, so, *m); 191 if (*m) 192 (void)m_free(*m); 193 } else 194 error = EINVAL; 195 return (error); 196 #else 197 if (op == PRCO_SETOPT && *m) 198 (void)m_free(*m); 199 return (EOPNOTSUPP); 200 #endif 201 } 202 return (ip_ctloutput(op, so, level, optname, m)); 203 } 204 205 u_long rip_sendspace = RIPSNDQ; 206 u_long rip_recvspace = RIPRCVQ; 207 208 /*ARGSUSED*/ 209 int 210 rip_usrreq(so, req, m, nam, control) 211 register struct socket *so; 212 int req; 213 struct mbuf *m, *nam, *control; 214 { 215 register int error = 0; 216 register struct inpcb *inp = sotoinpcb(so); 217 #ifdef MROUTING 218 extern struct socket *ip_mrouter; 219 #endif 220 switch (req) { 221 222 case PRU_ATTACH: 223 if (inp) 224 panic("rip_attach"); 225 if ((so->so_state & SS_PRIV) == 0) { 226 error = EACCES; 227 break; 228 } 229 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 230 (error = in_pcballoc(so, &rawinpcb))) 231 break; 232 inp = (struct inpcb *)so->so_pcb; 233 inp->inp_ip.ip_p = (int)nam; 234 break; 235 236 case PRU_DISCONNECT: 237 if ((so->so_state & SS_ISCONNECTED) == 0) { 238 error = ENOTCONN; 239 break; 240 } 241 /* FALLTHROUGH */ 242 case PRU_ABORT: 243 soisdisconnected(so); 244 /* FALLTHROUGH */ 245 case PRU_DETACH: 246 if (inp == 0) 247 panic("rip_detach"); 248 #ifdef MROUTING 249 if (so == ip_mrouter) 250 ip_mrouter_done(); 251 #endif 252 in_pcbdetach(inp); 253 break; 254 255 case PRU_BIND: 256 { 257 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 258 259 if (nam->m_len != sizeof(*addr)) { 260 error = EINVAL; 261 break; 262 } 263 if ((ifnet == 0) || 264 ((addr->sin_family != AF_INET) && 265 (addr->sin_family != AF_IMPLINK)) || 266 (addr->sin_addr.s_addr && 267 ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 268 error = EADDRNOTAVAIL; 269 break; 270 } 271 inp->inp_laddr = addr->sin_addr; 272 break; 273 } 274 case PRU_CONNECT: 275 { 276 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 277 278 if (nam->m_len != sizeof(*addr)) { 279 error = EINVAL; 280 break; 281 } 282 if (ifnet == 0) { 283 error = EADDRNOTAVAIL; 284 break; 285 } 286 if ((addr->sin_family != AF_INET) && 287 (addr->sin_family != AF_IMPLINK)) { 288 error = EAFNOSUPPORT; 289 break; 290 } 291 inp->inp_faddr = addr->sin_addr; 292 soisconnected(so); 293 break; 294 } 295 296 case PRU_CONNECT2: 297 error = EOPNOTSUPP; 298 break; 299 300 /* 301 * Mark the connection as being incapable of further input. 302 */ 303 case PRU_SHUTDOWN: 304 socantsendmore(so); 305 break; 306 307 /* 308 * Ship a packet out. The appropriate raw output 309 * routine handles any massaging necessary. 310 */ 311 case PRU_SEND: 312 { 313 register u_long dst; 314 315 if (so->so_state & SS_ISCONNECTED) { 316 if (nam) { 317 error = EISCONN; 318 break; 319 } 320 dst = inp->inp_faddr.s_addr; 321 } else { 322 if (nam == NULL) { 323 error = ENOTCONN; 324 break; 325 } 326 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 327 } 328 error = rip_output(m, so, dst); 329 m = NULL; 330 break; 331 } 332 333 case PRU_SENSE: 334 /* 335 * stat: don't bother with a blocksize. 336 */ 337 return (0); 338 339 /* 340 * Not supported. 341 */ 342 case PRU_RCVOOB: 343 case PRU_RCVD: 344 case PRU_LISTEN: 345 case PRU_ACCEPT: 346 case PRU_SENDOOB: 347 error = EOPNOTSUPP; 348 break; 349 350 case PRU_SOCKADDR: 351 in_setsockaddr(inp, nam); 352 break; 353 354 case PRU_PEERADDR: 355 in_setpeeraddr(inp, nam); 356 break; 357 358 default: 359 panic("rip_usrreq"); 360 } 361 if (m != NULL) 362 m_freem(m); 363 return (error); 364 } 365