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.9 (Berkeley) 10/01/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 #ifdef BBNNET 42 #include "../bbnnet/in_pcb.h" 43 #include "../bbnnet/nopcb.h" 44 #endif 45 46 struct ifnet_en { 47 struct ifnet ifen_ifnet; 48 struct route ifen_route; 49 struct in_addr ifen_src; 50 struct in_addr ifen_dst; 51 }; 52 53 int nsipoutput(), nsipioctl(); 54 #define LOMTU (1024+512); 55 56 struct ifnet nsipif; 57 union ns_net nsip_net; 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==0) return (0); 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 /* 102 * Everything else is done at a higher level. 103 */ 104 break; 105 106 case SIOCSIFFLAGS: 107 ifr = (struct ifreq *)data; 108 if ((ifr->ifr_flags & IFF_UP) == 0) 109 error = nsip_free(ifp); 110 111 112 default: 113 error = EINVAL; 114 } 115 return (error); 116 } 117 118 struct mbuf *nsip_badlen; 119 struct mbuf *nsip_lastin; 120 int nsip_hold_input; 121 122 idpip_input(m, ifp) 123 register struct mbuf *m; 124 struct ifnet *ifp; 125 { 126 register struct ip *ip; 127 register struct idp *idp; 128 register struct ifqueue *ifq = &nsintrq; 129 int len, s; 130 131 if(nsip_hold_input) { 132 if(nsip_lastin) { 133 m_freem(nsip_lastin); 134 } 135 nsip_lastin = m_copy(m, 0, (int)M_COPYALL); 136 } 137 /* 138 * Get IP and IDP header together in first mbuf. 139 */ 140 nsipif.if_ipackets++; 141 s = sizeof (struct ip) + sizeof (struct idp); 142 if ((m->m_off > MMAXOFF || m->m_len < s) && 143 (m = m_pullup(m, s))==0) { 144 nsipif.if_ierrors++; 145 return; 146 } 147 ip = mtod(m, struct ip *); 148 if (ip->ip_hl > (sizeof (struct ip) >> 2)) { 149 ip_stripoptions(ip, (struct mbuf *)0); 150 if (m->m_len < s) { 151 if ((m = m_pullup(m, s))==0) { 152 nsipif.if_ierrors++; 153 return; 154 } 155 ip = mtod(m, struct ip *); 156 } 157 } 158 159 /* 160 * Make mbuf data length reflect IDP length. 161 * If not enough data to reflect IDP length, drop. 162 */ 163 m->m_off += sizeof (struct ip); 164 m->m_len -= sizeof (struct ip); 165 idp = mtod(m, struct idp *); 166 len = ntohs(idp->idp_len); 167 if (len & 1) len++; /* Preserve Garbage Byte */ 168 if (ip->ip_len != len) { 169 if (len > ip->ip_len) { 170 nsipif.if_ierrors++; 171 if(nsip_badlen) m_freem(nsip_badlen); 172 nsip_badlen = m; 173 return; 174 } 175 /* Any extra will be trimmed off by the NS routines */ 176 } 177 178 /* 179 * Place interface pointer before the data 180 * for the receiving protocol. 181 */ 182 if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) { 183 m->m_off -= sizeof(struct ifnet *); 184 m->m_len += sizeof(struct ifnet *); 185 } else { 186 struct mbuf *n; 187 188 n = m_get(M_DONTWAIT, MT_HEADER); 189 if (n == (struct mbuf *)0) 190 goto bad; 191 n->m_off = MMINOFF; 192 n->m_len = sizeof(struct ifnet *); 193 n->m_next = m; 194 m = n; 195 } 196 *(mtod(m, struct ifnet **)) = ifp; 197 198 /* 199 * Deliver to NS 200 */ 201 s = splimp(); 202 if (IF_QFULL(ifq)) { 203 IF_DROP(ifq); 204 bad: 205 m_freem(m); 206 splx(s); 207 return; 208 } 209 IF_ENQUEUE(ifq, m); 210 schednetisr(NETISR_NS); 211 splx(s); 212 return; 213 } 214 215 /* ARGSUSED */ 216 nsipoutput(ifn, m0, dst) 217 struct ifnet_en *ifn; 218 struct mbuf *m0; 219 struct sockaddr *dst; 220 { 221 222 register struct mbuf *m = dtom(ifn); 223 register struct ip *ip; 224 register struct route *ro = &(ifn->ifen_route); 225 register int len = 0; 226 register struct idp *idp = mtod(m0, struct idp *); 227 int error; 228 229 if (m->m_len != sizeof(struct ifnet_en)) { 230 printf("nsipoutput: bad dst ifp %x\n", ifn); 231 goto bad; 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 m = m0; 244 if(m->m_off < MMINOFF + sizeof (struct ip)) { 245 m = m_get(M_DONTWAIT, MT_HEADER); 246 if (m == 0) { 247 m_freem(m0); 248 return (ENOBUFS); 249 } 250 m->m_off = MMAXOFF - sizeof (struct ip); 251 m->m_len = sizeof (struct ip); 252 m->m_next = m0; 253 } else { 254 m->m_off -= sizeof (struct ip); 255 m->m_len += sizeof (struct ip); 256 } 257 /* 258 * Fill in IP header. 259 */ 260 ip = mtod(m, struct ip *); 261 *(long *)ip = 0; 262 ip->ip_p = IPPROTO_IDP; 263 ip->ip_src = ifn->ifen_src; 264 ip->ip_dst = ifn->ifen_dst; 265 #ifdef BBNNET 266 ip->ip_tos = 0; 267 NOPCB_IPSEND(m, len, 0, error); 268 #else 269 ip->ip_len = (u_short)len + sizeof (struct ip); 270 ip->ip_ttl = MAXTTL; 271 272 /* 273 * Output final datagram. 274 */ 275 error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST)); 276 #endif 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(m0); 284 return(ENETUNREACH); 285 } 286 287 struct ifreq ifr = {"nsip0"}; 288 289 nsip_route(m) 290 register struct mbuf *m; 291 { 292 register struct nsip_req *rq = mtod(m, struct nsip_req *); 293 struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns; 294 struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip; 295 struct route ro; 296 struct ifnet_en *ifn; 297 struct sockaddr_in *src; 298 /* 299 * First, determine if we can get to the destination 300 */ 301 bzero((caddr_t)&ro, sizeof (ro)); 302 ro.ro_dst = *(struct sockaddr *)ip_dst; 303 rtalloc(&ro); 304 if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) { 305 return (ENETUNREACH); 306 } 307 /* 308 * And see how he's going to get back to us: 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 return (EADDRNOTAVAIL); 321 } 322 src = (struct sockaddr_in *)&ia->ia_addr; 323 } 324 /* 325 * Is there a free (pseudo-)interface or space? 326 */ 327 for (m = nsip_list; m; m = m->m_next) { 328 struct ifnet *ifp = mtod(m, struct ifnet *); 329 if ((ifp->if_flags & IFF_UP) == 0) 330 break; 331 } 332 if (m == (struct mbuf *) 0) 333 m = nsipattach(); 334 if (m==NULL) {return (ENOBUFS);} 335 ifn = mtod(m, struct ifnet_en *); 336 337 ro.ro_rt->rt_use++; 338 ifn->ifen_route = ro; 339 ifn->ifen_dst = ip_dst->sin_addr; 340 ifn->ifen_src = src->sin_addr; 341 342 /* 343 * now configure this as a point to point link 344 */ 345 ifr.ifr_name[4] = '0' + nsipif.if_unit - 1; 346 ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst; 347 return(ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr, 348 (struct ifnet *)ifn)); 349 } 350 351 nsip_free(ifp) 352 struct ifnet *ifp; 353 { 354 register struct ifnet_en *ifn = (struct ifnet_en *)ifp; 355 struct route *ro = & ifn->ifen_route; 356 357 if (ro->ro_rt) { 358 RTFREE(ro->ro_rt); 359 ro->ro_rt = 0; 360 } 361 ifp->if_flags &= ~IFF_UP; 362 return (0); 363 } 364 365 nsip_ctlinput(cmd, sa) 366 int cmd; 367 struct sockaddr *sa; 368 { 369 extern u_char inetctlerrmap[]; 370 struct sockaddr_in *sin; 371 int in_rtchange(); 372 373 if ((unsigned)cmd > PRC_NCMDS) 374 return; 375 if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 376 return; 377 sin = (struct sockaddr_in *)sa; 378 if (sin->sin_addr.s_addr == INADDR_ANY) 379 return; 380 381 switch (cmd) { 382 383 case PRC_ROUTEDEAD: 384 case PRC_REDIRECT_NET: 385 case PRC_REDIRECT_HOST: 386 case PRC_REDIRECT_TOSNET: 387 case PRC_REDIRECT_TOSHOST: 388 nsip_rtchange(&sin->sin_addr); 389 break; 390 } 391 } 392 393 nsip_rtchange(dst) 394 register struct in_addr *dst; 395 { 396 register struct mbuf *m; 397 register struct ifnet_en *ifn; 398 399 for (m = nsip_list; m; m = m->m_next) 400 if (ifn->ifen_dst.s_addr == dst->s_addr && 401 ifn->ifen_route.ro_rt) { 402 RTFREE(ifn->ifen_route.ro_rt); 403 ifn->ifen_route.ro_rt = 0; 404 } 405 } 406 #endif 407