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