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