Generally use NULL instead of explicitly casting 0 to some pointer type.
[dragonfly.git] / sys / netproto / ns / ns_ip.c
1 /*
2  * Copyright (c) 1984, 1985, 1986, 1987, 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  *      @(#)ns_ip.c     8.1 (Berkeley) 6/10/93
34  * $FreeBSD: src/sys/netns/ns_ip.c,v 1.9 1999/08/28 00:49:50 peter Exp $
35  * $DragonFly: src/sys/netproto/ns/ns_ip.c,v 1.15 2008/05/14 11:59:24 sephe Exp $
36  */
37
38 /*
39  * Software interface driver for encapsulating ns in ip.
40  */
41
42 #ifdef NSIP
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/mbuf.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/errno.h>
50 #include <sys/ioctl.h>
51 #include <sys/protosw.h>
52
53 #include <net/if.h>
54 #include <net/netisr.h>
55 #include <net/route.h>
56
57 #include <netinet/in.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/in_var.h>
60 #include <netinet/ip.h>
61 #include <netinet/ip_var.h>
62
63 #include <machine/mtpr.h>
64 #include <machine/stdarg.h>
65
66 #include "ns.h"
67 #include "ns_if.h"
68 #include "idp.h"
69
70 struct ifnet_en {
71         struct ifnet ifen_ifnet;
72         struct route ifen_route;
73         struct in_addr ifen_src;
74         struct in_addr ifen_dst;
75         struct ifnet_en *ifen_next;
76 };
77
78 int     nsipoutput(), nsipioctl(), nsipstart();
79 #define LOMTU   (1024+512);
80
81 struct ifnet nsipif;
82 static int nsipif_units;
83 struct ifnet_en *nsip_list;             /* list of all hosts and gateways or
84                                         broadcast addrs */
85
86 struct ifnet_en *
87 nsipattach(void)
88 {
89         struct ifnet_en *m;
90         struct ifnet *ifp;
91
92         if (nsipif.if_mtu == 0) {
93                 ifp = &nsipif;
94                 if_initname(ifp, "nsip", nsipif_units);
95                 ifp->if_mtu = LOMTU;
96                 ifp->if_ioctl = nsipioctl;
97                 ifp->if_output = nsipoutput;
98                 ifp->if_start = nsipstart;
99                 ifp->if_flags = IFF_POINTOPOINT;
100         }
101
102         MALLOC((m), struct ifnet_en *, sizeof(*m), M_PCB, M_WAITOK);
103         m->ifen_next = nsip_list;
104         nsip_list = m;
105         ifp = &m->ifen_ifnet;
106
107         ifp->if_softc = m;
108         if_initname(ifp, "nsip", nsipif_units++);
109         ifp->if_name = "nsip";
110         ifp->if_mtu = LOMTU;
111         ifp->if_ioctl = nsipioctl;
112         ifp->if_output = nsipoutput;
113         ifp->if_start = nsipstart;
114         ifp->if_flags = IFF_POINTOPOINT;
115         if_attach(ifp, NULL);
116
117         return (m);
118 }
119
120
121 /*
122  * Process an ioctl request.
123  */
124 /* ARGSUSED */
125 int
126 nsipioctl(struct ifnet *ifp, int cmd, caddr_t data)
127 {
128         int error = 0;
129         struct ifreq *ifr;
130
131         switch (cmd) {
132
133         case SIOCSIFADDR:
134                 ifp->if_flags |= IFF_UP;
135                 /* fall into: */
136
137         case SIOCSIFDSTADDR:
138                 /*
139                  * Everything else is done at a higher level.
140                  */
141                 break;
142
143         case SIOCSIFFLAGS:
144                 ifr = (struct ifreq *)data;
145                 if ((ifr->ifr_flags & IFF_UP) == 0)
146                         error = nsip_free(ifp);
147
148
149         default:
150                 error = EINVAL;
151         }
152         return (error);
153 }
154
155 struct mbuf *nsip_badlen;
156 struct mbuf *nsip_lastin;
157 int nsip_hold_input;
158
159 #warning "Audit the second argument, this expect ifp, but gets int from netinet"
160
161 void
162 idpip_input(struct mbuf *m, ...)
163 {
164         struct ip *ip;
165         struct idp *idp;
166         int len, s;
167         struct ifnet *ifp;
168         __va_list ap;
169
170         __va_start(ap, m);
171         ifp = __va_arg(ap, struct ifnet *);
172         __va_end(ap);
173
174         if (nsip_hold_input) {
175                 if (nsip_lastin) {
176                         m_freem(nsip_lastin);
177                 }
178                 nsip_lastin = m_copym(m, 0, (int)M_COPYALL, MB_DONTWAIT);
179         }
180         /*
181          * Get IP and IDP header together in first mbuf.
182          */
183         nsipif.if_ipackets++;
184         s = sizeof (struct ip) + sizeof (struct idp);
185         if (((m->m_flags & M_EXT) || m->m_len < s) &&
186             (m = m_pullup(m, s)) == 0) {
187                 nsipif.if_ierrors++;
188                 return;
189         }
190         ip = mtod(m, struct ip *);
191         if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
192                 ip_stripoptions(m);
193                 if (m->m_len < s) {
194                         if ((m = m_pullup(m, s)) == 0) {
195                                 nsipif.if_ierrors++;
196                                 return;
197                         }
198                         ip = mtod(m, struct ip *);
199                 }
200         }
201
202         /*
203          * Make mbuf data length reflect IDP length.
204          * If not enough data to reflect IDP length, drop.
205          */
206         m->m_data += sizeof (struct ip);
207         m->m_len -= sizeof (struct ip);
208         m->m_pkthdr.len -= sizeof (struct ip);
209         idp = mtod(m, struct idp *);
210         len = ntohs(idp->idp_len);
211         if (len & 1) len++;             /* Preserve Garbage Byte */
212         if (ip->ip_len != len) {
213                 if (len > ip->ip_len) {
214                         nsipif.if_ierrors++;
215                         if (nsip_badlen) m_freem(nsip_badlen);
216                         nsip_badlen = m;
217                         return;
218                 }
219                 /* Any extra will be trimmed off by the NS routines */
220         }
221
222         /*
223          * Place interface pointer before the data
224          * for the receiving protocol.
225          */
226         m->m_pkthdr.rcvif = ifp;
227         /*
228          * Deliver to NS
229          */
230         netisr_dispatch(NETISR_NS, m);
231 }
232
233 /* ARGSUSED */
234 static int
235 nsipoutput_serialized(struct ifnet_en *ifn, struct mbuf *m,
236                       struct sockaddr *dst)
237 {
238
239         struct ip *ip;
240         struct route *ro = &(ifn->ifen_route);
241         int len = 0;
242         struct idp *idp = mtod(m, struct idp *);
243         int error;
244
245         ifn->ifen_ifnet.if_opackets++;
246         nsipif.if_opackets++;
247
248
249         /*
250          * Calculate data length and make space
251          * for IP header.
252          */
253         len =  ntohs(idp->idp_len);
254         if (len & 1) len++;             /* Preserve Garbage Byte */
255         /* following clause not necessary on vax */
256         if (3 & (int)m->m_data) {
257                 /* force longword alignment of ip hdr */
258                 struct mbuf *m0 = m_gethdr(MT_HEADER, MB_DONTWAIT);
259                 if (m0 == 0) {
260                         m_freem(m);
261                         return (ENOBUFS);
262                 }
263                 MH_ALIGN(m0, sizeof (struct ip));
264                 m0->m_flags = m->m_flags & M_COPYFLAGS;
265                 m0->m_next = m;
266                 m0->m_len = sizeof (struct ip);
267                 m0->m_pkthdr.len = m0->m_len + m->m_len;
268         } else {
269                 M_PREPEND(m, sizeof (struct ip), MB_DONTWAIT);
270                 if (m == 0)
271                         return (ENOBUFS);
272         }
273         /*
274          * Fill in IP header.
275          */
276         ip = mtod(m, struct ip *);
277         *(long *)ip = 0;
278         ip->ip_p = IPPROTO_IDP;
279         ip->ip_src = ifn->ifen_src;
280         ip->ip_dst = ifn->ifen_dst;
281         ip->ip_len = (u_short)len + sizeof (struct ip);
282         ip->ip_ttl = MAXTTL;
283
284         /*
285          * Output final datagram.
286          */
287         error =  (ip_output(m, NULL, ro, SO_BROADCAST, NULL));
288         if (error) {
289                 ifn->ifen_ifnet.if_oerrors++;
290                 ifn->ifen_ifnet.if_ierrors = error;
291         }
292         return (error);
293 bad:
294         m_freem(m);
295         return (ENETUNREACH);
296 }
297
298 int
299 nsipoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
300            struct rtentry *rt __unused)
301 {
302         int error;
303
304         lwkt_serialize_enter(ifp->if_serializer);
305         error = nsipoutput_serialized(ifp->if_softc, m, dst);
306         lwkt_serialize_exit(ifp->if_serializer);
307
308         return error;
309 }
310
311 void
312 nsipstart(struct ifnet *ifp)
313 {
314         panic("nsip_start called");
315 }
316
317 struct ifreq ifr = {"nsip0"};
318
319 int
320 nsip_route(struct mbuf *m)
321 {
322         struct nsip_req *rq = mtod(m, struct nsip_req *);
323         struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
324         struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
325         struct route ro;
326         struct ifnet_en *ifn;
327         struct sockaddr_in *src;
328
329         /*
330          * First, make sure we already have an ns address:
331          */
332         if (ns_hosteqnh(ns_thishost, ns_zerohost))
333                 return (EADDRNOTAVAIL);
334         /*
335          * Now, determine if we can get to the destination
336          */
337         bzero((caddr_t)&ro, sizeof (ro));
338         ro.ro_dst = *(struct sockaddr *)ip_dst;
339         rtalloc(&ro);
340         if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
341                 return (ENETUNREACH);
342         }
343
344         /*
345          * And see how he's going to get back to us:
346          * i.e., what return ip address do we use?
347          */
348         {
349                 struct in_ifaddr *ia;
350                 struct ifnet *ifp = ro.ro_rt->rt_ifp;
351
352                 for (ia = in_ifaddr; ia; ia = ia->ia_next)
353                         if (ia->ia_ifp == ifp)
354                                 break;
355                 if (ia == 0)
356                         ia = in_ifaddr;
357                 if (ia == 0) {
358                         RTFREE(ro.ro_rt);
359                         return (EADDRNOTAVAIL);
360                 }
361                 src = (struct sockaddr_in *)&ia->ia_addr;
362         }
363
364         /*
365          * Is there a free (pseudo-)interface or space?
366          */
367         for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) {
368                 if ((ifn->ifen_ifnet.if_flags & IFF_UP) == 0)
369                         break;
370         }
371         if (ifn == NULL)
372                 ifn = nsipattach();
373         if (ifn == NULL) {
374                 RTFREE(ro.ro_rt);
375                 return (ENOBUFS);
376         }
377         ifn->ifen_route = ro;
378         ifn->ifen_dst =  ip_dst->sin_addr;
379         ifn->ifen_src = src->sin_addr;
380
381         /*
382          * now configure this as a point to point link
383          */
384         ifr.ifr_name[4] = '0' + nsipif_units - 1;
385         ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
386         ns_control(NULL, (int)SIOCSIFDSTADDR, (caddr_t)&ifr,
387                         (struct ifnet *)ifn, NULL);
388         satons_addr(ifr.ifr_addr).x_host = ns_thishost;
389         return (ns_control(NULL, (int)SIOCSIFADDR, (caddr_t)&ifr,
390                         (struct ifnet *)ifn, NULL));
391 }
392
393 int
394 nsip_free(struct ifnet *ifp)
395 {
396         struct ifnet_en *ifn = (struct ifnet_en *)ifp;
397         struct route *ro = & ifn->ifen_route;
398
399         if (ro->ro_rt) {
400                 RTFREE(ro->ro_rt);
401                 ro->ro_rt = 0;
402         }
403         ifp->if_flags &= ~IFF_UP;
404         return (0);
405 }
406
407 void
408 nsip_ctlinput(int cmd, struct sockaddr *sa)
409 {
410         extern u_char inetctlerrmap[];
411         struct sockaddr_in *sin;
412         int in_rtchange();
413
414         if ((unsigned)cmd >= PRC_NCMDS)
415                 return;
416         if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
417                 return;
418         sin = (struct sockaddr_in *)sa;
419         if (sin->sin_addr.s_addr == INADDR_ANY)
420                 return;
421
422         switch (cmd) {
423
424         case PRC_ROUTEDEAD:
425         case PRC_REDIRECT_NET:
426         case PRC_REDIRECT_HOST:
427         case PRC_REDIRECT_TOSNET:
428         case PRC_REDIRECT_TOSHOST:
429                 nsip_rtchange(&sin->sin_addr);
430                 break;
431         }
432 }
433
434 void
435 nsip_rtchange(struct in_addr *dst)
436 {
437         struct ifnet_en *ifn;
438
439         for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) {
440                 if (ifn->ifen_dst.s_addr == dst->s_addr &&
441                         ifn->ifen_route.ro_rt) {
442                                 RTFREE(ifn->ifen_route.ro_rt);
443                                 ifn->ifen_route.ro_rt = 0;
444                 }
445         }
446 }
447 #endif