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.10 (Berkeley) 10/15/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 #ifndef BBNNET 149 if (ip->ip_hl > (sizeof (struct ip) >> 2)) { 150 ip_stripoptions(ip, (struct mbuf *)0); 151 if (m->m_len < s) { 152 if ((m = m_pullup(m, s))==0) { 153 nsipif.if_ierrors++; 154 return; 155 } 156 ip = mtod(m, struct ip *); 157 } 158 } 159 #endif 160 161 /* 162 * Make mbuf data length reflect IDP length. 163 * If not enough data to reflect IDP length, drop. 164 */ 165 m->m_off += sizeof (struct ip); 166 m->m_len -= sizeof (struct ip); 167 idp = mtod(m, struct idp *); 168 len = ntohs(idp->idp_len); 169 if (len & 1) len++; /* Preserve Garbage Byte */ 170 if (ip->ip_len != len) { 171 if (len > ip->ip_len) { 172 nsipif.if_ierrors++; 173 if(nsip_badlen) m_freem(nsip_badlen); 174 nsip_badlen = m; 175 return; 176 } 177 /* Any extra will be trimmed off by the NS routines */ 178 } 179 180 /* 181 * Place interface pointer before the data 182 * for the receiving protocol. 183 */ 184 if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) { 185 m->m_off -= sizeof(struct ifnet *); 186 m->m_len += sizeof(struct ifnet *); 187 } else { 188 struct mbuf *n; 189 190 n = m_get(M_DONTWAIT, MT_HEADER); 191 if (n == (struct mbuf *)0) 192 goto bad; 193 n->m_off = MMINOFF; 194 n->m_len = sizeof(struct ifnet *); 195 n->m_next = m; 196 m = n; 197 } 198 *(mtod(m, struct ifnet **)) = ifp; 199 200 /* 201 * Deliver to NS 202 */ 203 s = splimp(); 204 if (IF_QFULL(ifq)) { 205 IF_DROP(ifq); 206 bad: 207 m_freem(m); 208 splx(s); 209 return; 210 } 211 IF_ENQUEUE(ifq, m); 212 schednetisr(NETISR_NS); 213 splx(s); 214 return; 215 } 216 217 /* ARGSUSED */ 218 nsipoutput(ifn, m0, dst) 219 struct ifnet_en *ifn; 220 struct mbuf *m0; 221 struct sockaddr *dst; 222 { 223 224 register struct mbuf *m = dtom(ifn); 225 register struct ip *ip; 226 register struct route *ro = &(ifn->ifen_route); 227 register int len = 0; 228 register struct idp *idp = mtod(m0, struct idp *); 229 int error; 230 231 if (m->m_len != sizeof(struct ifnet_en)) { 232 printf("nsipoutput: bad dst ifp %x\n", ifn); 233 goto bad; 234 } 235 ifn->ifen_ifnet.if_opackets++; 236 nsipif.if_opackets++; 237 238 239 /* 240 * Calculate data length and make space 241 * for IP header. 242 */ 243 len = ntohs(idp->idp_len); 244 if (len & 1) len++; /* Preserve Garbage Byte */ 245 m = m0; 246 if(m->m_off < MMINOFF + sizeof (struct ip)) { 247 m = m_get(M_DONTWAIT, MT_HEADER); 248 if (m == 0) { 249 m_freem(m0); 250 return (ENOBUFS); 251 } 252 m->m_off = MMAXOFF - sizeof (struct ip); 253 m->m_len = sizeof (struct ip); 254 m->m_next = m0; 255 } else { 256 m->m_off -= sizeof (struct ip); 257 m->m_len += sizeof (struct ip); 258 } 259 /* 260 * Fill in IP header. 261 */ 262 ip = mtod(m, struct ip *); 263 *(long *)ip = 0; 264 ip->ip_p = IPPROTO_IDP; 265 ip->ip_src = ifn->ifen_src; 266 ip->ip_dst = ifn->ifen_dst; 267 #ifdef BBNNET 268 ip->ip_tos = 0; 269 NOPCB_IPSEND(m, len, 0, error); 270 #else 271 ip->ip_len = (u_short)len + sizeof (struct ip); 272 ip->ip_ttl = MAXTTL; 273 274 /* 275 * Output final datagram. 276 */ 277 error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST)); 278 #endif 279 if (error) { 280 ifn->ifen_ifnet.if_oerrors++; 281 ifn->ifen_ifnet.if_ierrors = error; 282 } 283 return (error); 284 bad: 285 m_freem(m0); 286 return(ENETUNREACH); 287 } 288 289 struct ifreq ifr = {"nsip0"}; 290 291 nsip_route(m) 292 register struct mbuf *m; 293 { 294 register struct nsip_req *rq = mtod(m, struct nsip_req *); 295 struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns; 296 struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip; 297 struct route ro; 298 struct ifnet_en *ifn; 299 struct sockaddr_in *src; 300 /* 301 * First, 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 * And see how he's going to get back to us: 311 */ 312 { 313 register struct in_ifaddr *ia; 314 struct ifnet *ifp = ro.ro_rt->rt_ifp; 315 316 for (ia = in_ifaddr; ia; ia = ia->ia_next) 317 if (ia->ia_ifp == ifp) 318 break; 319 if (ia == 0) 320 ia = in_ifaddr; 321 if (ia == 0) { 322 return (EADDRNOTAVAIL); 323 } 324 src = (struct sockaddr_in *)&ia->ia_addr; 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) {return (ENOBUFS);} 337 ifn = mtod(m, struct ifnet_en *); 338 339 ro.ro_rt->rt_use++; 340 ifn->ifen_route = ro; 341 ifn->ifen_dst = ip_dst->sin_addr; 342 ifn->ifen_src = src->sin_addr; 343 344 /* 345 * now configure this as a point to point link 346 */ 347 ifr.ifr_name[4] = '0' + nsipif.if_unit - 1; 348 ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst; 349 return(ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr, 350 (struct ifnet *)ifn)); 351 } 352 353 nsip_free(ifp) 354 struct ifnet *ifp; 355 { 356 register struct ifnet_en *ifn = (struct ifnet_en *)ifp; 357 struct route *ro = & ifn->ifen_route; 358 359 if (ro->ro_rt) { 360 RTFREE(ro->ro_rt); 361 ro->ro_rt = 0; 362 } 363 ifp->if_flags &= ~IFF_UP; 364 return (0); 365 } 366 367 nsip_ctlinput(cmd, sa) 368 int cmd; 369 struct sockaddr *sa; 370 { 371 extern u_char inetctlerrmap[]; 372 struct sockaddr_in *sin; 373 int in_rtchange(); 374 375 if ((unsigned)cmd > PRC_NCMDS) 376 return; 377 if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) 378 return; 379 sin = (struct sockaddr_in *)sa; 380 if (sin->sin_addr.s_addr == INADDR_ANY) 381 return; 382 383 switch (cmd) { 384 385 case PRC_ROUTEDEAD: 386 case PRC_REDIRECT_NET: 387 case PRC_REDIRECT_HOST: 388 case PRC_REDIRECT_TOSNET: 389 case PRC_REDIRECT_TOSHOST: 390 nsip_rtchange(&sin->sin_addr); 391 break; 392 } 393 } 394 395 nsip_rtchange(dst) 396 register struct in_addr *dst; 397 { 398 register struct mbuf *m; 399 register struct ifnet_en *ifn; 400 401 for (m = nsip_list; m; m = m->m_next) { 402 ifn = mtod(m, struct ifnet_en *); 403 if (ifn->ifen_dst.s_addr == dst->s_addr && 404 ifn->ifen_route.ro_rt) { 405 RTFREE(ifn->ifen_route.ro_rt); 406 ifn->ifen_route.ro_rt = 0; 407 } 408 } 409 } 410 #endif 411