1 /* 2 * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ns_ip.c 7.8 (Berkeley) 06/05/93 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 * 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 */ 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 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 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, (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 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