Watt-32 tcp/ip  2.2 dev-rel.10
loopback.c
Go to the documentation of this file.
1 
48 #include <stdio.h>
49 #include <stdlib.h>
50 
51 #include "wattcp.h"
52 #include "misc.h"
53 #include "chksum.h"
54 #include "ip4_in.h"
55 #include "ip6_in.h"
56 #include "pcsed.h"
57 #include "pcstat.h"
58 #include "pcicmp.h"
59 #include "strings.h"
60 #include "loopback.h"
61 
62 WORD loopback_mode = LBACK_MODE_ENABLE;
63 
64 #if defined(USE_LOOPBACK)
65 
66 #if 0
67 
68  A sketch of calls involved in sending/receiving an IP-packet
69 
70 
71  Sending an IP-packet | Receiving an IP-packet
72  --------------------------------|-----------------------------------
73  | | |
74  | | tcp_tick()
75  | | |
76  _eth_formatpacket() ->buffer X | _eth_arrived()
77  | | |
79  | | |
80  | | |
81  _eth_send() enqueue copy of |
82  | X to IP-queue |
83  *----->loopback_device()--*-->>>>>>-<-------pkt_poll_recv()
84  | (1) | | | | |
85  | | | | | |
86  | | | | | |
87  | | | | | |
88  _pkt_send() drop buffer X \ | | none _ip4_handler()
89  | | | | |
90  | | | \ ip4_defragment()
91  | | | |
92  | | | protocol handlers
93  | | | |
94  | | | _eth_free()
95  v | | |
96  packet-driver | `-----------<-- pkt_free_pkt()
97  | | |
98  Ethernet/PPP \
99 
100  From the above it evident the current design cannot easily send
101  IP-fragments. _ip4_output() must be rewritten to handle max. 64kB
102  packets, split them in make_fragments(), format a link-layer packet
103  using _eth_formatpacket() and repetively call _eth_send().
104 
105  (1): A future Win32 version could try enqueueing to the Winsock
106  loopback handler. A TDI provider??
107 #endif
108 
109 
110 int (W32_CALL *loopback_handler) (in_Header*) = NULL;
111 
112 static int icmp_loopback (ICMP_PKT *icmp, unsigned icmp_len);
113 static int udp_loopback (udp_Header *udp, unsigned udp_len);
114 
122 int loopback_device (in_Header *ip)
123 {
124  int ip_len = 0;
125  DWORD ip_dst;
126  DWORD ip_ofs;
127  WORD ip_flg;
128 
129  if (!(loopback_mode & LBACK_MODE_ENABLE))
130  return (-1);
131 
132  if (ip->ver == 4)
133  {
134  int ip_hlen;
135 
136  if (!_chk_ip4_header(ip)) /* silently discard */
137  return (-1);
138 
139  ip_hlen = in_GetHdrLen (ip); /* length of IP-header (w/options) */
140  ip_len = intel16 (ip->length); /* total length of IP-packet */
141  ip_dst = ip->destination;
142 
143  ip->destination = ip->source; /* swap source and destination */
144  ip->source = ip_dst;
145  ip->checksum = 0;
146  ip->checksum = ~CHECKSUM (ip, ip_hlen); /* redo check-sum */
147 
148  ip_ofs = intel16 (ip->frag_ofs);
149  ip_flg = (WORD) (ip_ofs & ~IP_OFFMASK);
150  ip_ofs = (ip_ofs & IP_OFFMASK) << 3; /* 0 <= ip_ofs <= 65536-8 */
151 
152  if (ip_ofs || (ip_flg & IP_MF)) /* fragment; let ip4_defragment() */
153  return (ip_len); /* handle it on next poll */
154 
155  if (ip->proto == ICMP_PROTO)
156  {
157  ICMP_PKT *icmp = (ICMP_PKT*) ((BYTE*)ip + ip_hlen);
158  int len = icmp_loopback (icmp, ip_len - ip_hlen);
159 
160  if (len > 0)
161  return (ip_hlen+len);
162  }
163  else if (ip->proto == UDP_PROTO)
164  {
165  udp_Header *udp = (udp_Header*) ((BYTE*)ip + ip_hlen);
166  int len = udp_loopback (udp, ip_len-ip_hlen);
167 
168  if (len > 0)
169  return (ip_hlen+len);
170  }
171  }
172 #if defined(USE_IPV6)
173  else if (ip->ver == 6)
174  {
175  in6_Header *ip6 = (in6_Header*)ip;
176  ip6_address ip6_dst;
177 
178  ip_len = intel16 (ip6->len);
179  memcpy (&ip6_dst, &ip6->destination, sizeof(ip6_dst));
180  memcpy (&ip6->destination, &ip6->source, sizeof(ip6->destination));
181  memcpy (&ip6->source, &ip6_dst, sizeof(ip6->source));
182 
183  if (ip6->next_hdr == IP6_NEXT_ICMP)
184  {
185  ICMP_PKT *icmp = (ICMP_PKT*) (ip6 + 1);
186  int len = icmp_loopback (icmp, ip_len);
187 
188  if (len > 0)
189  return (len + sizeof(*ip6));
190  }
191  else if (ip6->next_hdr == UDP_PROTO)
192  {
193  udp_Header *udp = (udp_Header*) (ip6 + 1);
194  int len = udp_loopback (udp, ip_len);
195 
196  if (len > 0)
197  return (len + sizeof(*ip6));
198  }
199  }
200  else
201  {
202  (*_printf) ("%s: Illegal IP-packet (ver %d) for loopback device\n",
203  __FILE__, ip->ver);
204  return (-1);
205  }
206 #endif
207 
208  if (loopback_handler)
209  ip_len = (*loopback_handler) (ip);
210  return (ip_len);
211 }
212 
213 static int icmp_loopback (ICMP_PKT *icmp, unsigned icmp_len)
214 {
215  if (icmp_len >= sizeof(icmp->echo) &&
216  CHECKSUM(icmp,icmp_len) == 0xFFFF &&
217  icmp->echo.type == ICMP_ECHO)
218  {
219  static WORD echo_seq_num = 0;
220 
221  icmp->echo.type = ICMP_ECHOREPLY;
222  icmp->echo.sequence = echo_seq_num++;
223  icmp->echo.checksum = 0;
224  icmp->echo.checksum = ~CHECKSUM (icmp, icmp_len);
225  STAT (icmpstats.icps_reflect++);
226  STAT (icmpstats.icps_outhist[ICMP_ECHOREPLY]++);
227  return (icmp_len);
228  }
231  return (0);
232 }
233 
234 static int udp_loopback (udp_Header *udp, unsigned udp_len)
235 {
236  if (intel16(udp->dstPort) == IPPORT_ECHO)
237  {
239  }
240  else if (intel16(udp->dstPort) == IPPORT_DISCARD)
241  {
243  }
244  ARGSUSED (udp_len);
245  return (0);
246 }
247 
248 /*
249  * An example loopback handler for RPC Portmapper (udp port 111)
250  * (Maybe an contradiction in terms to do RPC locally :-)
251  *
252  * int (W32_CALL *old_loopback) (const in_Header*) = NULL;
253  *
254  * static W32_CALL int pmap_loopback (const in_Header *ip)
255  * {
256  * WORD hlen = in_GetHdrLen (ip);
257  * const udp_Header *udp = (const udp_Header*) ((BYTE*)ip + hlen);
258  *
259  * if (ip->proto == UDP_PROTO && intel16(udp->dstPort) == 111)
260  * return do_portmapper (udp); // return length of IP reply packet
261  *
262  * if (old_loopback)
263  * return (*old_loopback) (ip);
264  * return intel16 (ip->length);
265  * }
266  *
267  * void init_pmap_loopback (void)
268  * {
269  * old_loopback = loopback_handler;
270  * loopback_handler = pmap_loopback;
271  * }
272  */
273 
274 #endif /* USE_LOOPBACK */
void W32_CALL _eth_free(const void *pkt)
Free an input buffer once it is no longer needed.
Definition: pcsed.c:792
int _ip4_output(in_Header *ip, DWORD src_ip, DWORD dst_ip, BYTE protocol, BYTE ttl, BYTE tos, WORD ip_id, int data_len, const void *sock, const char *file, unsigned line)
The IP4 packet transmitter.
Definition: ip4_out.c:86
int _ip4_handler(const in_Header *ip, BOOL broadcast)
Definition: ip4_in.c:34
int W32_CALL _eth_send(WORD len, const void *sock, const char *file, unsigned line)
_eth_send() does the actual transmission once we are complete with filling the buffer.
Definition: pcsed.c:306
Core definitions.
Definition: ip_icmp.h:62
static union link_Packet * poll_recv_queue(WORD *type)
Poll the packet queue.
Definition: pcsed.c:895
void *W32_CALL _eth_formatpacket(const void *mac_dest, WORD eth_type)
_eth_format_packet() places the next packet to be transmitted into the above link-layer output packet...
Definition: pcsed.c:135
Definition: ip.h:67
static int icmp_loopback(ICMP_PKT *icmp, unsigned icmp_len)
Definition: loopback.c:213
void pkt_free_pkt(const void *pkt)
Release a packet from the receive queue.
Definition: pcpkt.c:1349
WORD W32_CALL tcp_tick(sock_type *s)
Must be called periodically by user application (or BSD socket API).
Definition: pctcp.c:1389
static int udp_loopback(udp_Header *udp, unsigned udp_len)
Definition: loopback.c:234
void *W32_CALL _eth_arrived(WORD *type_ptr, BOOL *broadcast)
Poll for arrival of new packets (IP/ARP/RARP/PPPoE protocol).
Definition: pcsed.c:1026