Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / modules / wip / lanman / tcp.c
blob42ed10dd5b811860af63c4aeacf97f64aa188cde
1 /*
2 Copyright (c) 2010 jimmikaelkael <jimmikaelkael@wanadoo.fr>
3 Licenced under Academic Free License version 3.0
4 */
6 #include <tamtypes.h>
7 #include <stdio.h>
8 #include <intrman.h>
9 #include <thbase.h>
10 #include <thsemap.h>
12 #include "tcp.h"
13 #include "lanman.h"
14 #include "smsutils.h"
15 #include "smap.h"
16 #include "inet.h"
18 static g_param_t *g_param;
20 static u8 tcp_sndbuf[1514] __attribute__((aligned(64))); // MTU
21 static u8 tcp_rcvbuf[4096] __attribute__((aligned(64))); // MTU
22 static void *p_rcptbuf;
23 static u16 rcptbuf_size;
24 static int tcp_mutex = -1;
25 static int tcp_listen = 0;
27 #define FIN 0x00
28 #define SYN 0x02
29 #define RST 0x04
30 #define PSH 0x08
31 #define ACK 0x10
33 static u8 TCP_FLAG;
34 static u32 seq_num;
35 static u32 next_seqnum;
36 static u32 ack_num;
38 #define TIMEOUT (3000*1000)
39 iop_sys_clock_t timeout_sysclock;
40 static int timeout_flag = 0;
41 static int tcp_reply_flag = 0;
43 static u16 tcp_port_src = 8209;
45 //-------------------------------------------------------------------------
46 static unsigned int timer_intr_handler(void *args)
48 if (timeout_flag)
49 iSignalSema(tcp_mutex);
51 iSetAlarm(&timeout_sysclock, timer_intr_handler, NULL);
53 return (unsigned int)args;
56 //-------------------------------------------------------------------------
57 void tcp_init(g_param_t *gparam)
59 g_param = gparam;
61 tcpip_pkt_t *tcp_pkt = (tcpip_pkt_t *)tcp_sndbuf;
63 // Initialize the static elements of our TCP packet
64 mips_memcpy(tcp_pkt->eth.addr_dst, g_param->eth_addr_dst, 12); // hardware MAC addresses
65 tcp_pkt->eth.type = 0x0008; // Network byte order: 0x800
66 tcp_pkt->ip.hlen = 0x45; // IPv4
67 tcp_pkt->ip.tos = 0;
68 tcp_pkt->ip.id = 0;
69 tcp_pkt->ip.flags = 0x40; // Don't fragment
70 tcp_pkt->ip.frag_offset = 0;
71 tcp_pkt->ip.ttl = TTL;
72 tcp_pkt->ip.proto = IP_PROTO_TCP;
73 mips_memcpy(&tcp_pkt->ip.addr_src.addr, &g_param->ip_addr_src, 4);
74 mips_memcpy(&tcp_pkt->ip.addr_dst.addr, &g_param->ip_addr_dst, 4);
75 tcp_pkt->tcp_port_src = IP_PORT(tcp_port_src);
76 tcp_pkt->tcp_port_dst = g_param->ip_port_dst;
77 tcp_pkt->tcp_wndsize = htons(TCPWND_SIZE);
79 // create a mutex
80 tcp_mutex = CreateMutex(IOP_MUTEX_LOCKED);
82 USec2SysClock(TIMEOUT, &timeout_sysclock);
83 SetAlarm(&timeout_sysclock, timer_intr_handler, NULL);
86 //-------------------------------------------------------------------------
87 int tcp_output(void *buf, int size, int hdata_flag)
89 tcpip_pkt_t *tcp_pkt;
90 int pktsize;
91 int oldstate;
93 tcp_pkt = (tcpip_pkt_t *)tcp_sndbuf;
94 pktsize = size + sizeof(tcpip_pkt_t);
96 tcp_pkt->ip.len = htons(pktsize - 14); // Subtract the ethernet header
98 tcp_pkt->ip.csum = 0;
99 tcp_pkt->ip.csum = inet_chksum(&tcp_pkt->ip, 20); // Checksum the IP header (20 bytes)
101 CpuSuspendIntr(&oldstate);
102 u32 seqno = htona((u8 *)&seq_num);
103 mips_memcpy(tcp_pkt->tcp_seq_num, &seqno, 4);
104 u32 ackno = htona((u8 *)&ack_num);
105 mips_memcpy(tcp_pkt->tcp_ack_num, &ackno, 4);
106 CpuResumeIntr(oldstate);
108 tcp_pkt->tcp_hdrlen = (hdata_flag ? 20+size : 20) << 2;
109 if (buf)
110 mips_memcpy(&tcp_sndbuf[54], buf, size);
112 tcp_pkt->tcp_flags = TCP_FLAG;
113 tcp_pkt->tcp_csum = 0;
114 tcp_pkt->tcp_csum = inet_chksum_pseudo(&tcp_sndbuf[34], &g_param->ip_addr_src, &g_param->ip_addr_dst, 20+size);
116 CpuSuspendIntr(&oldstate);
117 next_seqnum = seq_num + (TCP_FLAG==SYN ? 1 : size);
118 while (smap_xmit(tcp_pkt, pktsize) != 0);
119 CpuResumeIntr(oldstate);
121 return 1;
124 //-------------------------------------------------------------------------
125 int tcp_input(void *buf, int size) /// !!! Intr Context !!!
127 register u32 ackno;
129 if (tcp_listen) {
130 tcpip_pkt_t *tcp_pkt = (tcpip_pkt_t *)buf;
132 if (inet_chksum_pseudo(&tcp_pkt->tcp_port_src, &g_param->ip_addr_dst, &g_param->ip_addr_src, (ntohs(tcp_pkt->ip.len)-20)) == 0) {// check TCP checksum
133 if (tcp_pkt->tcp_flags & ACK) {
135 ackno = ntoha(tcp_pkt->tcp_ack_num);
136 if (ackno == next_seqnum) {
137 // packet is aknowledged
138 if (ntoha(tcp_pkt->tcp_seq_num) == ack_num-1)
139 tcp_send_ack(); // keep alive ack
140 else {
141 int len = ntohs(tcp_pkt->ip.len) - 20 - (tcp_pkt->tcp_hdrlen >> 2);
142 seq_num = ackno;
143 ack_num = ntoha(tcp_pkt->tcp_seq_num) + len + (tcp_pkt->tcp_flags & SYN ? 1 : 0);
144 if ((len > 0) || (tcp_pkt->tcp_flags & SYN)) {
145 // do input buffering
146 if (tcp_pkt->tcp_flags == (ACK|PSH))
147 tcp_send_ack();
148 tcp_reply_flag = 1;
149 p_rcptbuf = buf;
150 rcptbuf_size = size;
151 iSignalSema(tcp_mutex);
159 return 1;
162 //-------------------------------------------------------------------------
163 void tcp_send(void *buf, int size, int hdata_flag)
165 int oldstate;
166 tcpip_pkt_t *tcp_sndpkt = (tcpip_pkt_t *)tcp_sndbuf;
168 send:
169 if (TCP_FLAG==SYN) {
170 // select a port and increment it for retries
171 tcp_sndpkt->tcp_port_src = IP_PORT(tcp_port_src);
172 tcp_port_src++;
175 CpuSuspendIntr(&oldstate);
176 timeout_flag = 1;
177 tcp_listen = 1;
178 CpuResumeIntr(oldstate);
180 tcp_output(buf, size, hdata_flag);
182 WaitSema(tcp_mutex);
184 //while (QueryIntrContext())
185 // DelayThread(10000);
187 CpuSuspendIntr(&oldstate);
188 timeout_flag = 0;
189 tcp_listen = 0;
190 if (tcp_reply_flag == 0) { // It was a timeout ?
191 CpuResumeIntr(oldstate);
192 goto send; // yes, retry...
194 tcp_reply_flag = 0;
195 mips_memcpy(tcp_rcvbuf, p_rcptbuf, rcptbuf_size);
196 CpuResumeIntr(oldstate);
199 //-------------------------------------------------------------------------
200 void tcp_connect(void)
202 iop_sys_clock_t sysclock;
203 u8 options[4];
205 TCP_FLAG = SYN;
207 // generate ISN
208 GetSystemTime(&sysclock);
209 seq_num = sysclock.lo & 0xffff;
210 ack_num = 0;
212 // Options: MSS=1460
213 *((u16 *)&options[0]) = 0x0402;
214 *((u16 *)&options[2]) = htons(TCP_MSS);
216 // send the SYN
217 tcp_send(options, sizeof(options), 1);
219 TCP_FLAG = ACK|PSH;
221 tcp_send_ack();
224 //-------------------------------------------------------------------------
225 void tcp_send_ack(void)
227 TCP_FLAG = ACK;
228 tcp_output("\0", 0, 0);
229 TCP_FLAG = ACK|PSH;