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