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: }