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