| |
| /* GRE flag bits */ |
| enum { |
| GRE_chksum = (1<<15), |
| GRE_routing = (1<<14), |
| GRE_key = (1<<13), |
| GRE_seq = (1<<12), |
| GRE_srcrt = (1<<11), |
| GRE_recur = (7<<8), |
| GRE_ack = (1<<7), |
| GRE_ver = 0x7 |
| }; |
| |
| /* GRE protocols */ |
| enum { |
| GRE_sna = 0x0004, |
| GRE_osi = 0x00fe, |
| GRE_pup = 0x0200, |
| GRE_xns = 0x0600, |
| GRE_ip = 0x0800, |
| GRE_chaos = 0x0804, |
| GRE_rfc826 = 0x0806, |
| GRE_frarp = 0x0808, |
| GRE_vines = 0x0bad, |
| GRE_vinesecho = 0x0bae, |
| GRE_vinesloop = 0x0baf, |
| GRE_decnetIV = 0x6003, |
| GRE_ppp = 0x880b |
| }; |
| |
| int |
| sprintgre(void *a, char *buf, int len) |
| { |
| int flag, prot, chksum, offset, key, seq, ack; |
| int n; |
| uchar *p = a; |
| |
| chksum = offset = key = seq = ack = 0; |
| |
| flag = NetS(p); |
| prot = NetS(p+2); |
| p += 4; len -= 4; |
| if(flag & (GRE_chksum|GRE_routing)){ |
| chksum = NetS(p); |
| offset = NetS(p+2); |
| p += 4; len -= 4; |
| } |
| if(flag&GRE_key){ |
| key = NetL(p); |
| p += 4; len -= 4; |
| } |
| if(flag&GRE_seq){ |
| seq = NetL(p); |
| p += 4; len -= 4; |
| } |
| if(flag&GRE_ack){ |
| ack = NetL(p); |
| p += 4; len -= 4; |
| } |
| /* skip routing if present */ |
| if(flag&GRE_routing) { |
| while(len >= 4 && (n=p[3]) != 0) { |
| len -= n; |
| p += n; |
| } |
| } |
| |
| USED(offset); |
| USED(chksum); |
| |
| n = sprint(buf, "GRE(f %4.4ux p %ux k %ux", flag, prot, key); |
| if(flag&GRE_seq) |
| n += sprint(buf+n, " s %ux", seq); |
| if(flag&GRE_ack) |
| n += sprint(buf+n, " a %ux", ack); |
| n += sprint(buf+n, " len = %d/%d) ", len, key>>16); |
| if(prot == GRE_ppp && len > 0) |
| n += sprintppp(p, buf+n, len); |
| else |
| n += sprintx(p, buf+n, len); |
| |
| return n; |
| } |