1 /* ns_input.c 6.1 85/05/30 */ 2 3 #include "param.h" 4 #include "systm.h" 5 #include "mbuf.h" 6 #include "domain.h" 7 #include "protosw.h" 8 #include "socket.h" 9 #include "socketvar.h" 10 #include "errno.h" 11 #include "time.h" 12 #include "kernel.h" 13 14 #include "../net/if.h" 15 #include "../net/route.h" 16 #include "../net/raw_cb.h" 17 18 #include "ns.h" 19 #include "ns_if.h" 20 #include "ns_pcb.h" 21 #include "idp.h" 22 #include "idp_var.h" 23 #include "ns_error.h" 24 25 /* 26 * NS initialization. 27 */ 28 union ns_host ns_thishost; 29 union ns_host ns_zerohost; 30 union ns_host ns_broadhost; 31 32 static char allones[] = {-1, -1, -1, -1, -1, -1}; 33 34 struct nspcb nspcb; 35 struct nspcb nsrawpcb; 36 37 struct ifqueue nsintrq; 38 int nsqmaxlen = IFQ_MAXLEN; 39 40 int idpcksum = 0; 41 42 ns_init() 43 { 44 ns_broadhost = * (union ns_host *) allones; 45 nspcb.nsp_next = nspcb.nsp_prev = &nspcb; 46 nsrawpcb.nsp_next = nsrawpcb.nsp_prev = &nsrawpcb; 47 nsintrq.ifq_maxlen = nsqmaxlen; 48 } 49 50 /* 51 * Idp input routine. Pass to next level. 52 */ 53 int nsintr_getpck = 0; 54 int nsintr_swtch = 0; 55 nsintr() 56 { 57 register struct idp *idp; 58 register struct mbuf *m; 59 struct nspcb *nsp; 60 struct mbuf *m0; 61 register int i; 62 int len, s, error; 63 char oddpacketp; 64 65 next: 66 /* 67 * Get next datagram off input queue and get IDP header 68 * in first mbuf. 69 */ 70 s = splimp(); 71 IF_DEQUEUE(&nsintrq, m); 72 splx(s); 73 nsintr_getpck++; 74 if (m == 0) 75 return; 76 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct idp)) && 77 (m = m_pullup(m, sizeof (struct idp))) == 0) { 78 idpstat.idps_toosmall++; 79 goto next; 80 } 81 82 /* 83 * Give any raw listeners a crack at the packet 84 */ 85 for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) { 86 struct mbuf *m1 = m_copy(m, 0, M_COPYALL); 87 if (m1) idp_input(m1, nsp); 88 } 89 90 idp = mtod(m, struct idp *); 91 len = ntohs(idp->idp_len); 92 if (oddpacketp = len & 1) { 93 len++; /* If this packet is of odd length, 94 preserve garbage byte for checksum */ 95 } 96 97 /* 98 * Check that the amount of data in the buffers 99 * is as at least much as the IDP header would have us expect. 100 * Trim mbufs if longer than we expect. 101 * Drop packet if shorter than we expect. 102 */ 103 i = -len; 104 m0 = m; 105 for (;;) { 106 i += m->m_len; 107 if (m->m_next == 0) 108 break; 109 m = m->m_next; 110 } 111 if (i != 0) { 112 if (i < 0) { 113 idpstat.idps_tooshort++; 114 m = m0; 115 goto bad; 116 } 117 if (i <= m->m_len) 118 m->m_len -= i; 119 else 120 m_adj(m0, -i); 121 } 122 m = m0; 123 if (idpcksum && ((i = idp->idp_sum)!=0xffff)) { 124 idp->idp_sum = 0; 125 if (i != (idp->idp_sum = ns_cksum(m,len))) { 126 idpstat.idps_badsum++; 127 if (ns_hosteqnh(ns_thishost, idp->idp_dna.x_host)) 128 error = NS_ERR_BADSUM; 129 else 130 error = NS_ERR_BADSUM_T; 131 ns_error(m, error, 0); 132 goto next; 133 } 134 } 135 /* 136 * Is this a directed broadcast? 137 */ 138 if (ns_hosteqnh(ns_broadhost,idp->idp_dna.x_host)) { 139 if ((ns_netof(idp->idp_dna)!=ns_netof(idp->idp_sna)) && 140 (ns_netof(idp->idp_dna)!=-1) && (ns_netof(idp->idp_sna)!=0) 141 && (ns_netof(idp->idp_dna)!=0)) { 142 /* 143 * Look to see if I need to eat this packet as well. 144 */ 145 struct ns_ifaddr *ia = 146 ns_iaonnetof(idp->idp_dna.x_net); 147 if (ia) { 148 m = m_copy(m, 0, M_COPYALL); 149 } else 150 m = NULL; 151 idp_forward(idp); 152 if (m==NULL) 153 goto next; 154 idp = mtod(m, struct idp *); 155 } 156 /* 157 * Is this our packet? If not, forward. 158 */ 159 } else if (!ns_hosteqnh(ns_thishost,idp->idp_dna.x_host)) { 160 idp_forward(idp); 161 goto next; 162 } 163 164 /* 165 * Locate pcb for datagram. 166 */ 167 nsp = ns_pcblookup(&idp->idp_sna, idp->idp_dna.x_port, NS_WILDCARD); 168 169 170 /* 171 * Switch out to protocol's input routine. 172 */ 173 174 nsintr_swtch++; 175 if (nsp) { 176 if (oddpacketp) { 177 m_adj(m0, -1); 178 } 179 switch (idp->idp_pt) { 180 case NSPROTO_SPP: 181 spp_input(m,nsp); 182 break; 183 case NSPROTO_ERROR: 184 ns_err_input(m); 185 break; 186 default: 187 idp_input(m,nsp); 188 } 189 } else { 190 /* don't send ERROR response for multicast packet */ 191 if (idp->idp_dna.x_host.c_host[0] & 1) 192 goto bad; 193 ns_error(m, NS_ERR_NOSOCK, 0); 194 } 195 goto next; 196 197 bad: 198 m_freem(m); 199 goto next; 200 } 201 202 u_char nsctlerrmap[PRC_NCMDS] = { 203 ECONNABORTED, ECONNABORTED, 0, 0, 204 0, 0, EHOSTDOWN, EHOSTUNREACH, 205 ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 206 EMSGSIZE, 0, 0, 0, 207 0, 0, 0, 0 208 }; 209 210 idp_ctlinput(cmd, arg) 211 int cmd; 212 caddr_t arg; 213 { 214 struct ns_addr *ns; 215 int idp_abort(); 216 int type; 217 218 if (cmd < 0 || cmd > PRC_NCMDS) 219 return; 220 if (nsctlerrmap[cmd] == 0) 221 return; /* XXX */ 222 type = NS_ERR_UNREACH_HOST; 223 if (cmd == PRC_IFDOWN) 224 ns = &((struct sockaddr_ns *)arg)->sns_addr; 225 else if (cmd == PRC_HOSTDEAD || cmd == PRC_HOSTUNREACH) 226 ns = (struct ns_addr *)arg; 227 else { 228 ns = &((struct ns_errp *)arg)->ns_err_idp.idp_dna; 229 type = ((struct ns_errp *)arg)->ns_err_num; 230 type = ntohs(type); 231 } 232 switch (type) { 233 case NS_ERR_UNREACH_HOST: 234 case NS_ERR_NOSOCK: 235 ns_pcbnotify(ns, (int)nsctlerrmap[cmd], idp_abort, 0); 236 } 237 } 238 239 int idpprintfs = 0; 240 int idpforwarding = 1; 241 /* 242 * Forward a packet. If some error occurs return the sender 243 * an error packet. Note we can't always generate a meaningful 244 * error message because the NS errors don't have a large enough repetoire 245 * of codes and types. 246 */ 247 struct route idp_droute; 248 struct route idp_sroute; 249 250 idp_forward(idp) 251 register struct idp *idp; 252 { 253 register int error, type, code; 254 struct mbuf *mopt, *mcopy; 255 256 if (idpprintfs) { 257 printf("forward: src "); 258 ns_printhost(&idp->idp_sna); 259 printf(", dst "); 260 ns_printhost(&idp->idp_dna); 261 printf("hop count %d\n", idp->idp_tc); 262 } 263 if (idpforwarding == 0) { 264 /* can't tell difference between net and host */ 265 type = NS_ERR_UNREACH_HOST, code = 0; 266 goto senderror; 267 } 268 idp->idp_tc++; 269 if (idp->idp_tc > NS_MAXHOPS) { 270 type = NS_ERR_TOO_OLD, code = 0; 271 goto senderror; 272 } 273 /* need to adjust checksum */ 274 if (idp->idp_sum!=0xffff) { 275 union bytes { 276 u_char c[4]; 277 u_short s[2]; 278 long l; 279 } x; 280 register int shift; 281 x.l = 0; x.c[0] = 1; 282 shift = (((((int)ntohs(idp->idp_len))+1)>>1)-2) & 0xf; 283 x.l = idp->idp_sum + (x.l << shift); 284 x.l = x.s[0] + x.s[1]; 285 x.l = x.s[0] + x.s[1]; 286 if (x.l==0xffff) idp->idp_sum = 0; else idp->idp_sum = x.l; 287 } 288 mopt = m_get(M_DONTWAIT, MT_DATA); 289 if (mopt == NULL) { 290 m_freem(dtom(idp)); 291 return; 292 } 293 294 /* 295 * Save at most 42 bytes of the packet in case 296 * we need to generate an NS error message to the src. 297 */ 298 mcopy = m_copy(dtom(idp), 0, imin(ntohs(idp->idp_len), 42)); 299 300 if ((idp->idp_dna.x_host.c_host[0] & 0x1) == 0) 301 error = ns_output(dtom(idp), (struct route *)0, NS_FORWARDING); 302 /* 303 * Here we are about to forward a broadcast packet, 304 * so we try to insure that it doesn't go back out 305 * on the interface it came in on. 306 */ 307 else if (idp_do_route(&idp->idp_dna,&idp_droute)) { 308 if (idp_do_route(&idp->idp_sna,&idp_sroute)) { 309 struct ifnet *ifp; 310 311 if (idp_droute.ro_rt && 312 (ifp=idp_droute.ro_rt->rt_ifp) && 313 idp_sroute.ro_rt && 314 (ifp!=idp_sroute.ro_rt->rt_ifp)) { 315 error = ns_output(dtom(idp), &idp_droute, 316 NS_FORWARDING|NS_ALLOWBROADCAST); 317 } 318 idp_undo_route(&idp_sroute); 319 } 320 idp_undo_route(&idp_droute); 321 } 322 323 if (error == 0) { 324 if (mcopy) 325 m_freem(mcopy); 326 return; 327 } 328 if (mcopy == NULL) 329 return; 330 idp = mtod(mcopy, struct idp *); 331 type = NS_ERR_UNSPEC_T, code = 0; 332 switch (error) { 333 334 case ENETUNREACH: 335 case EHOSTDOWN: 336 case EHOSTUNREACH: 337 case ENETDOWN: 338 case EPERM: 339 type = NS_ERR_UNREACH_HOST; 340 break; 341 342 case EMSGSIZE: 343 type = NS_ERR_TOO_BIG; 344 code = 576; /* too hard to figure out mtu here */ 345 break; 346 347 case ENOBUFS: 348 type = NS_ERR_UNSPEC_T; 349 break; 350 } 351 senderror: 352 ns_error(dtom(idp), type, code); 353 } 354 355 idp_do_route(src, ro) 356 struct ns_addr *src; 357 struct route *ro; 358 { 359 360 struct sockaddr_ns *dst; 361 362 bzero((caddr_t)ro, sizeof (*ro)); 363 dst = (struct sockaddr_ns *)&ro->ro_dst; 364 365 dst->sns_family = AF_NS; 366 dst->sns_addr = *src; 367 rtalloc(ro); 368 if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) { 369 return(0); 370 } 371 ro->ro_rt->rt_use++; 372 return(1); 373 } 374 375 idp_undo_route(ro) 376 register struct route *ro; 377 { 378 if (ro->ro_rt) {RTFREE(ro->ro_rt);} 379 } 380 ns_watch_output(m) 381 struct mbuf *m; 382 { 383 register struct nspcb *nsp; 384 /* 385 * Give any raw listeners a crack at the packet 386 */ 387 for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) { 388 struct mbuf *m1 = m_copy(m, 0, M_COPYALL); 389 if (m1) idp_input(m1, nsp); 390 } 391 } 392