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