* Attempt to compress an outgoing TCP packet and return the type of * the result. The caller must have already verified that the protocol * is TCP. The first mbuf must contain the complete IP and TCP headers, * and "ip" must be == mtod(m, struct ip *). "comp" supplies the * compression state, and "compress_cid" tells us whether it is OK * to leave out the CID field when feasible. * * The
| 151 | * if m is an M_PKTHDR mbuf. |
| 152 | */ |
| 153 | u_int |
| 154 | sl_compress_tcp(struct mbuf *m, struct ip *ip, struct slcompress *comp, |
| 155 | int compress_cid) |
| 156 | { |
| 157 | struct cstate *cs = comp->last_cs->cs_next; |
| 158 | u_int hlen = ip->ip_hl; |
| 159 | struct tcphdr *oth; |
| 160 | struct tcphdr *th; |
| 161 | u_int deltaS, deltaA; |
| 162 | u_int changes = 0; |
| 163 | u_char new_seq[16]; |
| 164 | u_char *cp = new_seq; |
| 165 | |
| 166 | /* |
| 167 | * Bail if this is an IP fragment or if the TCP packet isn't |
| 168 | * `compressible' (i.e., ACK isn't set or some other control bit is |
| 169 | * set). (We assume that the caller has already made sure the |
| 170 | * packet is IP proto TCP). |
| 171 | */ |
| 172 | if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40) |
| 173 | return (TYPE_IP); |
| 174 | |
| 175 | th = (struct tcphdr *)&((int32_t *)ip)[hlen]; |
| 176 | if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK) |
| 177 | return (TYPE_IP); |
| 178 | /* |
| 179 | * Packet is compressible -- we're going to send either a |
| 180 | * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need |
| 181 | * to locate (or create) the connection state. Special case the |
| 182 | * most recently used connection since it's most likely to be used |
| 183 | * again & we don't have to do any reordering if it's used. |
| 184 | */ |
| 185 | INCR(sls_packets) |
| 186 | if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || |
| 187 | ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || |
| 188 | *(int32_t *)th != ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) { |
| 189 | /* |
| 190 | * Wasn't the first -- search for it. |
| 191 | * |
| 192 | * States are kept in a circularly linked list with |
| 193 | * last_cs pointing to the end of the list. The |
| 194 | * list is kept in lru order by moving a state to the |
| 195 | * head of the list whenever it is referenced. Since |
| 196 | * the list is short and, empirically, the connection |
| 197 | * we want is almost always near the front, we locate |
| 198 | * states via linear search. If we don't find a state |
| 199 | * for the datagram, the oldest state is (re-)used. |
| 200 | */ |
| 201 | struct cstate *lcs; |
| 202 | struct cstate *lastcs = comp->last_cs; |
| 203 | |
| 204 | do { |
| 205 | lcs = cs; cs = cs->cs_next; |
| 206 | INCR(sls_searches) |
| 207 | if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr |
| 208 | && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr |
| 209 | && *(int32_t *)th == |
| 210 | ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) |
no outgoing calls
no test coverage detected