1 /* 2 * Copyright (c) 1985 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 6.12 (Berkeley) 12/19/85 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 union ns_net nsip_net; 53 struct mbuf *nsip_list; /* list of all hosts and gateways or 54 broadcast addrs */ 55 56 struct mbuf * 57 nsipattach() 58 { 59 register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB); 60 register struct ifnet *ifp; 61 62 if (m == NULL) return (NULL); 63 m->m_off = MMINOFF; 64 m->m_len = sizeof(struct ifnet_en); 65 m->m_next = nsip_list; 66 nsip_list = m; 67 ifp = mtod(m, struct ifnet *); 68 69 ifp->if_name = "nsip"; 70 ifp->if_mtu = LOMTU; 71 ifp->if_ioctl = nsipioctl; 72 ifp->if_output = nsipoutput; 73 ifp->if_flags = IFF_POINTOPOINT; 74 ifp->if_unit = nsipif.if_unit++; 75 if_attach(ifp); 76 return (dtom(ifp)); 77 } 78 79 80 /* 81 * Process an ioctl request. 82 */ 83 /* ARGSUSED */ 84 nsipioctl(ifp, cmd, data) 85 register struct ifnet *ifp; 86 int cmd; 87 caddr_t data; 88 { 89 int error = 0; 90 struct ifreq *ifr; 91 92 switch (cmd) { 93 94 case SIOCSIFADDR: 95 ifp->if_flags |= IFF_UP; 96 /* fall into: */ 97 98 case SIOCSIFDSTADDR: 99 /* 100 * Everything else is done at a higher level. 101 */ 102 break; 103 104 case SIOCSIFFLAGS: 105 ifr = (struct ifreq *)data; 106 if ((ifr->ifr_flags & IFF_UP) == 0) 107 error = nsip_free(ifp); 108 109 110 default: 111 error = EINVAL; 112 } 113 return (error); 114 } 115 116 struct mbuf *nsip_badlen; 117 struct mbuf *nsip_lastin; 118 int nsip_hold_input; 119 120 idpip_input(m, ifp) 121 register struct mbuf *m; 122 struct ifnet *ifp; 123 { 124 register struct ip *ip; 125 register struct idp *idp; 126 register struct ifqueue *ifq = &nsintrq; 127 int len, s; 128 129 if (nsip_hold_input) { 130 if (nsip_lastin) { 131 m_freem(nsip_lastin); 132 } 133 nsip_lastin = m_copy(m, 0, (int)M_COPYALL); 134 } 135 /* 136 * Get IP and IDP header together in first mbuf. 137 */ 138 nsipif.if_ipackets++; 139 s = sizeof (struct ip) + sizeof (struct idp); 140 if ((m->m_off > MMAXOFF || m->m_len < s) && 141 (m = m_pullup(m, s)) == 0) { 142 nsipif.if_ierrors++; 143 return; 144 } 145 ip = mtod(m, struct ip *); 146 if (ip->ip_hl > (sizeof (struct ip) >> 2)) { 147 ip_stripoptions(ip, (struct mbuf *)0); 148 if (m->m_len < s) { 149 if ((m = m_pullup(m, s)) == 0) { 150 nsipif.if_ierrors++; 151 return; 152 } 153 ip = mtod(m, struct ip *); 154 } 155 } 156 157 /* 158 * Make mbuf data length reflect IDP length. 159 * If not enough data to reflect IDP length, drop. 160 */ 161 m->m_off += sizeof (struct ip); 162 m->m_len -= sizeof (struct ip); 163 idp = mtod(m, struct idp *); 164 len = ntohs(idp->idp_len); 165 if (len & 1) len++; /* Preserve Garbage Byte */ 166 if (ip->ip_len != len) { 167 if (len > ip->ip_len) { 168 nsipif.if_ierrors++; 169 if (nsip_badlen) m_freem(nsip_badlen); 170 nsip_badlen = m; 171 return; 172 } 173 /* Any extra will be trimmed off by the NS routines */ 174 } 175 176 /* 177 * Place interface pointer before the data 178 * for the receiving protocol. 179 */ 180 if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) { 181 m->m_off -= sizeof(struct ifnet *); 182 m->m_len += sizeof(struct ifnet *); 183 } else { 184 struct mbuf *n; 185 186 n = m_get(M_DONTWAIT, MT_HEADER); 187 if (n == (struct mbuf *)0) 188 goto bad; 189 n->m_off = MMINOFF; 190 n->m_len = sizeof(struct ifnet *); 191 n->m_next = m; 192 m = n; 193 } 194 *(mtod(m, struct ifnet **)) = ifp; 195 196 /* 197 * Deliver to NS 198 */ 199 s = splimp(); 200 if (IF_QFULL(ifq)) { 201 IF_DROP(ifq); 202 bad: 203 m_freem(m); 204 splx(s); 205 return; 206 } 207 IF_ENQUEUE(ifq, m); 208 schednetisr(NETISR_NS); 209 splx(s); 210 return; 211 } 212 213 /* ARGSUSED */ 214 nsipoutput(ifn, m0, dst) 215 struct ifnet_en *ifn; 216 struct mbuf *m0; 217 struct sockaddr *dst; 218 { 219 220 register struct mbuf *m = dtom(ifn); 221 register struct ip *ip; 222 register struct route *ro = &(ifn->ifen_route); 223 register int len = 0; 224 register struct idp *idp = mtod(m0, struct idp *); 225 int error; 226 227 if (m->m_len != sizeof(struct ifnet_en)) { 228 printf("nsipoutput: bad dst ifp %x\n", ifn); 229 goto bad; 230 } 231 ifn->ifen_ifnet.if_opackets++; 232 nsipif.if_opackets++; 233 234 235 /* 236 * Calculate data length and make space 237 * for IP header. 238 */ 239 len = ntohs(idp->idp_len); 240 if (len & 1) len++; /* Preserve Garbage Byte */ 241 m = m0; 242 if (m->m_off < MMINOFF + sizeof (struct ip)) { 243 m = m_get(M_DONTWAIT, MT_HEADER); 244 if (m == 0) { 245 m_freem(m0); 246 return (ENOBUFS); 247 } 248 m->m_off = MMAXOFF - sizeof (struct ip); 249 m->m_len = sizeof (struct ip); 250 m->m_next = m0; 251 } else { 252 m->m_off -= sizeof (struct ip); 253 m->m_len += sizeof (struct ip); 254 } 255 /* 256 * Fill in IP header. 257 */ 258 ip = mtod(m, struct ip *); 259 *(long *)ip = 0; 260 ip->ip_p = IPPROTO_IDP; 261 ip->ip_src = ifn->ifen_src; 262 ip->ip_dst = ifn->ifen_dst; 263 ip->ip_len = (u_short)len + sizeof (struct ip); 264 ip->ip_ttl = MAXTTL; 265 266 /* 267 * Output final datagram. 268 */ 269 error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST)); 270 if (error) { 271 ifn->ifen_ifnet.if_oerrors++; 272 ifn->ifen_ifnet.if_ierrors = error; 273 } 274 return (error); 275 bad: 276 m_freem(m0); 277 return (ENETUNREACH); 278 } 279 280 struct ifreq ifr = {"nsip0"}; 281 282 nsip_route(m) 283 register struct mbuf *m; 284 { 285 register struct nsip_req *rq = mtod(m, struct nsip_req *); 286 struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns; 287 struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip; 288 struct route ro; 289 struct ifnet_en *ifn; 290 struct sockaddr_in *src; 291 292 /* 293 * First, make sure we already have an ns address: 294 */ 295 if (ns_hosteqnh(ns_thishost, ns_zerohost)) 296 return (EADDRNOTAVAIL); 297 /* 298 * Now, determine if we can get to the destination 299 */ 300 bzero((caddr_t)&ro, sizeof (ro)); 301 ro.ro_dst = *(struct sockaddr *)ip_dst; 302 rtalloc(&ro); 303 if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) { 304 return (ENETUNREACH); 305 } 306 307 /* 308 * And see how he's going to get back to us: 309 * i.e., what return ip address do we use? 310 */ 311 { 312 register struct in_ifaddr *ia; 313 struct ifnet *ifp = ro.ro_rt->rt_ifp; 314 315 for (ia = in_ifaddr; ia; ia = ia->ia_next) 316 if (ia->ia_ifp == ifp) 317 break; 318 if (ia == 0) 319 ia = in_ifaddr; 320 if (ia == 0) { 321 RTFREE(ro.ro_rt); 322 return (EADDRNOTAVAIL); 323 } 324 src = (struct sockaddr_in *)&ia->ia_addr; 325 } 326 327 /* 328 * Is there a free (pseudo-)interface or space? 329 */ 330 for (m = nsip_list; m; m = m->m_next) { 331 struct ifnet *ifp = mtod(m, struct ifnet *); 332 if ((ifp->if_flags & IFF_UP) == 0) 333 break; 334 } 335 if (m == (struct mbuf *) 0) 336 m = nsipattach(); 337 if (m == NULL) { 338 RTFREE(ro.ro_rt); 339 return (ENOBUFS); 340 } 341 ifn = mtod(m, struct ifnet_en *); 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, (int)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, (int)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 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 401 nsip_rtchange(dst) 402 register struct in_addr *dst; 403 { 404 register struct mbuf *m; 405 register struct ifnet_en *ifn; 406 407 for (m = nsip_list; m; m = m->m_next) { 408 ifn = mtod(m, struct ifnet_en *); 409 if (ifn->ifen_dst.s_addr == dst->s_addr && 410 ifn->ifen_route.ro_rt) { 411 RTFREE(ifn->ifen_route.ro_rt); 412 ifn->ifen_route.ro_rt = 0; 413 } 414 } 415 } 416 #endif 417