- Merge aicom-network-branch (still without the NDIS stuff)
[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 #ifndef __REACTOS__
164 if (flags & IP_ROUTETOIF) {
165 if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
166 (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
167 ipstat.ips_noroute++;
168 error = ENETUNREACH;
169 goto bad;
170 }
171
172 ifp = ia->ia_ifp;
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
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 }
199
200 #else
201 if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
202 (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
203 ipstat.ips_noroute++;
204 error = ENETUNREACH;
205 goto bad;
206 }
207 #endif
208
209 #ifndef __REACTOS__
210 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
211 struct in_multi *inm;
212
213 m->m_flags |= M_MCAST;
214 /*
215 * IP destination address is multicast. Make sure "dst"
216 * still points to the address in "ro". (It may have been
217 * changed to point to a gateway address, above.)
218 */
219 dst = (struct sockaddr_in *)&ro->ro_dst;
220 /*
221 * See if the caller provided any multicast options
222 */
223 if (imo != NULL) {
224 ip->ip_ttl = imo->imo_multicast_ttl;
225 if (imo->imo_multicast_ifp != NULL)
226 ifp = imo->imo_multicast_ifp;
227 if (imo->imo_multicast_vif != -1)
228 ip->ip_src.s_addr =
229 ip_mcast_src(imo->imo_multicast_vif);
230 } else
231 ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL;
232 /*
233 * Confirm that the outgoing interface supports multicast.
234 */
235 if ((imo == NULL) || (imo->imo_multicast_vif == -1)) {
236 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
237 ipstat.ips_noroute++;
238 error = ENETUNREACH;
239 goto bad;
240 }
241 }
242 /*
243 * If source address not specified yet, use address
244 * of outgoing interface.
245 */
246 if (ip->ip_src.s_addr == INADDR_ANY) {
247 register struct in_ifaddr *ia;
248
249 panic("We don't handle this yet\n");
250 for (ia = in_ifaddr; ia; ia = ia->ia_next)
251 if (ia->ia_ifp == ifp) {
252 ip->ip_src = IA_SIN(ia)->sin_addr;
253 break;
254 }
255 }
256
257 IN_LOOKUP_MULTI(ip->ip_dst, ifp, inm);
258 if (inm != NULL &&
259 (imo == NULL || imo->imo_multicast_loop)) {
260 /*
261 * If we belong to the destination multicast group
262 * on the outgoing interface, and the caller did not
263 * forbid loopback, loop back a copy.
264 */
265 ip_mloopback(ifp, m, dst);
266 }
267 else {
268 /*
269 * If we are acting as a multicast router, perform
270 * multicast forwarding as if the packet had just
271 * arrived on the interface to which we are about
272 * to send. The multicast forwarding function
273 * recursively calls this function, using the
274 * IP_FORWARDING flag to prevent infinite recursion.
275 *
276 * Multicasts that are looped back by ip_mloopback(),
277 * above, will be forwarded by the ip_input() routine,
278 * if necessary.
279 */
280 if (ip_mrouter && (flags & IP_FORWARDING) == 0) {
281 /*
282 * Check if rsvp daemon is running. If not, don't
283 * set ip_moptions. This ensures that the packet
284 * is multicast and not just sent down one link
285 * as prescribed by rsvpd.
286 */
287 if (!rsvp_on)
288 imo = NULL;
289 if (ip_mforward(ip, ifp, m, imo) != 0) {
290 m_freem(m);
291 goto done;
292 }
293 }
294 }
295
296 /*
297 * Multicasts with a time-to-live of zero may be looped-
298 * back, above, but must not be transmitted on a network.
299 * Also, multicasts addressed to the loopback interface
300 * are not sent -- the above call to ip_mloopback() will
301 * loop back a copy if this host actually belongs to the
302 * destination group on the loopback interface.
303 */
304 if (ip->ip_ttl == 0 || ifp->if_flags & IFF_LOOPBACK) {
305 m_freem(m);
306 goto done;
307 }
308
309 goto sendit;
310 }
311 #endif
312
313 #ifdef __REACTOS__
314 /*
315 * If source address not specified yet, use address
316 * of outgoing interface.
317 */
318 if (ip->ip_src.s_addr == INADDR_ANY)
319 ip->ip_src = IA_SIN(ia)->sin_addr;
320 #endif
321 #ifndef __REACTOS__
322 /*
323 * Verify that we have any chance at all of being able to queue
324 * the packet or packet fragments
325 */
326 if ((ifp->if_snd.ifq_len + ip->ip_len / ifp->if_mtu + 1) >=
327 ifp->if_snd.ifq_maxlen) {
328 error = ENOBUFS;
329 goto bad;
330 }
331
332 /*
333 * Look for broadcast address and
334 * and verify user is allowed to send
335 * such a packet.
336 */
337 if (in_broadcast(dst->sin_addr, ifp)) {
338 if ((ifp->if_flags & IFF_BROADCAST) == 0) {
339 error = EADDRNOTAVAIL;
340 goto bad;
341 }
342 if ((flags & IP_ALLOWBROADCAST) == 0) {
343 error = EACCES;
344 goto bad;
345 }
346 /* don't allow broadcast messages to be fragmented */
347 if ((u_short)ip->ip_len > ifp->if_mtu) {
348 error = EMSGSIZE;
349 goto bad;
350 }
351 m->m_flags |= M_BCAST;
352 } else
353 m->m_flags &= ~M_BCAST;
354 #endif
355
356 #ifndef __REACTOS__
357 sendit:
358 /*
359 * Check with the firewall...
360 */
361 if (!(*ip_fw_chk_ptr)(m,ip,ifp,1)) {
362 error = EACCES;
363 goto done;
364 }
365 #endif
366
367 /*
368 * If small enough for interface, can just send directly.
369 */
370
371 /* FIXME: This was ROS-modified code. Where is the original? */
372 if ((u_short)ip->ip_len <= ((struct ifaddr *)ia)->ifa_mtu) {
373 ip->ip_len = htons((u_short)ip->ip_len);
374 ip->ip_off = htons((u_short)ip->ip_off);
375 ip->ip_sum = 0;
376 ip->ip_sum = in_cksum(m, hlen);
377 #ifdef __REACTOS__
378 if( OtcpEvent.PacketSend ) {
379 struct mbuf *new_m;
380 new_m = m_get( M_DONTWAIT, 0 );
381 if ( NULL == new_m ) {
382 error = ENOBUFS;
383 goto done;
384 }
385 MCLGET( new_m, M_DONTWAIT );
386 if (0 == (new_m->m_flags & M_EXT)) {
387 m_free( new_m );
388 error = ENOBUFS;
389 goto done;
390 }
391 m_copydata( m, 0, htons(ip->ip_len), new_m->m_data );
392 new_m->m_len = htons(ip->ip_len);
393 error = OtcpEvent.PacketSend( OtcpEvent.ClientData,
394 (OSK_PCHAR)new_m->m_data, new_m->m_len );
395 m_free( new_m );
396 m_freem( m );
397 goto done;
398 }
399 #else
400 error = (*ifp->if_output)(ifp, m,
401 (struct sockaddr *)dst, ro->ro_rt);
402 #endif
403 }
404 /*
405 * Too large for interface; fragment if possible.
406 * Must be able to put at least 8 bytes per fragment.
407 */
408 if (ip->ip_off & IP_DF) {
409 error = EMSGSIZE;
410 #ifndef __REACTOS__
411 #if 1
412 /*
413 * This case can happen if the user changed the MTU
414 * of an interface after enabling IP on it. Because
415 * most netifs don't keep track of routes pointing to
416 * them, there is no way for one to update all its
417 * routes when the MTU is changed.
418 */
419 if ((ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST))
420 && !(ro->ro_rt->rt_rmx.rmx_locks & RTV_MTU)
421 && (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) {
422 ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
423 }
424 #endif
425 #endif
426 ipstat.ips_cantfrag++;
427 goto bad;
428 }
429 #ifndef __REACTOS__
430 len = (ifp->if_mtu - hlen) &~ 7;
431 if (len < 8) {
432 error = EMSGSIZE;
433 goto bad;
434 }
435 #else
436 len = (((struct ifaddr *)ia)->ifa_mtu - hlen) & ~7;
437 #endif
438
439 {
440 int mhlen, firstlen = len;
441 struct mbuf **mnext = &m->m_nextpkt;
442
443 /*
444 * Loop through length of segment after first fragment,
445 * make new header and copy data of each part and link onto chain.
446 */
447 m0 = m;
448 mhlen = sizeof (struct ip);
449 for (off = hlen + len; off < (u_short)ip->ip_len; off += len) {
450 OS_DbgPrint(OSK_MID_TRACE,("off = %d, len = %d\n", off, len));
451 MGETHDR(m, M_DONTWAIT, MT_HEADER);
452 if (m == 0) {
453 error = ENOBUFS;
454 ipstat.ips_odropped++;
455 goto sendorfree;
456 }
457 m->m_data += max_linkhdr;
458 mhip = mtod(m, struct ip *);
459 *mhip = *ip;
460 if (hlen > sizeof (struct ip)) {
461 mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
462 mhip->ip_hl = mhlen >> 2;
463 }
464 m->m_len = mhlen;
465 mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF);
466 if (ip->ip_off & IP_MF)
467 mhip->ip_off |= IP_MF;
468 if (off + len >= (u_short)ip->ip_len)
469 len = (u_short)ip->ip_len - off;
470 else
471 mhip->ip_off |= IP_MF;
472 mhip->ip_len = htons((u_short)(len + mhlen));
473 m->m_next = m_copy(m0, off, len);
474 if (m->m_next == 0) {
475 (void) m_free(m);
476 error = ENOBUFS; /* ??? */
477 ipstat.ips_odropped++;
478 goto sendorfree;
479 }
480 m->m_pkthdr.len = mhlen + len;
481 m->m_pkthdr.rcvif = (struct ifnet *)0;
482 mhip->ip_off = htons((u_short)mhip->ip_off);
483 mhip->ip_sum = 0;
484 mhip->ip_sum = in_cksum(m, mhlen);
485 *mnext = m;
486 mnext = &m->m_nextpkt;
487 ipstat.ips_ofragments++;
488 }
489 /*
490 * Update first fragment by trimming what's been copied out
491 * and updating header, then send each fragment (in order).
492 */
493 m = m0;
494 OS_DbgPrint(OSK_MID_TRACE,("hlen %d firstlen %d ip->ip_len %x\n",
495 hlen, firstlen, ip->ip_len));
496 OS_DbgPrint(OSK_MID_TRACE,("hlen + firstlen - ip->ip_len %d\n",
497 hlen + firstlen - (u_short)ip->ip_len));
498 m_adj(m, hlen + firstlen - (u_short)ip->ip_len);
499 m->m_pkthdr.len = hlen + firstlen;
500 ip->ip_len = htons((u_short)(m->m_pkthdr.len));
501 ip->ip_off = htons((u_short)(ip->ip_off | IP_MF));
502 ip->ip_sum = 0;
503 ip->ip_sum = in_cksum(m, hlen - sizeof( struct ip ) );
504
505 OS_DbgPrint(OSK_MID_TRACE,("ip->ip_len = %x\n", ip->ip_len));
506
507 sendorfree:
508 for (m = m0; m; m = m0) {
509 m0 = m->m_nextpkt;
510 m->m_nextpkt = 0;
511 #ifndef __REACTOS__
512 if (error == 0)
513 error = (*ifp->if_output)(ifp, m,
514 (struct sockaddr *)dst, ro->ro_rt);
515 else
516 m_freem(m);
517 #else
518 if( error == 0 && OtcpEvent.PacketSend ) {
519 struct mbuf *new_m;
520 MGET( new_m, M_DONTWAIT, 0 );
521 if ( NULL == new_m ) {
522 error = ENOBUFS;
523 goto done;
524 }
525 MCLGET( new_m, M_DONTWAIT );
526 if (0 == (new_m->m_flags & M_EXT)) {
527 m_free( new_m );
528 error = ENOBUFS;
529 goto done;
530 }
531 m_copydata( m, 0, m->m_pkthdr.len, new_m->m_data );
532 new_m->m_len = m->m_pkthdr.len;
533 error = OtcpEvent.PacketSend( OtcpEvent.ClientData,
534 (OSK_PCHAR)new_m->m_data, new_m->m_len );
535 m_free( new_m );
536 m_freem( m );
537 }
538
539 OS_DbgPrint(OSK_MID_TRACE,("Error from upper layer: %d\n", error));
540 #endif
541 }
542
543 if (error == 0)
544 ipstat.ips_fragmented++;
545 }
546 done:
547 if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) {
548 RTFREE(ro->ro_rt);
549 }
550
551 return (error);
552 bad:
553 m_freem(m0);
554 goto done;
555 }
556
557 /*
558 * Insert IP options into preformed packet.
559 * Adjust IP destination as required for IP source routing,
560 * as indicated by a non-zero in_addr at the start of the options.
561 *
562 * XXX This routine assumes that the packet has no options in place.
563 */
564 static struct mbuf *
565 ip_insertoptions(m, opt, phlen)
566 register struct mbuf *m;
567 struct mbuf *opt;
568 int *phlen;
569 {
570 register struct ipoption *p = mtod(opt, struct ipoption *);
571 struct mbuf *n;
572 register struct ip *ip = mtod(m, struct ip *);
573 unsigned optlen;
574
575 optlen = opt->m_len - sizeof(p->ipopt_dst);
576 if (optlen + (u_short)ip->ip_len > IP_MAXPACKET)
577 return (m); /* XXX should fail */
578 if (p->ipopt_dst.s_addr)
579 ip->ip_dst = p->ipopt_dst;
580 if (m->m_flags & M_EXT || m->m_data - optlen < m->m_pktdat) {
581 MGETHDR(n, M_DONTWAIT, MT_HEADER);
582 if (n == 0)
583 return (m);
584 n->m_pkthdr.len = m->m_pkthdr.len + optlen;
585 m->m_len -= sizeof(struct ip);
586 m->m_data += sizeof(struct ip);
587 n->m_next = m;
588 m = n;
589 m->m_len = optlen + sizeof(struct ip);
590 m->m_data += max_linkhdr;
591 (void)memcpy(mtod(m, void *), ip, sizeof(struct ip));
592 } else {
593 m->m_data -= optlen;
594 m->m_len += optlen;
595 m->m_pkthdr.len += optlen;
596 ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));
597 }
598 ip = mtod(m, struct ip *);
599 (void)memcpy(ip + 1, p->ipopt_list, (unsigned)optlen);
600 *phlen = sizeof(struct ip) + optlen;
601 ip->ip_hl = *phlen >> 2;
602 ip->ip_len += optlen;
603 return (m);
604 }
605
606 /*
607 * Copy options from ip to jp,
608 * omitting those not copied during fragmentation.
609 */
610 int
611 ip_optcopy(ip, jp)
612 struct ip *ip, *jp;
613 {
614 register u_char *cp, *dp;
615 int opt, optlen, cnt;
616
617 cp = (u_char *)(ip + 1);
618 dp = (u_char *)(jp + 1);
619 cnt = (ip->ip_hl << 2) - sizeof (struct ip);
620 for (; cnt > 0; cnt -= optlen, cp += optlen) {
621 opt = cp[0];
622 if (opt == IPOPT_EOL)
623 break;
624 if (opt == IPOPT_NOP) {
625 /* Preserve for IP mcast tunnel's LSRR alignment. */
626 *dp++ = IPOPT_NOP;
627 optlen = 1;
628 continue;
629 } else
630 optlen = cp[IPOPT_OLEN];
631 /* bogus lengths should have been caught by ip_dooptions */
632 if (optlen > cnt)
633 optlen = cnt;
634 if (IPOPT_COPIED(opt)) {
635 (void)memcpy(dp, cp, (unsigned)optlen);
636 dp += optlen;
637 }
638 }
639 for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
640 *dp++ = IPOPT_EOL;
641 return (optlen);
642 }
643
644 /*
645 * IP socket option processing.
646 */
647 int
648 ip_ctloutput(op, so, level, optname, mp)
649 int op;
650 struct socket *so;
651 int level, optname;
652 struct mbuf **mp;
653 {
654 register struct inpcb *inp = sotoinpcb(so);
655 register struct mbuf *m = *mp;
656 register int optval = 0;
657 int error = 0;
658
659 if (level != IPPROTO_IP) {
660 error = EINVAL;
661 if (op == PRCO_SETOPT && *mp)
662 (void) m_free(*mp);
663 } else switch (op) {
664
665 case PRCO_SETOPT:
666 switch (optname) {
667 case IP_OPTIONS:
668 #ifdef notyet
669 case IP_RETOPTS:
670 return (ip_pcbopts(optname, &inp->inp_options, m));
671 #else
672 return (ip_pcbopts(&inp->inp_options, m));
673 #endif
674
675 case IP_TOS:
676 case IP_TTL:
677 case IP_RECVOPTS:
678 case IP_RECVRETOPTS:
679 case IP_RECVDSTADDR:
680 if (m == 0 || m->m_len != sizeof(int))
681 error = EINVAL;
682 else {
683 optval = *mtod(m, int *);
684 switch (optname) {
685
686 case IP_TOS:
687 inp->inp_ip.ip_tos = optval;
688 break;
689
690 case IP_TTL:
691 inp->inp_ip.ip_ttl = optval;
692 break;
693 #define OPTSET(bit) \
694 if (optval) \
695 inp->inp_flags |= bit; \
696 else \
697 inp->inp_flags &= ~bit;
698
699 case IP_RECVOPTS:
700 OPTSET(INP_RECVOPTS);
701 break;
702
703 case IP_RECVRETOPTS:
704 OPTSET(INP_RECVRETOPTS);
705 break;
706
707 case IP_RECVDSTADDR:
708 OPTSET(INP_RECVDSTADDR);
709 break;
710 }
711 }
712 break;
713 #undef OPTSET
714
715 case IP_MULTICAST_IF:
716 case IP_MULTICAST_VIF:
717 case IP_MULTICAST_TTL:
718 case IP_MULTICAST_LOOP:
719 case IP_ADD_MEMBERSHIP:
720 case IP_DROP_MEMBERSHIP:
721 error = ip_setmoptions(optname, &inp->inp_moptions, m);
722 break;
723
724 default:
725 error = ENOPROTOOPT;
726 break;
727 }
728 if (m)
729 (void)m_free(m);
730 break;
731
732 case PRCO_GETOPT:
733 switch (optname) {
734 case IP_OPTIONS:
735 case IP_RETOPTS:
736 *mp = m = m_get(M_WAIT, MT_SOOPTS);
737 if (inp->inp_options) {
738 m->m_len = inp->inp_options->m_len;
739 (void)memcpy(mtod(m, void *),
740 mtod(inp->inp_options, void *), (unsigned)m->m_len);
741 } else
742 m->m_len = 0;
743 break;
744
745 case IP_TOS:
746 case IP_TTL:
747 case IP_RECVOPTS:
748 case IP_RECVRETOPTS:
749 case IP_RECVDSTADDR:
750 *mp = m = m_get(M_WAIT, MT_SOOPTS);
751 m->m_len = sizeof(int);
752 switch (optname) {
753
754 case IP_TOS:
755 optval = inp->inp_ip.ip_tos;
756 break;
757
758 case IP_TTL:
759 optval = inp->inp_ip.ip_ttl;
760 break;
761
762 #define OPTBIT(bit) (inp->inp_flags & bit ? 1 : 0)
763
764 case IP_RECVOPTS:
765 optval = OPTBIT(INP_RECVOPTS);
766 break;
767
768 case IP_RECVRETOPTS:
769 optval = OPTBIT(INP_RECVRETOPTS);
770 break;
771
772 case IP_RECVDSTADDR:
773 optval = OPTBIT(INP_RECVDSTADDR);
774 break;
775 }
776 *mtod(m, int *) = optval;
777 break;
778
779 case IP_MULTICAST_IF:
780 case IP_MULTICAST_VIF:
781 case IP_MULTICAST_TTL:
782 case IP_MULTICAST_LOOP:
783 case IP_ADD_MEMBERSHIP:
784 case IP_DROP_MEMBERSHIP:
785 error = ip_getmoptions(optname, inp->inp_moptions, mp);
786 break;
787
788 default:
789 error = ENOPROTOOPT;
790 break;
791 }
792 break;
793 }
794 return (error);
795 }
796
797 /*
798 * Set up IP options in pcb for insertion in output packets.
799 * Store in mbuf with pointer in pcbopt, adding pseudo-option
800 * with destination address if source routed.
801 */
802 int
803 #ifdef notyet
804 ip_pcbopts(optname, pcbopt, m)
805 int optname;
806 #else
807 ip_pcbopts(pcbopt, m)
808 #endif
809 struct mbuf **pcbopt;
810 register struct mbuf *m;
811 {
812 register int cnt, optlen;
813 register u_char *cp;
814 u_char opt;
815
816 /* turn off any old options */
817 if (*pcbopt)
818 (void)m_free(*pcbopt);
819 *pcbopt = 0;
820 if (m == (struct mbuf *)0 || m->m_len == 0) {
821 /*
822 * Only turning off any previous options.
823 */
824 if (m)
825 (void)m_free(m);
826 return (0);
827 }
828
829 #ifndef vax
830 if (m->m_len % sizeof(long))
831 goto bad;
832 #endif
833 /*
834 * IP first-hop destination address will be stored before
835 * actual options; move other options back
836 * and clear it when none present.
837 */
838 if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN])
839 goto bad;
840 cnt = m->m_len;
841 m->m_len += sizeof(struct in_addr);
842 cp = mtod(m, u_char *) + sizeof(struct in_addr);
843 ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt);
844 bzero(mtod(m, caddr_t), sizeof(struct in_addr));
845
846 for (; cnt > 0; cnt -= optlen, cp += optlen) {
847 opt = cp[IPOPT_OPTVAL];
848 if (opt == IPOPT_EOL)
849 break;
850 if (opt == IPOPT_NOP)
851 optlen = 1;
852 else {
853 optlen = cp[IPOPT_OLEN];
854 if (optlen <= IPOPT_OLEN || optlen > cnt)
855 goto bad;
856 }
857 switch (opt) {
858
859 default:
860 break;
861
862 case IPOPT_LSRR:
863 case IPOPT_SSRR:
864 /*
865 * user process specifies route as:
866 * ->A->B->C->D
867 * D must be our final destination (but we can't
868 * check that since we may not have connected yet).
869 * A is first hop destination, which doesn't appear in
870 * actual IP option, but is stored before the options.
871 */
872 if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr))
873 goto bad;
874 m->m_len -= sizeof(struct in_addr);
875 cnt -= sizeof(struct in_addr);
876 optlen -= sizeof(struct in_addr);
877 cp[IPOPT_OLEN] = optlen;
878 /*
879 * Move first hop before start of options.
880 */
881 bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t),
882 sizeof(struct in_addr));
883 /*
884 * Then copy rest of options back
885 * to close up the deleted entry.
886 */
887 ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] +
888 sizeof(struct in_addr)),
889 (caddr_t)&cp[IPOPT_OFFSET+1],
890 (unsigned)cnt + sizeof(struct in_addr));
891 break;
892 }
893 }
894 if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr))
895 goto bad;
896 *pcbopt = m;
897 return (0);
898
899 bad:
900 (void)m_free(m);
901 return (EINVAL);
902 }
903
904 /*
905 * Set the IP multicast options in response to user setsockopt().
906 */
907 int
908 ip_setmoptions(optname, imop, m)
909 int optname;
910 struct ip_moptions **imop;
911 struct mbuf *m;
912 {
913 register int error = 0;
914 #ifndef __REACTOS__
915 u_char loop;
916 register int i;
917 struct in_addr addr;
918 register struct ip_mreq *mreq;
919 register struct ifnet *ifp;
920 #endif
921 register struct ip_moptions *imo = *imop;
922 #ifndef __REACTOS__
923 struct route ro;
924 register struct sockaddr_in *dst;
925 int s;
926 #endif
927
928 if (imo == NULL) {
929 /*
930 * No multicast option buffer attached to the pcb;
931 * allocate one and initialize to default values.
932 */
933 imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS,
934 M_WAITOK);
935
936 if (imo == NULL)
937 return (ENOBUFS);
938 *imop = imo;
939 imo->imo_multicast_ifp = NULL;
940 imo->imo_multicast_vif = -1;
941 imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
942 imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
943 imo->imo_num_memberships = 0;
944 }
945
946 switch (optname) {
947 #ifndef __REACTOS__
948 /* store an index number for the vif you wanna use in the send */
949 case IP_MULTICAST_VIF:
950 if (!legal_vif_num) {
951 error = EOPNOTSUPP;
952 break;
953 }
954 if (m == NULL || m->m_len != sizeof(int)) {
955 error = EINVAL;
956 break;
957 }
958 i = *(mtod(m, int *));
959 if (!legal_vif_num(i) && (i != -1)) {
960 error = EINVAL;
961 break;
962 }
963 imo->imo_multicast_vif = i;
964 break;
965
966 case IP_MULTICAST_IF:
967 /*
968 * Select the interface for outgoing multicast packets.
969 */
970 if (m == NULL || m->m_len != sizeof(struct in_addr)) {
971 error = EINVAL;
972 break;
973 }
974 addr = *(mtod(m, struct in_addr *));
975 /*
976 * INADDR_ANY is used to remove a previous selection.
977 * When no interface is selected, a default one is
978 * chosen every time a multicast packet is sent.
979 */
980 if (addr.s_addr == INADDR_ANY) {
981 imo->imo_multicast_ifp = NULL;
982 break;
983 }
984 /*
985 * The selected interface is identified by its local
986 * IP address. Find the interface and confirm that
987 * it supports multicasting.
988 */
989 s = splimp();
990 INADDR_TO_IFP(addr, ifp);
991 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
992 error = EADDRNOTAVAIL;
993 break;
994 }
995 imo->imo_multicast_ifp = ifp;
996 splx(s);
997 break;
998
999 case IP_MULTICAST_TTL:
1000 /*
1001 * Set the IP time-to-live for outgoing multicast packets.
1002 */
1003 if (m == NULL || m->m_len != 1) {
1004 error = EINVAL;
1005 break;
1006 }
1007 imo->imo_multicast_ttl = *(mtod(m, u_char *));
1008 break;
1009
1010 case IP_MULTICAST_LOOP:
1011 /*
1012 * Set the loopback flag for outgoing multicast packets.
1013 * Must be zero or one.
1014 */
1015 if (m == NULL || m->m_len != 1 ||
1016 (loop = *(mtod(m, u_char *))) > 1) {
1017 error = EINVAL;
1018 break;
1019 }
1020 imo->imo_multicast_loop = loop;
1021 break;
1022
1023 case IP_ADD_MEMBERSHIP:
1024 /*
1025 * Add a multicast group membership.
1026 * Group must be a valid IP multicast address.
1027 */
1028 if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
1029 error = EINVAL;
1030 break;
1031 }
1032 mreq = mtod(m, struct ip_mreq *);
1033 if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
1034 error = EINVAL;
1035 break;
1036 }
1037 s = splimp();
1038 /*
1039 * If no interface address was provided, use the interface of
1040 * the route to the given multicast address.
1041 */
1042 if (mreq->imr_interface.s_addr == INADDR_ANY) {
1043 bzero((caddr_t)&ro, sizeof(ro));
1044 dst = (struct sockaddr_in *)&ro.ro_dst;
1045 dst->sin_len = sizeof(*dst);
1046 dst->sin_family = AF_INET;
1047 dst->sin_addr = mreq->imr_multiaddr;
1048 rtalloc(&ro);
1049 if (ro.ro_rt == NULL) {
1050 error = EADDRNOTAVAIL;
1051 splx(s);
1052 break;
1053 }
1054 ifp = ro.ro_rt->rt_ifp;
1055 rtfree(ro.ro_rt);
1056 }
1057 else {
1058 INADDR_TO_IFP(mreq->imr_interface, ifp);
1059 }
1060
1061 /*
1062 * See if we found an interface, and confirm that it
1063 * supports multicast.
1064 */
1065 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
1066 error = EADDRNOTAVAIL;
1067 splx(s);
1068 break;
1069 }
1070 /*
1071 * See if the membership already exists or if all the
1072 * membership slots are full.
1073 */
1074 for (i = 0; i < imo->imo_num_memberships; ++i) {
1075 if (imo->imo_membership[i]->inm_ifp == ifp &&
1076 imo->imo_membership[i]->inm_addr.s_addr
1077 == mreq->imr_multiaddr.s_addr)
1078 break;
1079 }
1080 if (i < imo->imo_num_memberships) {
1081 error = EADDRINUSE;
1082 splx(s);
1083 break;
1084 }
1085 if (i == IP_MAX_MEMBERSHIPS) {
1086 error = ETOOMANYREFS;
1087 splx(s);
1088 break;
1089 }
1090 /*
1091 * Everything looks good; add a new record to the multicast
1092 * address list for the given interface.
1093 */
1094 if ((imo->imo_membership[i] =
1095 in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {
1096 error = ENOBUFS;
1097 splx(s);
1098 break;
1099 }
1100 ++imo->imo_num_memberships;
1101 splx(s);
1102 break;
1103
1104 case IP_DROP_MEMBERSHIP:
1105 /*
1106 * Drop a multicast group membership.
1107 * Group must be a valid IP multicast address.
1108 */
1109 if (m == NULL || m->m_len != sizeof(struct ip_mreq)) {
1110 error = EINVAL;
1111 break;
1112 }
1113 mreq = mtod(m, struct ip_mreq *);
1114 if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) {
1115 error = EINVAL;
1116 break;
1117 }
1118
1119 s = splimp();
1120 /*
1121 * If an interface address was specified, get a pointer
1122 * to its ifnet structure.
1123 */
1124 if (mreq->imr_interface.s_addr == INADDR_ANY)
1125 ifp = NULL;
1126 else {
1127 INADDR_TO_IFP(mreq->imr_interface, ifp);
1128 if (ifp == NULL) {
1129 error = EADDRNOTAVAIL;
1130 splx(s);
1131 break;
1132 }
1133 }
1134 /*
1135 * Find the membership in the membership array.
1136 */
1137 for (i = 0; i < imo->imo_num_memberships; ++i) {
1138 if ((ifp == NULL ||
1139 imo->imo_membership[i]->inm_ifp == ifp) &&
1140 imo->imo_membership[i]->inm_addr.s_addr ==
1141 mreq->imr_multiaddr.s_addr)
1142 break;
1143 }
1144 if (i == imo->imo_num_memberships) {
1145 error = EADDRNOTAVAIL;
1146 splx(s);
1147 break;
1148 }
1149 /*
1150 * Give up the multicast address record to which the
1151 * membership points.
1152 */
1153 in_delmulti(imo->imo_membership[i]);
1154 /*
1155 * Remove the gap in the membership array.
1156 */
1157 for (++i; i < imo->imo_num_memberships; ++i)
1158 imo->imo_membership[i-1] = imo->imo_membership[i];
1159 --imo->imo_num_memberships;
1160 splx(s);
1161 break;
1162 #endif
1163 default:
1164 error = EOPNOTSUPP;
1165 break;
1166 }
1167
1168 /*
1169 * If all options have default values, no need to keep the mbuf.
1170 */
1171 if (imo->imo_multicast_ifp == NULL &&
1172 imo->imo_multicast_vif == -1 &&
1173 imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&
1174 imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&
1175 imo->imo_num_memberships == 0) {
1176 free(*imop, M_IPMOPTS);
1177 *imop = NULL;
1178 }
1179
1180 return (error);
1181 }
1182
1183 /*
1184 * Return the IP multicast options in response to user getsockopt().
1185 */
1186 int
1187 ip_getmoptions(optname, imo, mp)
1188 int optname;
1189 register struct ip_moptions *imo;
1190 register struct mbuf **mp;
1191 {
1192 #ifndef __REACTOS__
1193 u_char *ttl;
1194 u_char *loop;
1195 struct in_addr *addr;
1196 struct in_ifaddr *ia;
1197 #endif
1198
1199 *mp = m_get(M_WAIT, MT_SOOPTS);
1200
1201 switch (optname) {
1202 #ifndef __REACTOS__
1203 case IP_MULTICAST_VIF:
1204 if (imo != NULL)
1205 *(mtod(*mp, int *)) = imo->imo_multicast_vif;
1206 else
1207 *(mtod(*mp, int *)) = -1;
1208 (*mp)->m_len = sizeof(int);
1209 return(0);
1210
1211 case IP_MULTICAST_IF:
1212 addr = mtod(*mp, struct in_addr *);
1213 (*mp)->m_len = sizeof(struct in_addr);
1214 if (imo == NULL || imo->imo_multicast_ifp == NULL)
1215 addr->s_addr = INADDR_ANY;
1216 else {
1217 IFP_TO_IA(imo->imo_multicast_ifp, ia);
1218 addr->s_addr = (ia == NULL) ? INADDR_ANY
1219 : IA_SIN(ia)->sin_addr.s_addr;
1220 }
1221 return (0);
1222
1223 case IP_MULTICAST_TTL:
1224 ttl = mtod(*mp, u_char *);
1225 (*mp)->m_len = 1;
1226 *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL
1227 : imo->imo_multicast_ttl;
1228 return (0);
1229
1230 case IP_MULTICAST_LOOP:
1231 loop = mtod(*mp, u_char *);
1232 (*mp)->m_len = 1;
1233 *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP
1234 : imo->imo_multicast_loop;
1235 return (0);
1236 #endif
1237 default:
1238 return (EOPNOTSUPP);
1239 }
1240 }
1241
1242 /*
1243 * Discard the IP multicast options.
1244 */
1245 void
1246 ip_freemoptions(imo)
1247 register struct ip_moptions *imo;
1248 {
1249 register int i;
1250
1251 if (imo != NULL) {
1252 for (i = 0; i < imo->imo_num_memberships; ++i)
1253 in_delmulti(imo->imo_membership[i]);
1254 free(imo, M_IPMOPTS);
1255 }
1256 }
1257
1258 #ifndef __REACTOS__
1259 /*
1260 * Routine called from ip_output() to loop back a copy of an IP multicast
1261 * packet to the input queue of a specified interface. Note that this
1262 * calls the output routine of the loopback "driver", but with an interface
1263 * pointer that might NOT be a loopback interface -- evil, but easier than
1264 * replicating that code here.
1265 */
1266 static void
1267 ip_mloopback(ifp, m, dst)
1268 struct ifnet *ifp;
1269 register struct mbuf *m;
1270 register struct sockaddr_in *dst;
1271 {
1272 register struct ip *ip;
1273 struct mbuf *copym;
1274
1275 copym = m_copy(m, 0, M_COPYALL);
1276 if (copym != NULL) {
1277 /*
1278 * We don't bother to fragment if the IP length is greater
1279 * than the interface's MTU. Can this possibly matter?
1280 */
1281 ip = mtod(copym, struct ip *);
1282 ip->ip_len = htons((u_short)ip->ip_len);
1283 ip->ip_off = htons((u_short)ip->ip_off);
1284 ip->ip_sum = 0;
1285 ip->ip_sum = in_cksum(copym, ip->ip_hl << 2);
1286 (void) looutput(ifp, copym, (struct sockaddr *)dst, NULL);
1287 }
1288 }
1289 #endif