- Uncomment some SYN handling code
[reactos.git] / reactos / lib / drivers / oskittcp / oskittcp / ip_output.c
1 /*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/malloc.h>
39 #include <sys/mbuf.h>
40 #include <sys/errno.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/queue.h>
45
46 #include <net/if.h>
47 #include <net/route.h>
48
49 #include <netinet/in.h>
50 #include <netinet/in_systm.h>
51 #include <netinet/ip.h>
52 #include <netinet/in_pcb.h>
53 #include <netinet/in_var.h>
54 #include <netinet/ip_var.h>
55
56 #include <netinet/ip_fw.h>
57
58 #ifdef vax
59 #include <machine/mtpr.h>
60 #endif
61 #include <oskittcp.h>
62
63 u_short ip_id;
64
65 static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
66 #ifndef __REACTOS__
67 static void ip_mloopback
68 __P((struct ifnet *, struct mbuf *, struct sockaddr_in *));
69 #endif
70
71 /*
72 * IP output. The packet in mbuf chain m contains a skeletal IP
73 * header (with len, off, ttl, proto, tos, src, dst).
74 * The mbuf chain containing the packet will be freed.
75 * The mbuf opt, if present, will not be freed.
76 */
77 int
78 ip_output(m0, opt, ro, flags, imo)
79 struct mbuf *m0;
80 struct mbuf *opt;
81 struct route *ro;
82 int flags;
83 struct ip_moptions *imo;
84 {
85 register struct ip *ip, *mhip;
86 #ifndef __REACTOS__
87 register struct ifnet *ifp;
88 #endif
89 register struct mbuf *m = m0;
90 register int hlen = sizeof (struct ip);
91 int len = 0, off, error = 0;
92 /*
93 * It might seem obvious at first glance that one could easily
94 * make a one-behind cache out of this by simply making `iproute'
95 * static and eliminating the bzero() below. However, this turns
96 * out not to work, for two reasons:
97 *
98 * 1) This routine needs to be reentrant. It can be called
99 * recursively from encapsulating network interfaces, and it
100 * is always called recursively from ip_mforward().
101 *
102 * 2) You turn out not to gain much. There is already a one-
103 * behind cache implemented for the specific case of forwarding,
104 * and sends on a connected socket will use a route associated
105 * with the PCB. The only cases left are sends on unconnected
106 * and raw sockets, and if these cases are really significant,
107 * something is seriously wrong.
108 */
109 struct route iproute;
110 struct sockaddr_in *dst;
111 struct in_ifaddr *ia = NULL;
112
113 #ifdef DIAGNOSTIC
114 if ((m->m_flags & M_PKTHDR) == 0)
115 panic("ip_output no HDR");
116 #endif
117 if (opt) {
118 m = ip_insertoptions(m, opt, &len);
119 hlen = len;
120 }
121 ip = mtod(m, struct ip *);
122 /*
123 * Fill in IP header.
124 */
125 if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) {
126 ip->ip_v = IPVERSION;
127 ip->ip_off &= IP_DF;
128 ip->ip_id = htons(ip_id++);
129 ip->ip_hl = hlen >> 2;
130 ipstat.ips_localout++;
131 } else {
132 hlen = ip->ip_hl << 2;
133 }
134 /*
135 * Route packet.
136 */
137 if (ro == 0) {
138 ro = &iproute;
139 bzero((caddr_t)ro, sizeof (*ro));
140 }
141 dst = (struct sockaddr_in *)&ro->ro_dst;
142 /*
143 * If there is a cached route,
144 * check that it is to the same destination
145 * and is still up. If not, free it and try again.
146 */
147 if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
148 dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
149 RTFREE(ro->ro_rt);
150 ro->ro_rt = (struct rtentry *)0;
151 }
152 if (ro->ro_rt == 0) {
153 dst->sin_family = AF_INET;
154 dst->sin_len = sizeof(*dst);
155 dst->sin_addr = ip->ip_dst;
156 }
157 /*
158 * If routing to interface only,
159 * short circuit routing lookup.
160 */
161 #define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
162 #define sintosa(sin) ((struct sockaddr *)(sin))
163 if (flags & IP_ROUTETOIF) {
164 if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
165 (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
166 ipstat.ips_noroute++;
167 error = ENETUNREACH;
168 goto bad;
169 }
170 #ifndef __REACTOS__
171 ifp = ia->ia_ifp;
172 #endif
173 ip->ip_ttl = 1;
174 } else {
175 /*
176 * If this is the case, we probably don't want to allocate
177 * a protocol-cloned route since we didn't get one from the
178 * ULP. This lets TCP do its thing, while not burdening
179 * forwarding or ICMP with the overhead of cloning a route.
180 * Of course, we still want to do any cloning requested by
181 * the link layer, as this is probably required in all cases
182 * for correct operation (as it is for ARP).
183 */
184 #ifndef __REACTOS__
185 if (ro->ro_rt == 0)
186 rtalloc_ign(ro, RTF_PRCLONING);
187 if (ro->ro_rt == 0) {
188 ipstat.ips_noroute++;
189 OS_DbgPrint(OSK_MID_TRACE,("EHOSTUNREACH\n"));
190 error = EHOSTUNREACH;
191 goto bad;
192 }
193 ia = ifatoia(ro->ro_rt->rt_ifa);
194 ifp = ro->ro_rt->rt_ifp;
195 ro->ro_rt->rt_use++;
196 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
197 dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway;
198 #endif
199 }
200 #ifndef __REACTOS__
201 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
202 struct in_multi *inm;
203
204 m->m_flags |= M_MCAST;
205 /*
206 * IP destination address is multicast. Make sure "dst"
207 * still points to the address in "ro". (It may have been
208 * changed to point to a gateway address, above.)
209 */
210 dst = (struct sockaddr_in *)&ro->ro_dst;
211 /*
212 * See if the caller provided any multicast options
213 */
214 if (imo != NULL) {
215 ip->ip_ttl = imo->imo_multicast_ttl;
216 if (imo->imo_multicast_ifp != NULL)
217 ifp = imo->imo_multicast_ifp;
218 if (imo->imo_multicast_vif != -1)
219 ip->ip_src.s_addr =
220 ip_mcast_src(imo->imo_multicast_vif);
221 } else
222 ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
223 /*
224 * Confirm that the outgoing interface supports multicast.
225 */
226 if ((imo == NULL) || (imo->imo_multicast_vif == -1)) {
227 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
228 ipstat.ips_noroute++;
229 error = ENETUNREACH;
230 goto bad;
231 }
232 }
233 /*
234 * If source address not specified yet, use address
235 * of outgoing interface.
236 */
237 if (ip->ip_src.s_addr == INADDR_ANY) {
238 register struct in_ifaddr *ia;
239
240 panic("We don't handle this yet\n");
241 for (ia = in_ifaddr; ia; ia = ia->ia_next)
242 if (ia->ia_ifp == ifp) {
243 ip->ip_src = IA_SIN(ia)->sin_addr;
244 break;
245 }
246 }
247
248 IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
249 if (inm != NULL &&
250 (imo == NULL || imo->imo_multicast_loop)) {
251 /*
252 * If we belong to the destination multicast group
253 * on the outgoing interface, and the caller did not
254 * forbid loopback, loop back a copy.
255 */
256 ip_mloopback(ifp, m, dst);
257 }
258 else {
259 /*
260 * If we are acting as a multicast router, perform
261 * multicast forwarding as if the packet had just
262 * arrived on the interface to which we are about
263 * to send. The multicast forwarding function
264 * recursively calls this function, using the
265 * IP_FORWARDING flag to prevent infinite recursion.
266 *
267 * Multicasts that are looped back by ip_mloopback(),
268 * above, will be forwarded by the ip_input() routine,
269 * if necessary.
270 */
271 if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
272 /*
273 * Check if rsvp daemon is running. If not, don't
274 * set ip_moptions. This ensures that the packet
275 * is multicast and not just sent down one link
276 * as prescribed by rsvpd.
277 */
278 if (!rsvp_on)
279 imo = NULL;
280 if (ip_mforward(ip, ifp, m, imo) != 0) {
281 m_freem(m);
282 goto done;
283 }
284 }
285 }
286
287 /*
288 * Multicasts with a time-to-live of zero may be looped-
289 * back, above, but must not be transmitted on a network.
290 * Also, multicasts addressed to the loopback interface
291 * are not sent -- the above call to ip_mloopback() will
292 * loop back a copy if this host actually belongs to the
293 * destination group on the loopback interface.
294 */
295 if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) {
296 m_freem(m);
297 goto done;
298 }
299
300 goto sendit;
301 }
302 #endif
303
304 #ifdef __REACTOS__
305 /*
306 * If source address not specified yet, use address
307 * of outgoing interface.
308 */
309 if (ip->ip_src.s_addr == INADDR_ANY)
310 ip->ip_src = IA_SIN(ia)->sin_addr;
311 #endif
312 #ifndef __REACTOS__
313 /*
314 * Verify that we have any chance at all of being able to queue
315 * the packet or packet fragments
316 */
317 if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >=
318 ifp->if_snd.ifq_maxlen) {
319 error = ENOBUFS;
320 goto bad;
321 }
322
323 /*
324 * Look for broadcast address and
325 * and verify user is allowed to send
326 * such a packet.
327 */
328 if (in_broadcast(dst->sin_addr, ifp)) {
329 if ((ifp->if_flags & IFF_BROADCAST) == 0) {
330 error = EADDRNOTAVAIL;
331 goto bad;
332 }
333 if ((flags & IP_ALLOWBROADCAST) == 0) {
334 error = EACCES;
335 goto bad;
336 }
337 /* don't allow broadcast messages to be fragmented */
338 if ((u_short)ip->ip_len > ifp->if_mtu) {
339 error = EMSGSIZE;
340 goto bad;
341 }
342 m->m_flags |= M_BCAST;
343 } else
344 m->m_flags &= ~M_BCAST;
345 #endif
346
347 #ifndef __REACTOS__
348 sendit:
349 /*
350 * Check with the firewall...
351 */
352 if (!(*ip_fw_chk_ptr)(m,ip,ifp,1)) {
353 error = EACCES;
354 goto done;
355 }
356 #endif
357
358 /*
359 * If small enough for interface, can just send directly.
360 */
361 if ((u_short)ip->ip_len <= 1400 /* XXX Get MTU from Interface */) {
362 ip->ip_len = htons((u_short)ip->ip_len);
363 ip->ip_off = htons((u_short)ip->ip_off);
364 ip->ip_sum = 0;
365 ip->ip_sum = in_cksum(m, hlen);
366 #ifdef __REACTOS__
367 if( OtcpEvent.PacketSend ) {
368 struct mbuf *new_m;
369 new_m = m_get( M_DONTWAIT, 0 );
370 if ( NULL == new_m ) {
371 error = ENOBUFS;
372 goto done;
373 }
374 MCLGET( new_m, M_DONTWAIT );
375 if (0 == (new_m->m_flags & M_EXT)) {
376 m_free( new_m );
377 error = ENOBUFS;
378 goto done;
379 }
380 m_copydata( m, 0, htons(ip->ip_len), new_m->m_data );
381 new_m->m_len = htons(ip->ip_len);
382 error = OtcpEvent.PacketSend( OtcpEvent.ClientData,
383 (OSK_PCHAR)new_m->m_data, new_m->m_len );
384 m_free( new_m );
385 goto done;
386 }
387 #else
388 error = (*ifp->if_output)(ifp, m,
389 (struct sockaddr *)dst, ro->ro_rt);
390 #endif
391 }
392 /*
393 * Too large for interface; fragment if possible.
394 * Must be able to put at least 8 bytes per fragment.
395 */
396 if (ip->ip_off & IP_DF) {
397 error = EMSGSIZE;
398 #ifndef __REACTOS__
399 #if 1
400 /*
401 * This case can happen if the user changed the MTU
402 * of an interface after enabling IP on it. Because
403 * most netifs don't keep track of routes pointing to
404 * them, there is no way for one to update all its
405 * routes when the MTU is changed.
406 */
407 if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST))
408 && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU)
409 && (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) {
410 ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
411 }
412 #endif
413 #endif
414 ipstat.ips_cantfrag++;
415 goto bad;
416 }
417 #ifndef __REACTOS__
418 len = (ifp->if_mtu - hlen) &~ 7;
419 if (len < 8) {
420 error = EMSGSIZE;
421 goto bad;
422 }
423 #else
424 OS_DbgPrint(OSK_MID_TRACE,("Using default mtu of 1500\n"));
425 len = (1500 - hlen) & ~7;
426 #endif
427
428 {
429 int mhlen, firstlen = len;
430 struct mbuf **mnext = &m->m_nextpkt;
431
432 /*
433 * Loop through length of segment after first fragment,
434 * make new header and copy data of each part and link onto chain.
435 */
436 m0 = m;
437 mhlen = sizeof (struct ip);
438 for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
439 OS_DbgPrint(OSK_MID_TRACE,("off = %d, len = %d\n", off, len));
440 MGETHDR(m, M_DONTWAIT, MT_HEADER);
441 if (m == 0) {
442 error = ENOBUFS;
443 ipstat.ips_odropped++;
444 goto sendorfree;
445 }
446 m->m_data += max_linkhdr;
447 mhip = mtod(m, struct ip *);
448 *mhip = *ip;
449 if (hlen > sizeof (struct ip)) {
450 mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
451 mhip->ip_hl = mhlen >> 2;
452 }
453 m->m_len = mhlen;
454 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
455 if (ip->ip_off & IP_MF)
456 mhip->ip_off |= IP_MF;
457 if (off + len >= (u_short)ip->ip_len)
458 len = (u_short)ip->ip_len - off;
459 else
460 mhip->ip_off |= IP_MF;
461 mhip->ip_len = htons((u_short)(len + mhlen));
462 m->m_next = m_copy(m0, off, len);
463 if (m->m_next == 0) {
464 (void) m_free(m);
465 error = ENOBUFS; /* ??? */
466 ipstat.ips_odropped++;
467 goto sendorfree;
468 }
469 m->m_pkthdr.len = mhlen + len;
470 m->m_pkthdr.rcvif = (struct ifnet *)0;
471 mhip->ip_off = htons((u_short)mhip->ip_off);
472 mhip->ip_sum = 0;
473 mhip->ip_sum = in_cksum(m, mhlen);
474 *mnext = m;
475 mnext = &m->m_nextpkt;
476 ipstat.ips_ofragments++;
477 }
478 /*
479 * Update first fragment by trimming what's been copied out
480 * and updating header, then send each fragment (in order).
481 */
482 m = m0;
483 OS_DbgPrint(OSK_MID_TRACE,("hlen %d firstlen %d ip->ip_len %x\n",
484 hlen, firstlen, ip->ip_len));
485 OS_DbgPrint(OSK_MID_TRACE,("hlen + firstlen - ip->ip_len %d\n",
486 hlen + firstlen - (u_short)ip->ip_len));
487 m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
488 m->m_pkthdr.len = hlen + firstlen;
489 ip->ip_len = htons((u_short)(m->m_pkthdr.len));
490 ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
491 ip->ip_sum = 0;
492 ip->ip_sum = in_cksum(m, hlen - sizeof( struct ip ) );
493
494 OS_DbgPrint(OSK_MID_TRACE,("ip->ip_len = %x\n", ip->ip_len));
495
496 sendorfree:
497 for (m = m0; m; m = m0) {
498 m0 = m->m_nextpkt;
499 m->m_nextpkt = 0;
500 #ifndef __REACTOS__
501 if (error == 0)
502 error = (*ifp->if_output)(ifp, m,
503 (struct sockaddr *)dst, ro->ro_rt);
504 else
505 m_freem(m);
506 #else
507 if( error == 0 && OtcpEvent.PacketSend ) {
508 struct mbuf *new_m;
509 MGET( new_m, M_DONTWAIT, 0 );
510 if ( NULL == new_m ) {
511 error = ENOBUFS;
512 goto done;
513 }
514 MCLGET( new_m, M_DONTWAIT );
515 if (0 == (new_m->m_flags & M_EXT)) {
516 m_free( new_m );
517 error = ENOBUFS;
518 goto done;
519 }
520 m_copydata( m, 0, htons(ip->ip_len), new_m->m_data );
521 new_m->m_len = htons(ip->ip_len);
522 error = OtcpEvent.PacketSend( OtcpEvent.ClientData,
523 (OSK_PCHAR)new_m->m_data, new_m->m_len );
524 m_free( new_m );
525 }
526
527 OS_DbgPrint(OSK_MID_TRACE,("Error from upper layer: %d\n", error));
528 #endif
529 }
530
531 if (error == 0)
532 ipstat.ips_fragmented++;
533 }
534 done:
535 if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) {
536 RTFREE(ro->ro_rt);
537 }
538
539 return (error);
540 bad:
541 m_freem(m0);
542 goto done;
543 }
544
545 /*
546 * Insert IP options into preformed packet.
547 * Adjust IP destination as required for IP source routing,
548 * as indicated by a non-zero in_addr at the start of the options.
549 *
550 * XXX This routine assumes that the packet has no options in place.
551 */
552 static struct mbuf *
553 ip_insertoptions(m, opt, phlen)
554 register struct mbuf *m;
555 struct mbuf *opt;
556 int *phlen;
557 {
558 register struct ipoption *p = mtod(opt, struct ipoption *);
559 struct mbuf *n;
560 register struct ip *ip = mtod(m, struct ip *);
561 unsigned optlen;
562
563 optlen = opt->m_len - sizeof(p->ipopt_dst);
564 if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
565 return (m); /* XXX should fail */
566 if (p->ipopt_dst.s_addr)
567 ip->ip_dst = p->ipopt_dst;
568 if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
569 MGETHDR(n, M_DONTWAIT, MT_HEADER);
570 if (n == 0)
571 return (m);
572 n->m_pkthdr.len = m->m_pkthdr.len + optlen;
573 m->m_len -= sizeof(struct ip);
574 m->m_data += sizeof(struct ip);
575 n->m_next = m;
576 m = n;
577 m->m_len = optlen + sizeof(struct ip);
578 m->m_data += max_linkhdr;
579 (void)memcpy(mtod(m, void *), ip, sizeof(struct ip));
580 } else {
581 m->m_data -= optlen;
582 m->m_len += optlen;
583 m->m_pkthdr.len += optlen;
584 ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
585 }
586 ip = mtod(m, struct ip *);
587 (void)memcpy(ip + 1, p->ipopt_list, (unsigned)optlen);
588 *phlen = sizeof(struct ip) + optlen;
589 ip->ip_hl = *phlen >> 2;
590 ip->ip_len += optlen;
591 return (m);
592 }
593
594 /*
595 * Copy options from ip to jp,
596 * omitting those not copied during fragmentation.
597 */
598 int
599 ip_optcopy(ip, jp)
600 struct ip *ip, *jp;
601 {
602 register u_char *cp, *dp;
603 int opt, optlen, cnt;
604
605 cp = (u_char *)(ip + 1);
606 dp = (u_char *)(jp + 1);
607 cnt = (ip->ip_hl << 2) - sizeof (struct ip);
608 for (; cnt > 0; cnt -= optlen, cp += optlen) {
609 opt = cp[0];
610 if (opt == IPOPT_EOL)
611 break;
612 if (opt == IPOPT_NOP) {
613 /* Preserve for IP mcast tunnel's LSRR alignment. */
614 *dp++ = IPOPT_NOP;
615 optlen = 1;
616 continue;
617 } else
618 optlen = cp[IPOPT_OLEN];
619 /* bogus lengths should have been caught by ip_dooptions */
620 if (optlen > cnt)
621 optlen = cnt;
622 if (IPOPT_COPIED(opt)) {
623 (void)memcpy(dp, cp, (unsigned)optlen);
624 dp += optlen;
625 }
626 }
627 for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
628 *dp++ = IPOPT_EOL;
629 return (optlen);
630 }
631
632 /*
633 * IP socket option processing.
634 */
635 int
636 ip_ctloutput(op, so, level, optname, mp)
637 int op;
638 struct socket *so;
639 int level, optname;
640 struct mbuf **mp;
641 {
642 register struct inpcb *inp = sotoinpcb(so);
643 register struct mbuf *m = *mp;
644 register int optval = 0;
645 int error = 0;
646
647 if (level != IPPROTO_IP) {
648 error = EINVAL;
649 if (op == PRCO_SETOPT && *mp)
650 (void) m_free(*mp);
651 } else switch (op) {
652
653 case PRCO_SETOPT:
654 switch (optname) {
655 case IP_OPTIONS:
656 #ifdef notyet
657 case IP_RETOPTS:
658 return (ip_pcbopts(optname, &inp->inp_options, m));
659 #else
660 return (ip_pcbopts(&inp->inp_options, m));
661 #endif
662
663 case IP_TOS:
664 case IP_TTL:
665 case IP_RECVOPTS:
666 case IP_RECVRETOPTS:
667 case IP_RECVDSTADDR:
668 if (m == 0 || m->m_len != sizeof(int))
669 error = EINVAL;
670 else {
671 optval = *mtod(m, int *);
672 switch (optname) {
673
674 case IP_TOS:
675 inp->inp_ip.ip_tos = optval;
676 break;
677
678 case IP_TTL:
679 inp->inp_ip.ip_ttl = optval;
680 break;
681 #define OPTSET(bit) \
682 if (optval) \
683 inp->inp_flags |= bit; \
684 else \
685 inp->inp_flags &= ~bit;
686
687 case IP_RECVOPTS:
688 OPTSET(INP_RECVOPTS);
689 break;
690
691 case IP_RECVRETOPTS:
692 OPTSET(INP_RECVRETOPTS);
693 break;
694
695 case IP_RECVDSTADDR:
696 OPTSET(INP_RECVDSTADDR);
697 break;
698 }
699 }
700 break;
701 #undef OPTSET
702
703 case IP_MULTICAST_IF:
704 case IP_MULTICAST_VIF:
705 case IP_MULTICAST_TTL:
706 case IP_MULTICAST_LOOP:
707 case IP_ADD_MEMBERSHIP:
708 case IP_DROP_MEMBERSHIP:
709 error = ip_setmoptions(optname, &inp->inp_moptions, m);
710 break;
711
712 default:
713 error = ENOPROTOOPT;
714 break;
715 }
716 if (m)
717 (void)m_free(m);
718 break;
719
720 case PRCO_GETOPT:
721 switch (optname) {
722 case IP_OPTIONS:
723 case IP_RETOPTS:
724 *mp = m = m_get(M_WAIT, MT_SOOPTS);
725 if (inp->inp_options) {
726 m->m_len = inp->inp_options->m_len;
727 (void)memcpy(mtod(m, void *),
728 mtod(inp->inp_options, void *), (unsigned)m->m_len);
729 } else
730 m->m_len = 0;
731 break;
732
733 case IP_TOS:
734 case IP_TTL:
735 case IP_RECVOPTS:
736 case IP_RECVRETOPTS:
737 case IP_RECVDSTADDR:
738 *mp = m = m_get(M_WAIT, MT_SOOPTS);
739 m->m_len = sizeof(int);
740 switch (optname) {
741
742 case IP_TOS:
743 optval = inp->inp_ip.ip_tos;
744 break;
745
746 case IP_TTL:
747 optval = inp->inp_ip.ip_ttl;
748 break;
749
750 #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0)
751
752 case IP_RECVOPTS:
753 optval = OPTBIT(INP_RECVOPTS);
754 break;
755
756 case IP_RECVRETOPTS:
757 optval = OPTBIT(INP_RECVRETOPTS);
758 break;
759
760 case IP_RECVDSTADDR:
761 optval = OPTBIT(INP_RECVDSTADDR);
762 break;
763 }
764 *mtod(m, int *) = optval;
765 break;
766
767 case IP_MULTICAST_IF:
768 case IP_MULTICAST_VIF:
769 case IP_MULTICAST_TTL:
770 case IP_MULTICAST_LOOP:
771 case IP_ADD_MEMBERSHIP:
772 case IP_DROP_MEMBERSHIP:
773 error = ip_getmoptions(optname, inp->inp_moptions, mp);
774 break;
775
776 default:
777 error = ENOPROTOOPT;
778 break;
779 }
780 break;
781 }
782 return (error);
783 }
784
785 /*
786 * Set up IP options in pcb for insertion in output packets.
787 * Store in mbuf with pointer in pcbopt, adding pseudo-option
788 * with destination address if source routed.
789 */
790 int
791 #ifdef notyet
792 ip_pcbopts(optname, pcbopt, m)
793 int optname;
794 #else
795 ip_pcbopts(pcbopt, m)
796 #endif
797 struct mbuf **pcbopt;
798 register struct mbuf *m;
799 {
800 register int cnt, optlen;
801 register u_char *cp;
802 u_char opt;
803
804 /* turn off any old options */
805 if (*pcbopt)
806 (void)m_free(*pcbopt);
807 *pcbopt = 0;
808 if (m == (struct mbuf *)0 || m->m_len == 0) {
809 /*
810 * Only turning off any previous options.
811 */
812 if (m)
813 (void)m_free(m);
814 return (0);
815 }
816
817 #ifndef vax
818 if (m->m_len % sizeof(long))
819 goto bad;
820 #endif
821 /*
822 * IP first-hop destination address will be stored before
823 * actual options; move other options back
824 * and clear it when none present.
825 */
826 if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
827 goto bad;
828 cnt = m->m_len;
829 m->m_len += sizeof(struct in_addr);
830 cp = mtod(m, u_char *) + sizeof(struct in_addr);
831 ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
832 bzero(mtod(m, caddr_t), sizeof(struct in_addr));
833
834 for (; cnt > 0; cnt -= optlen, cp += optlen) {
835 opt = cp[IPOPT_OPTVAL];
836 if (opt == IPOPT_EOL)
837 break;
838 if (opt == IPOPT_NOP)
839 optlen = 1;
840 else {
841 optlen = cp[IPOPT_OLEN];
842 if (optlen <= IPOPT_OLEN || optlen > cnt)
843 goto bad;
844 }
845 switch (opt) {
846
847 default:
848 break;
849
850 case IPOPT_LSRR:
851 case IPOPT_SSRR:
852 /*
853 * user process specifies route as:
854 * ->A->B->C->D
855 * D must be our final destination (but we can't
856 * check that since we may not have connected yet).
857 * A is first hop destination, which doesn't appear in
858 * actual IP option, but is stored before the options.
859 */
860 if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
861 goto bad;
862 m->m_len -= sizeof(struct in_addr);
863 cnt -= sizeof(struct in_addr);
864 optlen -= sizeof(struct in_addr);
865 cp[IPOPT_OLEN] = optlen;
866 /*
867 * Move first hop before start of options.
868 */
869 bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
870 sizeof(struct in_addr));
871 /*
872 * Then copy rest of options back
873 * to close up the deleted entry.
874 */
875 ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
876 sizeof(struct in_addr)),
877 (caddr_t)&cp[IPOPT_OFFSET+1],
878 (unsigned)cnt + sizeof(struct in_addr));
879 break;
880 }
881 }
882 if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
883 goto bad;
884 *pcbopt = m;
885 return (0);
886
887 bad:
888 (void)m_free(m);
889 return (EINVAL);
890 }
891
892 /*
893 * Set the IP multicast options in response to user setsockopt().
894 */
895 int
896 ip_setmoptions(optname, imop, m)
897 int optname;
898 struct ip_moptions **imop;
899 struct mbuf *m;
900 {
901 register int error = 0;
902 #ifndef __REACTOS__
903 u_char loop;
904 register int i;
905 struct in_addr addr;
906 register struct ip_mreq *mreq;
907 register struct ifnet *ifp;
908 #endif
909 register struct ip_moptions *imo = *imop;
910 #ifndef __REACTOS__
911 struct route ro;
912 register struct sockaddr_in *dst;
913 int s;
914 #endif
915
916 if (imo == NULL) {
917 /*
918 * No multicast option buffer attached to the pcb;
919 * allocate one and initialize to default values.
920 */
921 imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS,
922 M_WAITOK);
923
924 if (imo == NULL)
925 return (ENOBUFS);
926 *imop = imo;
927 imo->imo_multicast_ifp = NULL;
928 imo->imo_multicast_vif = -1;
929 imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
930 imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
931 imo->imo_num_memberships = 0;
932 }
933
934 switch (optname) {
935 #ifndef __REACTOS__
936 /* store an index number for the vif you wanna use in the send */
937 case IP_MULTICAST_VIF:
938 if (!legal_vif_num) {
939 error = EOPNOTSUPP;
940 break;
941 }
942 if (m == NULL || m->m_len != sizeof(int)) {
943 error = EINVAL;
944 break;
945 }
946 i = *(mtod(m, int *));
947 if (!legal_vif_num(i) && (i != -1)) {
948 error = EINVAL;
949 break;
950 }
951 imo->imo_multicast_vif = i;
952 break;
953
954 case IP_MULTICAST_IF:
955 /*
956 * Select the interface for outgoing multicast packets.
957 */
958 if (m == NULL || m->m_len != sizeof(struct in_addr)) {
959 error = EINVAL;
960 break;
961 }
962 addr = *(mtod(m, struct in_addr *));
963 /*
964 * INADDR_ANY is used to remove a previous selection.
965 * When no interface is selected, a default one is
966 * chosen every time a multicast packet is sent.
967 */
968 if (addr.s_addr == INADDR_ANY) {
969 imo->imo_multicast_ifp = NULL;
970 break;
971 }
972 /*
973 * The selected interface is identified by its local
974 * IP address. Find the interface and confirm that
975 * it supports multicasting.
976 */
977 s = splimp();
978 INADDR_TO_IFP(addr, ifp);
979 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
980 error = EADDRNOTAVAIL;
981 break;
982 }
983 imo->imo_multicast_ifp = ifp;
984 splx(s);
985 break;
986
987 case IP_MULTICAST_TTL:
988 /*
989 * Set the IP time-to-live for outgoing multicast packets.
990 */
991 if (m == NULL || m->m_len != 1) {
992 error = EINVAL;
993 break;
994 }
995 imo->imo_multicast_ttl = *(mtod(m, u_char *));
996 break;
997
998 case IP_MULTICAST_LOOP:
999 /*
1000 * Set the loopback flag for outgoing multicast packets.
1001 * Must be zero or one.
1002 */
1003 if (m == NULL || m->m_len != 1 ||
1004 (loop = *(mtod(m, u_char *))) > 1) {
1005 error = EINVAL;
1006 break;
1007 }
1008 imo->imo_multicast_loop = loop;
1009 break;
1010
1011 case IP_ADD_MEMBERSHIP:
1012 /*
1013 * Add a multicast group membership.
1014 * Group must be a valid IP multicast address.
1015 */
1016 if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
1017 error = EINVAL;
1018 break;
1019 }
1020 mreq = mtod(m, struct ip_mreq *);
1021 if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
1022 error = EINVAL;
1023 break;
1024 }
1025 s = splimp();
1026 /*
1027 * If no interface address was provided, use the interface of
1028 * the route to the given multicast address.
1029 */
1030 if (mreq->imr_interface.s_addr == INADDR_ANY) {
1031 bzero((caddr_t)&ro, sizeof(ro));
1032 dst = (struct sockaddr_in *)&ro.ro_dst;
1033 dst->sin_len = sizeof(*dst);
1034 dst->sin_family = AF_INET;
1035 dst->sin_addr = mreq->imr_multiaddr;
1036 rtalloc(&ro);
1037 if (ro.ro_rt == NULL) {
1038 error = EADDRNOTAVAIL;
1039 splx(s);
1040 break;
1041 }
1042 ifp = ro.ro_rt->rt_ifp;
1043 rtfree(ro.ro_rt);
1044 }
1045 else {
1046 INADDR_TO_IFP(mreq->imr_interface, ifp);
1047 }
1048
1049 /*
1050 * See if we found an interface, and confirm that it
1051 * supports multicast.
1052 */
1053 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
1054 error = EADDRNOTAVAIL;
1055 splx(s);
1056 break;
1057 }
1058 /*
1059 * See if the membership already exists or if all the
1060 * membership slots are full.
1061 */
1062 for (i = 0; i < imo->imo_num_memberships; ++i) {
1063 if (imo->imo_membership[i]->inm_ifp == ifp &&
1064 imo->imo_membership[i]->inm_addr.s_addr
1065 == mreq->imr_multiaddr.s_addr)
1066 break;
1067 }
1068 if (i < imo->imo_num_memberships) {
1069 error = EADDRINUSE;
1070 splx(s);
1071 break;
1072 }
1073 if (i == IP_MAX_MEMBERSHIPS) {
1074 error = ETOOMANYREFS;
1075 splx(s);
1076 break;
1077 }
1078 /*
1079 * Everything looks good; add a new record to the multicast
1080 * address list for the given interface.
1081 */
1082 if ((imo->imo_membership[i] =
1083 in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {
1084 error = ENOBUFS;
1085 splx(s);
1086 break;
1087 }
1088 ++imo->imo_num_memberships;
1089 splx(s);
1090 break;
1091
1092 case IP_DROP_MEMBERSHIP:
1093 /*
1094 * Drop a multicast group membership.
1095 * Group must be a valid IP multicast address.
1096 */
1097 if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
1098 error = EINVAL;
1099 break;
1100 }
1101 mreq = mtod(m, struct ip_mreq *);
1102 if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
1103 error = EINVAL;
1104 break;
1105 }
1106
1107 s = splimp();
1108 /*
1109 * If an interface address was specified, get a pointer
1110 * to its ifnet structure.
1111 */
1112 if (mreq->imr_interface.s_addr == INADDR_ANY)
1113 ifp = NULL;
1114 else {
1115 INADDR_TO_IFP(mreq->imr_interface, ifp);
1116 if (ifp == NULL) {
1117 error = EADDRNOTAVAIL;
1118 splx(s);
1119 break;
1120 }
1121 }
1122 /*
1123 * Find the membership in the membership array.
1124 */
1125 for (i = 0; i < imo->imo_num_memberships; ++i) {
1126 if ((ifp == NULL ||
1127 imo->imo_membership[i]->inm_ifp == ifp) &&
1128 imo->imo_membership[i]->inm_addr.s_addr ==
1129 mreq->imr_multiaddr.s_addr)
1130 break;
1131 }
1132 if (i == imo->imo_num_memberships) {
1133 error = EADDRNOTAVAIL;
1134 splx(s);
1135 break;
1136 }
1137 /*
1138 * Give up the multicast address record to which the
1139 * membership points.
1140 */
1141 in_delmulti(imo->imo_membership[i]);
1142 /*
1143 * Remove the gap in the membership array.
1144 */
1145 for (++i; i < imo->imo_num_memberships; ++i)
1146 imo->imo_membership[i-1] = imo->imo_membership[i];
1147 --imo->imo_num_memberships;
1148 splx(s);
1149 break;
1150 #endif
1151 default:
1152 error = EOPNOTSUPP;
1153 break;
1154 }
1155
1156 /*
1157 * If all options have default values, no need to keep the mbuf.
1158 */
1159 if (imo->imo_multicast_ifp == NULL &&
1160 imo->imo_multicast_vif == -1 &&
1161 imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
1162 imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
1163 imo->imo_num_memberships == 0) {
1164 free(*imop, M_IPMOPTS);
1165 *imop = NULL;
1166 }
1167
1168 return (error);
1169 }
1170
1171 /*
1172 * Return the IP multicast options in response to user getsockopt().
1173 */
1174 int
1175 ip_getmoptions(optname, imo, mp)
1176 int optname;
1177 register struct ip_moptions *imo;
1178 register struct mbuf **mp;
1179 {
1180 #ifndef __REACTOS__
1181 u_char *ttl;
1182 u_char *loop;
1183 struct in_addr *addr;
1184 struct in_ifaddr *ia;
1185 #endif
1186
1187 *mp = m_get(M_WAIT, MT_SOOPTS);
1188
1189 switch (optname) {
1190 #ifndef __REACTOS__
1191 case IP_MULTICAST_VIF:
1192 if (imo != NULL)
1193 *(mtod(*mp, int *)) = imo->imo_multicast_vif;
1194 else
1195 *(mtod(*mp, int *)) = -1;
1196 (*mp)->m_len = sizeof(int);
1197 return(0);
1198
1199 case IP_MULTICAST_IF:
1200 addr = mtod(*mp, struct in_addr *);
1201 (*mp)->m_len = sizeof(struct in_addr);
1202 if (imo == NULL || imo->imo_multicast_ifp == NULL)
1203 addr->s_addr = INADDR_ANY;
1204 else {
1205 IFP_TO_IA(imo->imo_multicast_ifp, ia);
1206 addr->s_addr = (ia == NULL) ? INADDR_ANY
1207 : IA_SIN(ia)->sin_addr.s_addr;
1208 }
1209 return (0);
1210
1211 case IP_MULTICAST_TTL:
1212 ttl = mtod(*mp, u_char *);
1213 (*mp)->m_len = 1;
1214 *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL
1215 : imo->imo_multicast_ttl;
1216 return (0);
1217
1218 case IP_MULTICAST_LOOP:
1219 loop = mtod(*mp, u_char *);
1220 (*mp)->m_len = 1;
1221 *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP
1222 : imo->imo_multicast_loop;
1223 return (0);
1224 #endif
1225 default:
1226 return (EOPNOTSUPP);
1227 }
1228 }
1229
1230 /*
1231 * Discard the IP multicast options.
1232 */
1233 void
1234 ip_freemoptions(imo)
1235 register struct ip_moptions *imo;
1236 {
1237 register int i;
1238
1239 if (imo != NULL) {
1240 for (i = 0; i < imo->imo_num_memberships; ++i)
1241 in_delmulti(imo->imo_membership[i]);
1242 free(imo, M_IPMOPTS);
1243 }
1244 }
1245
1246 #ifndef __REACTOS__
1247 /*
1248 * Routine called from ip_output() to loop back a copy of an IP multicast
1249 * packet to the input queue of a specified interface. Note that this
1250 * calls the output routine of the loopback "driver", but with an interface
1251 * pointer that might NOT be a loopback interface -- evil, but easier than
1252 * replicating that code here.
1253 */
1254 static void
1255 ip_mloopback(ifp, m, dst)
1256 struct ifnet *ifp;
1257 register struct mbuf *m;
1258 register struct sockaddr_in *dst;
1259 {
1260 register struct ip *ip;
1261 struct mbuf *copym;
1262
1263 copym = m_copy(m, 0, M_COPYALL);
1264 if (copym != NULL) {
1265 /*
1266 * We don't bother to fragment if the IP length is greater
1267 * than the interface's MTU. Can this possibly matter?
1268 */
1269 ip = mtod(copym, struct ip *);
1270 ip->ip_len = htons((u_short)ip->ip_len);
1271 ip->ip_off = htons((u_short)ip->ip_off);
1272 ip->ip_sum = 0;
1273 ip->ip_sum = in_cksum(copym, ip->ip_hl << 2);
1274 (void) looutput(ifp, copym, (struct sockaddr *)dst, NULL);
1275 }
1276 }
1277 #endif