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