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.5 (Berkeley) 02/09/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 (m != 0 && *m != 0) 159 (void)m_free(*m); 160 return (EINVAL); 161 } 162 163 switch (optname) { 164 165 case IP_HDRINCL: 166 if (op == PRCO_SETOPT || op == PRCO_GETOPT) { 167 if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 168 return (EINVAL); 169 if (op == PRCO_SETOPT) { 170 if (*mtod(*m, int *)) 171 inp->inp_flags |= INP_HDRINCL; 172 else 173 inp->inp_flags &= ~INP_HDRINCL; 174 (void)m_free(*m); 175 } else { 176 (*m)->m_len = sizeof (int); 177 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 178 } 179 return (0); 180 } 181 break; 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 return (ip_ctloutput(op, so, level, optname, m)); 206 } 207 208 u_long rip_sendspace = RIPSNDQ; 209 u_long rip_recvspace = RIPRCVQ; 210 211 /*ARGSUSED*/ 212 int 213 rip_usrreq(so, req, m, nam, control) 214 register struct socket *so; 215 int req; 216 struct mbuf *m, *nam, *control; 217 { 218 register int error = 0; 219 register struct inpcb *inp = sotoinpcb(so); 220 #ifdef MROUTING 221 extern struct socket *ip_mrouter; 222 #endif 223 switch (req) { 224 225 case PRU_ATTACH: 226 if (inp) 227 panic("rip_attach"); 228 if ((so->so_state & SS_PRIV) == 0) { 229 error = EACCES; 230 break; 231 } 232 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 233 (error = in_pcballoc(so, &rawinpcb))) 234 break; 235 inp = (struct inpcb *)so->so_pcb; 236 inp->inp_ip.ip_p = (int)nam; 237 break; 238 239 case PRU_DISCONNECT: 240 if ((so->so_state & SS_ISCONNECTED) == 0) { 241 error = ENOTCONN; 242 break; 243 } 244 /* FALLTHROUGH */ 245 case PRU_ABORT: 246 soisdisconnected(so); 247 /* FALLTHROUGH */ 248 case PRU_DETACH: 249 if (inp == 0) 250 panic("rip_detach"); 251 #ifdef MROUTING 252 if (so == ip_mrouter) 253 ip_mrouter_done(); 254 #endif 255 in_pcbdetach(inp); 256 break; 257 258 case PRU_BIND: 259 { 260 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 261 262 if (nam->m_len != sizeof(*addr)) { 263 error = EINVAL; 264 break; 265 } 266 if ((ifnet == 0) || 267 ((addr->sin_family != AF_INET) && 268 (addr->sin_family != AF_IMPLINK)) || 269 (addr->sin_addr.s_addr && 270 ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 271 error = EADDRNOTAVAIL; 272 break; 273 } 274 inp->inp_laddr = addr->sin_addr; 275 break; 276 } 277 case PRU_CONNECT: 278 { 279 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 280 281 if (nam->m_len != sizeof(*addr)) { 282 error = EINVAL; 283 break; 284 } 285 if (ifnet == 0) { 286 error = EADDRNOTAVAIL; 287 break; 288 } 289 if ((addr->sin_family != AF_INET) && 290 (addr->sin_family != AF_IMPLINK)) { 291 error = EAFNOSUPPORT; 292 break; 293 } 294 inp->inp_faddr = addr->sin_addr; 295 soisconnected(so); 296 break; 297 } 298 299 case PRU_CONNECT2: 300 error = EOPNOTSUPP; 301 break; 302 303 /* 304 * Mark the connection as being incapable of further input. 305 */ 306 case PRU_SHUTDOWN: 307 socantsendmore(so); 308 break; 309 310 /* 311 * Ship a packet out. The appropriate raw output 312 * routine handles any massaging necessary. 313 */ 314 case PRU_SEND: 315 { 316 register u_long dst; 317 318 if (so->so_state & SS_ISCONNECTED) { 319 if (nam) { 320 error = EISCONN; 321 break; 322 } 323 dst = inp->inp_faddr.s_addr; 324 } else { 325 if (nam == NULL) { 326 error = ENOTCONN; 327 break; 328 } 329 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 330 } 331 error = rip_output(m, so, dst); 332 m = NULL; 333 break; 334 } 335 336 case PRU_SENSE: 337 /* 338 * stat: don't bother with a blocksize. 339 */ 340 return (0); 341 342 /* 343 * Not supported. 344 */ 345 case PRU_RCVOOB: 346 case PRU_RCVD: 347 case PRU_LISTEN: 348 case PRU_ACCEPT: 349 case PRU_SENDOOB: 350 error = EOPNOTSUPP; 351 break; 352 353 case PRU_SOCKADDR: 354 in_setsockaddr(inp, nam); 355 break; 356 357 case PRU_PEERADDR: 358 in_setpeeraddr(inp, nam); 359 break; 360 361 default: 362 panic("rip_usrreq"); 363 } 364 if (m != NULL) 365 m_freem(m); 366 return (error); 367 } 368