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