1 /* 2 * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)ns_input.c 7.5 (Berkeley) 10/12/88 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "malloc.h" 23 #include "mbuf.h" 24 #include "domain.h" 25 #include "protosw.h" 26 #include "socket.h" 27 #include "socketvar.h" 28 #include "errno.h" 29 #include "time.h" 30 #include "kernel.h" 31 32 #include "../net/if.h" 33 #include "../net/route.h" 34 #include "../net/raw_cb.h" 35 36 #include "ns.h" 37 #include "ns_if.h" 38 #include "ns_pcb.h" 39 #include "idp.h" 40 #include "idp_var.h" 41 #include "ns_error.h" 42 43 /* 44 * NS initialization. 45 */ 46 union ns_host ns_thishost; 47 union ns_host ns_zerohost; 48 union ns_host ns_broadhost; 49 union ns_net ns_zeronet; 50 union ns_net ns_broadnet; 51 52 static u_short allones[] = {-1, -1, -1}; 53 54 struct nspcb nspcb; 55 struct nspcb nsrawpcb; 56 57 struct ifqueue nsintrq; 58 int nsqmaxlen = IFQ_MAXLEN; 59 60 int idpcksum = 1; 61 long ns_pexseq; 62 63 ns_init() 64 { 65 extern struct timeval time; 66 67 ns_broadhost = * (union ns_host *) allones; 68 ns_broadnet = * (union ns_net *) allones; 69 nspcb.nsp_next = nspcb.nsp_prev = &nspcb; 70 nsrawpcb.nsp_next = nsrawpcb.nsp_prev = &nsrawpcb; 71 nsintrq.ifq_maxlen = nsqmaxlen; 72 ns_pexseq = time.tv_usec; 73 } 74 75 /* 76 * Idp input routine. Pass to next level. 77 */ 78 int nsintr_getpck = 0; 79 int nsintr_swtch = 0; 80 nsintr() 81 { 82 register struct idp *idp; 83 register struct mbuf *m; 84 register struct nspcb *nsp; 85 struct ifnet *ifp; 86 struct mbuf *m0; 87 register int i; 88 int len, s, error; 89 char oddpacketp; 90 91 next: 92 /* 93 * Get next datagram off input queue and get IDP header 94 * in first mbuf. 95 */ 96 s = splimp(); 97 IF_DEQUEUE(&nsintrq, m); 98 splx(s); 99 nsintr_getpck++; 100 if (m == 0) 101 return; 102 if ((m->m_flags & M_EXT || m->m_len < sizeof (struct idp)) && 103 (m = m_pullup(m, sizeof (struct idp))) == 0) { 104 idpstat.idps_toosmall++; 105 goto next; 106 } 107 108 /* 109 * Give any raw listeners a crack at the packet 110 */ 111 for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) { 112 struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL); 113 if (m1) idp_input(m1, nsp); 114 } 115 116 idp = mtod(m, struct idp *); 117 len = ntohs(idp->idp_len); 118 if (oddpacketp = len & 1) { 119 len++; /* If this packet is of odd length, 120 preserve garbage byte for checksum */ 121 } 122 123 /* 124 * Check that the amount of data in the buffers 125 * is as at least much as the IDP header would have us expect. 126 * Trim mbufs if longer than we expect. 127 * Drop packet if shorter than we expect. 128 */ 129 if (m->m_pkthdr.len < len) { 130 idpstat.idps_tooshort++; 131 goto bad; 132 } 133 if (m->m_pkthdr.len > len) { 134 if (m->m_len == m->m_pkthdr.len) { 135 m->m_len = len; 136 m->m_pkthdr.len = len; 137 } else 138 m_adj(m, len - m->m_pkthdr.len); 139 } 140 if (idpcksum && ((i = idp->idp_sum)!=0xffff)) { 141 idp->idp_sum = 0; 142 if (i != (idp->idp_sum = ns_cksum(m, len))) { 143 idpstat.idps_badsum++; 144 idp->idp_sum = i; 145 if (ns_hosteqnh(ns_thishost, idp->idp_dna.x_host)) 146 error = NS_ERR_BADSUM; 147 else 148 error = NS_ERR_BADSUM_T; 149 ns_error(m, error, 0); 150 goto next; 151 } 152 } 153 /* 154 * Is this a directed broadcast? 155 */ 156 if (ns_hosteqnh(ns_broadhost,idp->idp_dna.x_host)) { 157 if ((!ns_neteq(idp->idp_dna, idp->idp_sna)) && 158 (!ns_neteqnn(idp->idp_dna.x_net, ns_broadnet)) && 159 (!ns_neteqnn(idp->idp_sna.x_net, ns_zeronet)) && 160 (!ns_neteqnn(idp->idp_dna.x_net, ns_zeronet)) ) { 161 /* 162 * Look to see if I need to eat this packet. 163 * Algorithm is to forward all young packets 164 * and prematurely age any packets which will 165 * by physically broadcasted. 166 * Any very old packets eaten without forwarding 167 * would die anyway. 168 * 169 * Suggestion of Bill Nesheim, Cornell U. 170 */ 171 if (idp->idp_tc < NS_MAXHOPS) { 172 idp_forward(m); 173 goto next; 174 } 175 } 176 /* 177 * Is this our packet? If not, forward. 178 */ 179 } else if (!ns_hosteqnh(ns_thishost,idp->idp_dna.x_host)) { 180 idp_forward(m); 181 goto next; 182 } 183 /* 184 * Locate pcb for datagram. 185 */ 186 nsp = ns_pcblookup(&idp->idp_sna, idp->idp_dna.x_port, NS_WILDCARD); 187 /* 188 * Switch out to protocol's input routine. 189 */ 190 nsintr_swtch++; 191 if (nsp) { 192 if (oddpacketp) { 193 m_adj(m, -1); 194 } 195 if ((nsp->nsp_flags & NSP_ALL_PACKETS)==0) 196 switch (idp->idp_pt) { 197 198 case NSPROTO_SPP: 199 spp_input(m, nsp); 200 goto next; 201 202 case NSPROTO_ERROR: 203 ns_err_input(m); 204 goto next; 205 } 206 idp_input(m, nsp); 207 } else { 208 ns_error(m, NS_ERR_NOSOCK, 0); 209 } 210 goto next; 211 212 bad: 213 m_freem(m); 214 goto next; 215 } 216 217 u_char nsctlerrmap[PRC_NCMDS] = { 218 ECONNABORTED, ECONNABORTED, 0, 0, 219 0, 0, EHOSTDOWN, EHOSTUNREACH, 220 ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 221 EMSGSIZE, 0, 0, 0, 222 0, 0, 0, 0 223 }; 224 225 idp_donosocks = 1; 226 227 idp_ctlinput(cmd, arg) 228 int cmd; 229 caddr_t arg; 230 { 231 struct ns_addr *ns; 232 struct nspcb *nsp; 233 struct ns_errp *errp; 234 int idp_abort(); 235 extern struct nspcb *idp_drop(); 236 int type; 237 238 if (cmd < 0 || cmd > PRC_NCMDS) 239 return; 240 if (nsctlerrmap[cmd] == 0) 241 return; /* XXX */ 242 type = NS_ERR_UNREACH_HOST; 243 switch (cmd) { 244 struct sockaddr_ns *sns; 245 246 case PRC_IFDOWN: 247 case PRC_HOSTDEAD: 248 case PRC_HOSTUNREACH: 249 sns = (struct sockaddr_ns *)arg; 250 if (sns->sns_family != AF_INET) 251 return; 252 ns = &sns->sns_addr; 253 break; 254 255 default: 256 errp = (struct ns_errp *)arg; 257 ns = &errp->ns_err_idp.idp_dna; 258 type = errp->ns_err_num; 259 type = ntohs((u_short)type); 260 } 261 switch (type) { 262 263 case NS_ERR_UNREACH_HOST: 264 ns_pcbnotify(ns, (int)nsctlerrmap[cmd], idp_abort, (long)0); 265 break; 266 267 case NS_ERR_NOSOCK: 268 nsp = ns_pcblookup(ns, errp->ns_err_idp.idp_sna.x_port, 269 NS_WILDCARD); 270 if(nsp && idp_donosocks && ! ns_nullhost(nsp->nsp_faddr)) 271 (void) idp_drop(nsp, (int)nsctlerrmap[cmd]); 272 } 273 } 274 275 int idpprintfs = 0; 276 int idpforwarding = 1; 277 /* 278 * Forward a packet. If some error occurs return the sender 279 * an error packet. Note we can't always generate a meaningful 280 * error message because the NS errors don't have a large enough repetoire 281 * of codes and types. 282 */ 283 struct route idp_droute; 284 struct route idp_sroute; 285 286 idp_forward(m) 287 struct mbuf *m; 288 { 289 register struct idp *idp = mtod(m, struct idp *); 290 register int error, type, code; 291 struct mbuf *mcopy = NULL; 292 int agedelta = 1; 293 int flags = NS_FORWARDING; 294 int ok_there = 0; 295 int ok_back = 0; 296 297 if (idpprintfs) { 298 printf("forward: src "); 299 ns_printhost(&idp->idp_sna); 300 printf(", dst "); 301 ns_printhost(&idp->idp_dna); 302 printf("hop count %d\n", idp->idp_tc); 303 } 304 if (idpforwarding == 0) { 305 /* can't tell difference between net and host */ 306 type = NS_ERR_UNREACH_HOST, code = 0; 307 goto senderror; 308 } 309 idp->idp_tc++; 310 if (idp->idp_tc > NS_MAXHOPS) { 311 type = NS_ERR_TOO_OLD, code = 0; 312 goto senderror; 313 } 314 /* 315 * Save at most 42 bytes of the packet in case 316 * we need to generate an NS error message to the src. 317 */ 318 mcopy = m_copy(m, 0, imin((int)ntohs(idp->idp_len), 42)); 319 320 if ((ok_there = idp_do_route(&idp->idp_dna,&idp_droute))==0) { 321 type = NS_ERR_UNREACH_HOST, code = 0; 322 goto senderror; 323 } 324 /* 325 * Here we think about forwarding broadcast packets, 326 * so we try to insure that it doesn't go back out 327 * on the interface it came in on. Also, if we 328 * are going to physically broadcast this, let us 329 * age the packet so we can eat it safely the second time around. 330 */ 331 if (idp->idp_dna.x_host.c_host[0] & 0x1) { 332 struct ns_ifaddr *ia = ns_iaonnetof(&idp->idp_dna); 333 struct ifnet *ifp; 334 if (ia) { 335 /* I'm gonna hafta eat this packet */ 336 agedelta += NS_MAXHOPS - idp->idp_tc; 337 idp->idp_tc = NS_MAXHOPS; 338 } 339 if ((ok_back = idp_do_route(&idp->idp_sna,&idp_sroute))==0) { 340 /* error = ENETUNREACH; He'll never get it! */ 341 m_freem(m); 342 goto cleanup; 343 } 344 if (idp_droute.ro_rt && 345 (ifp=idp_droute.ro_rt->rt_ifp) && 346 idp_sroute.ro_rt && 347 (ifp!=idp_sroute.ro_rt->rt_ifp)) { 348 flags |= NS_ALLOWBROADCAST; 349 } else { 350 type = NS_ERR_UNREACH_HOST, code = 0; 351 goto senderror; 352 } 353 } 354 /* need to adjust checksum */ 355 if (idp->idp_sum!=0xffff) { 356 union bytes { 357 u_char c[4]; 358 u_short s[2]; 359 long l; 360 } x; 361 register int shift; 362 x.l = 0; x.c[0] = agedelta; 363 shift = (((((int)ntohs(idp->idp_len))+1)>>1)-2) & 0xf; 364 x.l = idp->idp_sum + (x.s[0] << shift); 365 x.l = x.s[0] + x.s[1]; 366 x.l = x.s[0] + x.s[1]; 367 if (x.l==0xffff) idp->idp_sum = 0; else idp->idp_sum = x.l; 368 } 369 if ((error = ns_output(m, &idp_droute, flags)) && 370 (mcopy!=NULL)) { 371 idp = mtod(mcopy, struct idp *); 372 type = NS_ERR_UNSPEC_T, code = 0; 373 switch (error) { 374 375 case ENETUNREACH: 376 case EHOSTDOWN: 377 case EHOSTUNREACH: 378 case ENETDOWN: 379 case EPERM: 380 type = NS_ERR_UNREACH_HOST; 381 break; 382 383 case EMSGSIZE: 384 type = NS_ERR_TOO_BIG; 385 code = 576; /* too hard to figure out mtu here */ 386 break; 387 388 case ENOBUFS: 389 type = NS_ERR_UNSPEC_T; 390 break; 391 } 392 mcopy = NULL; 393 senderror: 394 ns_error(m, type, code); 395 } 396 cleanup: 397 if (ok_there) 398 idp_undo_route(&idp_droute); 399 if (ok_back) 400 idp_undo_route(&idp_sroute); 401 if (mcopy != NULL) 402 m_freem(mcopy); 403 } 404 405 idp_do_route(src, ro) 406 struct ns_addr *src; 407 struct route *ro; 408 { 409 410 struct sockaddr_ns *dst; 411 412 bzero((caddr_t)ro, sizeof (*ro)); 413 dst = (struct sockaddr_ns *)&ro->ro_dst; 414 415 dst->sns_family = AF_NS; 416 dst->sns_addr = *src; 417 dst->sns_addr.x_port = 0; 418 rtalloc(ro); 419 if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) { 420 return (0); 421 } 422 ro->ro_rt->rt_use++; 423 return (1); 424 } 425 426 idp_undo_route(ro) 427 register struct route *ro; 428 { 429 if (ro->ro_rt) {RTFREE(ro->ro_rt);} 430 } 431 static union ns_net 432 ns_zeronet; 433 434 ns_watch_output(m, ifp) 435 struct mbuf *m; 436 struct ifnet *ifp; 437 { 438 register struct nspcb *nsp; 439 register struct ifaddr *ia; 440 /* 441 * Give any raw listeners a crack at the packet 442 */ 443 for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) { 444 struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL); 445 if (m0) { 446 register struct idp *idp; 447 448 M_PREPEND(m0, sizeof (*idp), M_DONTWAIT); 449 if (m0 == NULL) 450 continue; 451 idp = mtod(m0, struct idp *); 452 idp->idp_sna.x_net = ns_zeronet; 453 idp->idp_sna.x_host = ns_thishost; 454 if (ifp && (ifp->if_flags & IFF_POINTOPOINT)) 455 for(ia = ifp->if_addrlist; ia; 456 ia = ia->ifa_next) { 457 if (ia->ifa_addr.sa_family==AF_NS) { 458 idp->idp_sna = 459 satons_addr(ia->ifa_dstaddr); 460 break; 461 } 462 } 463 idp->idp_len = ntohl(m0->m_pkthdr.len); 464 idp_input(m0, nsp); 465 } 466 } 467 } 468