cck@CUNIXA.COLUMBIA.EDU (Charlie C. Kim) (05/08/88)
Bill Greene and I have been tracking down the AlisaTalk/KIP problems and have found the following. The first important piece of information is that AlisaTalk has an "AppleTalk Bridge" on the VMS hosts that all the VMS services lie behind. The first problem we found was that KIP was improperly using using the hop count in the ddp header as part of the length (a bug that I introduced I belive). This was in the code that downsized an incoming packet if it was longer than the ddp packet size -- this happens when a packet on EtherTalk is shorter than the minimum ethernet size (should be 60 bytes, but some systems insist on 64 bytes). This prevented macs on the localtalk network from accepting incoming packets. NBP worked okay because the packet sizes involved were over 43 bytes (the mimimum size ddp packet that would function without error in the above). The second problem found is far more serious. In summary, KIP does not properly handle RTMP/ZIP transactions. It has a minimal amount of code that allows it to accept RTMP from other bridges and send ZIP responses to queries. However, KIP does not attempt to find the zone of networks found via RTMP transactions (in other words, it does not send out ZIP queries or accept ZIP responses) -- instead it sets them to "unknown" (0). Because of this, servers (actually nbp lookups on entities) behind non-KIP gateways (AlisaTalk, Hayes InterBridge) cannot be done. To explain this further, we simply note that NBP lookups are done in a bridged environment by sending a "Bridge Lookup" packet to the nearest Bridge that is responsible for sending NBP lookups as directed broadcasts to each network in the specified zone. Since acquired networks are never assigned a zone, NBP lookups would never be sent to those networks. But, why where the lookups working at all? It was because of a bug in the code that did not check to see that the "ALLZONES" index was initialized before it was used. (A network in allzones receives all NBP lookups). Allzones is set to zero. The "unknown" zone value is zero. Thus, all the networks in "unknown" were being 'queried' on every lookup. (Bill, the real reason the first gateway worked was the above. The reason the other gateway didn't work was because the "acquired" routes are only sent out to other KIP gateways if they are marked "core"). Parts of this analysis may be incorrect, but I believe the majority to be correct. Note: clients behind the non-KIP networks should still be able to communicate with most servers (the only exception would be in the situation where you have: non-kip-bridge<->kip-bridge<->non-kip-bridge). So what is the solution? The best possible solution is to make KIP query unknown networks. This is a fair amount of work. A workaround would be to (a) allow non-IP networks to be set in atalkatab or (b) to write an host EtherTalk redirector. If someone wants to do the work, they are welcome to contact me for ideas. Following are set of patches: gw.c - correct ethertalk length correction gw2.c - fix ddpreply to be smart about sending short vs. long ddp. short ddp only to localtalk interface - fix nbpback to ensure allzones is set before use - update for modified ddpreply rtmp.c - update for modified ddprely: rtmp & zip packets - initialize allzones - make ZIP GetMyZone return zone of the network the packet came in upon, not the zone of the interface it came in upon (suggested by Robert Elz). This makes it useful when host whose primary zone isn't that of the gw does a gmz The ddpreply patches were the first tried to attempt to resolve the problem -- while they turned out not to be necessary, they still bring kip closer to specification (EtherTalk). The GMZ patch could be used to allow CAP hosts to "automatically" retrieve their zone (e.g. so zone name doesn't have to be specified in atalk.local). Charlie C. Kim User Services Columbia University %%%START OF PATCHES%%% *** /tmp/,RCSt1008421 Sun May 8 10:52:05 1988 --- gw.c Fri May 6 17:35:54 1988 *************** *** 318,324 ddp.srcNet = source_if->if_dnet; if (ddp.dstNet == 0) ddp.dstNet = source_if->if_dnet; ! temp = ddp.length - ddpSize; p->p_off += ddpSize; wasddp = 1; break; --- 318,324 ----- ddp.srcNet = source_if->if_dnet; if (ddp.dstNet == 0) ddp.dstNet = source_if->if_dnet; ! temp = (ddp.length & ddpLengthMask) - ddpSize; p->p_off += ddpSize; wasddp = 1; break; *** /tmp/,RCSt1008421 Sun May 8 10:52:07 1988 --- gw2.c Fri May 6 15:32:49 1988 *************** *** 199,207 for ( ; ar < &aroute[NAROUTE] ; ++ar) { if (ar->net == 0) continue; ! if (ar->zone != allzones && ! ar->zone != nback_zoneindex) /* wrong zone? */ ! continue; K_PGET(PT_DATA, p); if (p == 0) return; /* try later */ --- 199,209 ----- for ( ; ar < &aroute[NAROUTE] ; ++ar) { if (ar->net == 0) continue; ! /* continue if wrong zone and the zone is not all zones */ ! /* make sure allzones is set before using */ ! if (ar->zone != nback_zoneindex && ! !(allzones && ar->zone == allzones)) ! continue; K_PGET(PT_DATA, p); if (p == 0) return; /* try later */ *************** *** 488,494 if (p->p_off[lapSize+ddpSize] != echoRequest) goto drop; p->p_off[lapSize+ddpSize] = echoReply; ! ddpreply(p, echoSkt); return; case ddpZIP: if (ddp.dstSkt != zipSkt) --- 490,496 ----- if (p->p_off[lapSize+ddpSize] != echoRequest) goto drop; p->p_off[lapSize+ddpSize] = echoReply; ! ddpreply(p, echoSkt, (ddp.length & ddpLengthMask) - ddpSize); return; case ddpZIP: if (ddp.dstSkt != zipSkt) *************** *** 527,534 ig->op = -1; break; } - ddp.length = (ddpSize + sizeof *a + ipgpMinSize - + strlen(ig->string) + 1); p->p_len = ddp.length + lapSize; a->control = atpRspCode + atpEOM; a->bitmap = 0; --- 529,534 ----- ig->op = -1; break; } p->p_len = ddp.length + lapSize; a->control = atpRspCode + atpEOM; a->bitmap = 0; *************** *** 532,538 p->p_len = ddp.length + lapSize; a->control = atpRspCode + atpEOM; a->bitmap = 0; ! ddpreply(p, ddpIPSkt); return; drop: K_PFREE(p); --- 532,538 ----- p->p_len = ddp.length + lapSize; a->control = atpRspCode + atpEOM; a->bitmap = 0; ! ddpreply(p, ddpIPSkt, (sizeof(*a)+ipgpMinSize+strlen(ig->string)+1)); return; drop: K_PFREE(p); *************** *** 760,766 } ! ddpreply(p, skt) register struct pbuf *p; int skt; { --- 760,777 ----- } ! /* ! * assumes ddp.type already set and that the reply goes to the node specified ! * by: (ddp.srcNet, ddp.srcNode, ddp.srcSkt) ! * ! * p should be aligned so offset points to start of lap data with room ! * for lap + long ddp. ! * ! * skt is outgoing socket ! * ! * len is the length of the data portion ! */ ! ddpreply(p, skt, len) register struct pbuf *p; int skt; int len; *************** *** 763,768 ddpreply(p, skt) register struct pbuf *p; int skt; { register struct DDP *dp = &ddp; --- 774,780 ----- ddpreply(p, skt, len) register struct pbuf *p; int skt; + int len; { u_char dst; register struct DDP *dp = &ddp; *************** *** 764,769 register struct pbuf *p; int skt; { register struct DDP *dp = &ddp; dp->checksum = 0; --- 776,782 ----- int skt; int len; { + u_char dst; register struct DDP *dp = &ddp; /* if incoming was short ddp and came in from localtalk interface */ *************** *** 766,778 { register struct DDP *dp = &ddp; ! dp->checksum = 0; ! dp->dstNet = dp->srcNet; ! dp->dstNode = dp->srcNode; ! dp->dstSkt = dp->srcSkt; ! dp->srcNet = source_if->if_dnet; ! dp->srcNode = source_if->if_dnode; ! dp->srcSkt = skt; ! bcopy((caddr_t)dp, p->p_off+lapSize, ddpSize); ! routeddp(p, 0); } --- 779,807 ----- u_char dst; register struct DDP *dp = &ddp; ! /* if incoming was short ddp and came in from localtalk interface */ ! /* and is going back to the localtalk interface, then send back as */ ! /* short ddp, else long ddp */ ! if (source_if == &ifab && (dp->srcNet == source_if->if_dnet)) { ! p->p_off += (ddpSize - ddpSSize); /* move ahead to ddp short boundary */ ! p->p_len -= (ddpSize - ddpSSize); ! dst = dp->srcNode; ! ddps.srcSkt = skt; /* source sockt */ ! ddps.dstSkt = dp->srcSkt; ! ddps.type = dp->type; ! ddps.length = len + ddpSSize; ! bcopy((caddr_t)&ddps, p->p_off+lapSize, ddpSSize); ! (*source_if->if_output)(source_if, p, AF_SDDP, &dst); ! } else { ! dp->length = len + ddpSize; ! dp->checksum = 0; ! dp->dstNet = dp->srcNet; ! dp->dstNode = dp->srcNode; ! dp->dstSkt = dp->srcSkt; ! dp->srcNet = source_if->if_dnet; ! dp->srcNode = source_if->if_dnode; ! dp->srcSkt = skt; ! bcopy((caddr_t)dp, p->p_off+lapSize, ddpSize); ! routeddp(p, 0); ! } } *** /tmp/,RCSt1008421 Sun May 8 10:52:09 1988 --- rtmp.c Fri May 6 15:32:49 1988 *************** *** 33,39 rtmp_delay = 1; /* broadcast the current routing table */ ! rtmpsend(0xff, rtmpSkt, 1, &ifab); if (ifet.if_dnet) /* only send routing packets if ETalk enabled*/ rtmpsend(0xff, rtmpSkt, 1, &ifet); --- 33,39 ----- rtmp_delay = 1; /* broadcast the current routing table */ ! rtmpsend(&ifab); if (ifet.if_dnet) /* only send routing packets if ETalk enabled*/ rtmpsend(&ifet); *************** *** 35,41 /* broadcast the current routing table */ rtmpsend(0xff, rtmpSkt, 1, &ifab); if (ifet.if_dnet) /* only send routing packets if ETalk enabled*/ ! rtmpsend(0xff, rtmpSkt, 1, &ifet); if (rtmp_vdelay++ == 0) /* validity timer goes off every 20 secs */ return; --- 35,41 ----- /* broadcast the current routing table */ rtmpsend(&ifab); if (ifet.if_dnet) /* only send routing packets if ETalk enabled*/ ! rtmpsend(&ifet); if (rtmp_vdelay++ == 0) /* validity timer goes off every 20 secs */ return; *************** *** 55,61 /* ! * Send an RTMP packet to dnode, dsoc. If 'tuples' is true, * include the routing tuples. */ rtmpsend(dnode, dsoc, tuples, ifp) --- 55,61 ----- /* ! * Send an RTMP packet. If 'tuples' is true, * include the routing tuples. */ /* break into send and reply */ *************** *** 58,64 * Send an RTMP packet to dnode, dsoc. If 'tuples' is true, * include the routing tuples. */ ! rtmpsend(dnode, dsoc, tuples, ifp) struct ifnet *ifp; { register struct pbuf *p; --- 58,68 ----- * Send an RTMP packet. If 'tuples' is true, * include the routing tuples. */ ! /* break into send and reply */ ! ! /* rtmp send: used only to broadcast rtmp "here I ams" */ ! /* setup for ddp reply and call rtmpreply */ ! rtmpsend(ifp) struct ifnet *ifp; { source_if = ifp; *************** *** 61,66 rtmpsend(dnode, dsoc, tuples, ifp) struct ifnet *ifp; { register struct pbuf *p; register struct RTMP *r; struct DDPS d; --- 65,80 ----- rtmpsend(ifp) struct ifnet *ifp; { + source_if = ifp; + ddp.srcNet = source_if->if_dnet; + ddp.srcNode = 0xff; /* broadcast */ + ddp.srcSkt = rtmpSkt; + rtmpreply(1); + } + + /* rtmp reply - reply to last packet (was rtmp request) */ + rtmpreply(tuples) + { register struct pbuf *p; register struct RTMP *r; register i; *************** *** 63,69 { register struct pbuf *p; register struct RTMP *r; - struct DDPS d; register i; u_char dst; --- 77,82 ----- { register struct pbuf *p; register struct RTMP *r; register i; K_PGET(PT_DATA, p); *************** *** 65,71 register struct RTMP *r; struct DDPS d; register i; - u_char dst; K_PGET(PT_DATA, p); if (p == 0) --- 78,83 ----- register struct pbuf *p; register struct RTMP *r; register i; K_PGET(PT_DATA, p); if (p == 0) *************** *** 70,77 K_PGET(PT_DATA, p); if (p == 0) return; ! r = (struct RTMP *)(p->p_off + lapSize + ddpSSize); ! r->net = ifp->if_dnet; r->idLen = 8; r->id = ifp->if_dnode; if (tuples) --- 82,89 ----- K_PGET(PT_DATA, p); if (p == 0) return; ! r = (struct RTMP *)(p->p_off + lapSize + ddpSize); ! r->net = source_if->if_dnet; r->idLen = 8; r->id = source_if->if_dnode; if (tuples) *************** *** 73,79 r = (struct RTMP *)(p->p_off + lapSize + ddpSSize); r->net = ifp->if_dnet; r->idLen = 8; ! r->id = ifp->if_dnode; if (tuples) i = rtmpsettuples((caddr_t)(r + 1)); else --- 85,91 ----- r = (struct RTMP *)(p->p_off + lapSize + ddpSize); r->net = source_if->if_dnet; r->idLen = 8; ! r->id = source_if->if_dnode; if (tuples) i = rtmpsettuples((caddr_t)(r + 1)); else *************** *** 78,91 i = rtmpsettuples((caddr_t)(r + 1)); else i = 0; ! d.length = i + ddpSSize + rtmpSize; ! p->p_len = d.length + lapSize; ! d.dstSkt = dsoc; ! d.srcSkt = rtmpSkt; ! dst = dnode; ! d.type = ddpRTMP; ! bcopy((caddr_t)&d, p->p_off+lapSize, ddpSSize); ! (*ifp->if_output)(ifp, p, AF_SDDP, &dst); } --- 90,99 ----- i = rtmpsettuples((caddr_t)(r + 1)); else i = 0; ! /* setup for ddp send */ ! ddp.type = ddpRTMP; /* in case request */ ! p->p_len = i+rtmpSize+ddpSize+lapSize; ! ddpreply(p, rtmpSkt, i+rtmpSize); } *************** *** 201,207 /* RTMP request from Mac trying to get his net # */ if (*p->p_off != 1) goto drop; /* only opcode defined now is 1 */ ! rtmpsend(ddp.srcNode, ddp.srcSkt, 0, source_if); goto drop; } --- 209,215 ----- /* RTMP request from Mac trying to get his net # */ if (*p->p_off != 1) goto drop; /* only opcode defined now is 1 */ ! rtmpreply(0); /* reply */ goto drop; } *************** *** 462,467 * net# net# ... 0 zonename * 0xFFFF */ for (;;) { n = *cp++; n <<= 8; --- 470,476 ----- * net# net# ... 0 zonename * 0xFFFF */ + allzones = 0; for (;;) { n = *cp++; n <<= 8; *************** *** 523,529 } } - /* * String compare, case independent; * returns zero if equal, one otherwise --- 532,537 ----- } } /* * String compare, case independent; * returns zero if equal, one otherwise *************** *** 577,583 if (ddp.type == ddpATP) goto get; /* if ATP style request */ ! /* else pure ZIP in a short DDP */ if (ddp.type != ddpZIP) goto drop; z = (struct ZIP *)ip->p_off+lapSize+ddpSize; --- 585,591 ----- if (ddp.type == ddpATP) goto get; /* if ATP style request */ ! /* else pure ZIP */ if (ddp.type != ddpZIP) goto drop; z = (struct ZIP *)ip->p_off+lapSize+ddpSize; *************** *** 592,598 K_PGET(PT_DATA, op); if (op == 0) goto drop; ! po = op->p_off + lapSize + ddpSSize + sizeof(struct ZIP); sp = (u_short *)(z+1); for (count = 0, len = 0 ; count < z->count && len < 512 ; count++) { u.s = i = *sp++; /* network */ --- 600,606 ----- K_PGET(PT_DATA, op); if (op == 0) goto drop; ! po = op->p_off + lapSize + ddpSize + sizeof(struct ZIP); sp = (u_short *)(z+1); for (count = 0, len = 0 ; count < z->count && len < 512 ; count++) { u.s = i = *sp++; /* network */ *************** *** 608,614 po += (*pi + 1); len += (*pi + 3); } ! z = (struct ZIP *)(op->p_off + lapSize + ddpSSize); z->command = zipReply; z->count = count; d.length = len + sizeof *z + ddpSSize; --- 616,622 ----- po += (*pi + 1); len += (*pi + 3); } ! z = (struct ZIP *)(op->p_off + lapSize + ddpSize); z->command = zipReply; z->count = count; op->p_len = lapSize + ddpSize + len + sizeof *z; *************** *** 611,624 z = (struct ZIP *)(op->p_off + lapSize + ddpSSize); z->command = zipReply; z->count = count; ! d.length = len + sizeof *z + ddpSSize; ! op->p_len = d.length + lapSize; ! d.dstSkt = ddp.srcSkt; ! d.srcSkt = zipSkt; ! d.type = ddpZIP; ! dst = ddp.srcNode; ! bcopy((caddr_t)&d, op->p_off+lapSize, ddpSSize); ! (*source_if->if_output)(source_if, op, AF_SDDP, &dst); goto drop; get: /* we can reuse the input packet (query needs too much out of it) */ --- 619,626 ----- z = (struct ZIP *)(op->p_off + lapSize + ddpSize); z->command = zipReply; z->count = count; ! op->p_len = lapSize + ddpSize + len + sizeof *z; ! ddpreply(op, zipSkt, len + sizeof *z); goto drop; get: /* we can reuse the input packet (query needs too much out of it) */ *************** *** 644,649 case GMZ: zap->c[4] = 0; /* Find the zone for the interface request came in on */ for (ar = &aroute[0]; ar < &aroute[NAROUTE]; ++ar) if (ar->net == source_if->if_dnet) break; pi = azone[ar->zone]; --- 646,653 ----- case GMZ: zap->c[4] = 0; /* Find the zone for the interface request came in on */ + /* cck: modify to find the zone for the source network */ + /* of the packet that came in */ for (ar = &aroute[0]; ar < &aroute[NAROUTE]; ++ar) if (ar->net == ddp.srcNet) break; *************** *** 645,651 zap->c[4] = 0; /* Find the zone for the interface request came in on */ for (ar = &aroute[0]; ar < &aroute[NAROUTE]; ++ar) ! if (ar->net == source_if->if_dnet) break; pi = azone[ar->zone]; count = *pi + 1; bcopy(pi, po, count); /* get zone */ --- 649,658 ----- /* cck: modify to find the zone for the source network */ /* of the packet that came in */ for (ar = &aroute[0]; ar < &aroute[NAROUTE]; ++ar) ! if (ar->net == ddp.srcNet) ! break; ! if (ar == &aroute[NAROUTE]) ! goto drop; pi = azone[ar->zone]; count = *pi + 1; bcopy(pi, po, count); /* get zone */ *************** *** 678,686 zap->s[3] = j; /* set count */ break; } ! ddp.length = sizeof(zipatp) + len + ddpSize; ! ip->p_len = lapSize+ddp.length; ! ddpreply(ip, zipSkt); return; drop: K_PFREE(ip); --- 685,692 ----- zap->s[3] = j; /* set count */ break; } ! ip->p_len = lapSize+ddpSize+sizeof(zipatp)+len; ! ddpreply(ip, zipSkt, sizeof(zipatp) + len); return; drop: K_PFREE(ip); %%%END OF PATCHES%%%
cck@CUNIXC.COLUMBIA.EDU (Charlie C. Kim) (05/12/88)
In a set of patches for KIP & AlisaTalk, modifications were made to ddpreply to make it conform to the "ethertalk" specification better. Unfortunately, I created a major bug in gw2.c that killed the igpassign functions. So, don't apply the patches to gw2.c and rtmp.c. The patchs to gw.c is correct. When I fix the problems and verify the fixes, I will resend (or post the location of) a set of diffs incorporating all changes to be made against the baseline kip 01/88 code. Charlie C. Kim User Services Columbia University
newsuser@LTH.Se (Lund Institute of Technology news server) (05/16/88)
In article <8805081514.AA06203@columbia.edu> cck@CUNIXA.COLUMBIA.EDU (Charlie C. Kim) writes: > >The first problem we found was that KIP was improperly using using the >hop count in the ddp header as part of the length (a bug that I >introduced I belive). > [ ... ] >The second problem found is far more serious. In summary, KIP does >not properly handle RTMP/ZIP transactions. It has a minimal amount of >code that allows it to accept RTMP from other bridges and send ZIP >responses to queries. > [ ... ] >Following are set of patches: > gw.c - correct ethertalk length correction > gw2.c - fix ddpreply to be smart about sending short vs. long > ddp. short ddp only to localtalk interface > - fix nbpback to ensure allzones is set before use > - update for modified ddpreply > rtmp.c - update for modified ddprely: rtmp & zip packets > - initialize allzones > - make ZIP GetMyZone return zone of the network the packet > came in upon, not the zone of the interface it came in upon > (suggested by Robert Elz). This makes it useful when host > whose primary zone isn't that of the gw does a gmz > [ ... ] >Charlie C. Kim >User Services >Columbia University We have a network with one Kinetics FastPath and one Hayes InterBridge. The CAP server is not visible on the other (non-KFPS) side of the InterBridge. I have looked at the packets on LocalTalk, and the InterBridge sends a ZIP query every now and then, but the KFPS ignores it. This is a major problem for us. I don't want to introduce new bugs, and it seems to be a litte bit difficult to compile the gateway code (find a vax, use the right compiler, convert to s-records etc). So, if anybody (Charlie?) has already done it, could you please upload it to the CAP (listserv) server at cuvma, post it, or mail it to me? Thanks! -- Roland Mansson, Dept of Comp Sc, Lund University, Box 118, S-221 00 Lund, Sweden Phone +46-46109640 (work), +46-46111539 (home) USENET:roland@dna.lth.se BITNET:LTHLIB@SELDC52 AppleLink:IT0073