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