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