static struct mbuf * sync_LayerPush(struct bundle *bundle, struct link *l, struct mbuf *bp, int pri, u_short *proto) { log_DumpBp(LogSYNC, "Write", bp); m_settype(bp, MB_SYNCOUT); return bp; }
static struct mbuf * sync_LayerPull(struct bundle *b, struct link *l, struct mbuf *bp, u_short *proto) { struct physical *p = link2physical(l); if (!p) log_Printf(LogERROR, "Can't Pull a sync packet from a logical link\n"); else { log_DumpBp(LogSYNC, "Read", bp); /* Either done here or by the HDLC layer */ p->hdlc.lqm.SaveInOctets += m_length(bp) + 1; p->hdlc.lqm.SaveInPackets++; m_settype(bp, MB_SYNCIN); } return bp; }
static void ChapOutput(struct physical *physical, u_int code, u_int id, const u_char *ptr, int count, const char *text) { int plen; struct fsmheader lh; struct mbuf *bp; plen = sizeof(struct fsmheader) + count; lh.code = code; lh.id = id; lh.length = htons(plen); bp = m_get(plen, MB_CHAPOUT); memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); if (count) memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count); log_DumpBp(LogDEBUG, "ChapOutput", bp); if (text == NULL) log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]); else log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text); link_PushPacket(&physical->link, bp, physical->dl->bundle, LINK_QUEUES(&physical->link) - 1, PROTO_CHAP); }
u_char sl_compress_tcp(struct mbuf * m, struct ip * ip, struct slcompress *comp, struct slstat *slstat, int compress_cid) { register struct cstate *cs = comp->last_cs->cs_next; register u_int hlen = ip->ip_hl; register struct tcphdr *oth; register struct tcphdr *th; register u_int deltaS, deltaA; register u_int changes = 0; u_char new_seq[16]; register u_char *cp = new_seq; /* * Bail if this is an IP fragment or if the TCP packet isn't `compressible' * (i.e., ACK isn't set or some other control bit is set). (We assume that * the caller has already made sure the packet is IP proto TCP). */ if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) { log_Printf(LogDEBUG, "??? 1 ip_off = %x, m_len = %lu\n", ntohs(ip->ip_off), (unsigned long)m->m_len); log_DumpBp(LogDEBUG, "", m); return (TYPE_IP); } th = (struct tcphdr *) & ((int *) ip)[hlen]; if ((th->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) != TH_ACK) { log_Printf(LogDEBUG, "??? 2 th_flags = %x\n", th->th_flags); log_DumpBp(LogDEBUG, "", m); return (TYPE_IP); } /* * Packet is compressible -- we're going to send either a COMPRESSED_TCP or * UNCOMPRESSED_TCP packet. Either way we need to locate (or create) the * connection state. Special case the most recently used connection since * it's most likely to be used again & we don't have to do any reordering * if it's used. */ slstat->sls_packets++; if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || *(int *) th != ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) { /* * Wasn't the first -- search for it. * * States are kept in a circularly linked list with last_cs pointing to the * end of the list. The list is kept in lru order by moving a state to * the head of the list whenever it is referenced. Since the list is * short and, empirically, the connection we want is almost always near * the front, we locate states via linear search. If we don't find a * state for the datagram, the oldest state is (re-)used. */ register struct cstate *lcs; register struct cstate *lastcs = comp->last_cs; do { lcs = cs; cs = cs->cs_next; slstat->sls_searches++; if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr && *(int *) th == ((int *) &cs->cs_ip)[cs->cs_ip.ip_hl]) goto found; } while (cs != lastcs); /* * Didn't find it -- re-use oldest cstate. Send an uncompressed packet * that tells the other side what connection number we're using for this * conversation. Note that since the state list is circular, the oldest * state points to the newest and we only need to set last_cs to update * the lru linkage. */ slstat->sls_misses++; comp->last_cs = lcs; #define THOFFSET(th) (th->th_off) hlen += th->th_off; hlen <<= 2; if (hlen > m->m_len) return (TYPE_IP); goto uncompressed; found: /* * Found it -- move to the front on the connection list. */ if (cs == lastcs) comp->last_cs = lcs; else { lcs->cs_next = cs->cs_next; cs->cs_next = lastcs->cs_next; lastcs->cs_next = cs; } } /* * Make sure that only what we expect to change changed. The first line of * the `if' checks the IP protocol version, header length & type of * service. The 2nd line checks the "Don't fragment" bit. The 3rd line * checks the time-to-live and protocol (the protocol check is unnecessary * but costless). The 4th line checks the TCP header length. The 5th line * checks IP options, if any. The 6th line checks TCP options, if any. If * any of these things are different between the previous & current * datagram, we send the current datagram `uncompressed'. */ oth = (struct tcphdr *) & ((int *) &cs->cs_ip)[hlen]; deltaS = hlen; hlen += th->th_off; hlen <<= 2; if (hlen > m->m_len) return (TYPE_IP); if (((u_short *) ip)[0] != ((u_short *) & cs->cs_ip)[0] || ((u_short *) ip)[3] != ((u_short *) & cs->cs_ip)[3] || ((u_short *) ip)[4] != ((u_short *) & cs->cs_ip)[4] || THOFFSET(th) != THOFFSET(oth) || (deltaS > 5 && memcmp(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || (THOFFSET(th) > 5 && memcmp(th + 1, oth + 1, (THOFFSET(th) - 5) << 2))) { goto uncompressed; } /* * Figure out which of the changing fields changed. The receiver expects * changes in the order: urgent, window, ack, seq (the order minimizes the * number of temporaries needed in this section of code). */ if (th->th_flags & TH_URG) { deltaS = ntohs(th->th_urp); ENCODEZ(deltaS); changes |= NEW_U; } else if (th->th_urp != oth->th_urp) { /* * argh! URG not set but urp changed -- a sensible implementation should * never do this but RFC793 doesn't prohibit the change so we have to * deal with it. */ goto uncompressed; } deltaS = (u_short) (ntohs(th->th_win) - ntohs(oth->th_win)); if (deltaS) { ENCODE(deltaS); changes |= NEW_W; } deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack); if (deltaA) { if (deltaA > 0xffff) { goto uncompressed; } ENCODE(deltaA); changes |= NEW_A; } deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq); if (deltaS) { if (deltaS > 0xffff) { goto uncompressed; } ENCODE(deltaS); changes |= NEW_S; } switch (changes) { case 0: /* * Nothing changed. If this packet contains data and the last one didn't, * this is probably a data packet following an ack (normal on an * interactive connection) and we send it compressed. Otherwise it's * probably a retransmit, retransmitted ack or window probe. Send it * uncompressed in case the other side missed the compressed version. */ if (ip->ip_len != cs->cs_ip.ip_len && ntohs(cs->cs_ip.ip_len) == hlen) break; /* FALLTHROUGH */ case SPECIAL_I: case SPECIAL_D: /* * actual changes match one of our special case encodings -- send packet * uncompressed. */ goto uncompressed; case NEW_S | NEW_A: if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { /* special case for echoed terminal traffic */ changes = SPECIAL_I; cp = new_seq; } break; case NEW_S: if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { /* special case for data xfer */ changes = SPECIAL_D; cp = new_seq; } break; } deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); if (deltaS != 1) { ENCODEZ(deltaS); changes |= NEW_I; } if (th->th_flags & TH_PUSH) changes |= TCP_PUSH_BIT; /* * Grab the cksum before we overwrite it below. Then update our state with * this packet's header. */ deltaA = ntohs(th->th_sum); memcpy(&cs->cs_ip, ip, hlen); /* * We want to use the original packet as our compressed packet. (cp - * new_seq) is the number of bytes we need for compressed sequence numbers. * In addition we need one byte for the change mask, one for the connection * id and two for the tcp checksum. So, (cp - new_seq) + 4 bytes of header * are needed. hlen is how many bytes of the original packet to toss so * subtract the two to get the new packet size. */ deltaS = cp - new_seq; cp = (u_char *) ip; /* * Since fastq traffic can jump ahead of the background traffic, we don't * know what order packets will go on the line. In this case, we always * send a "new" connection id so the receiver state stays synchronized. */ if (comp->last_xmit == cs->cs_id && compress_cid) { hlen -= deltaS + 3; cp += hlen; *cp++ = changes; } else { comp->last_xmit = cs->cs_id; hlen -= deltaS + 4; cp += hlen; *cp++ = changes | NEW_C; *cp++ = cs->cs_id; } m->m_len -= hlen; m->m_offset += hlen; *cp++ = deltaA >> 8; *cp++ = deltaA; memcpy(cp, new_seq, deltaS); slstat->sls_compressed++; return (TYPE_COMPRESSED_TCP); /* * Update connection state cs & send uncompressed packet ('uncompressed' * means a regular ip/tcp packet but with the 'conversation id' we hope to * use on future compressed packets in the protocol field). */ uncompressed: memcpy(&cs->cs_ip, ip, hlen); ip->ip_p = cs->cs_id; comp->last_xmit = cs->cs_id; return (TYPE_UNCOMPRESSED_TCP); }