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