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