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