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