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