- Implement OskitTCPGetSocketError which retreives so->so_error
[reactos.git] / reactos / lib / drivers / oskittcp / oskittcp / interface.c
1 #include <oskittcp.h>
2 #include <oskitdebug.h>
3 #include <net/raw_cb.h>
4
5 #include <sys/param.h>
6 #include <sys/systm.h>
7 #include <sys/socket.h>
8 #include <sys/kernel.h>
9 #include <sys/filedesc.h>
10 #include <sys/proc.h>
11 #include <sys/fcntl.h>
12 #include <sys/file.h>
13 #include <sys/mbuf.h>
14 #include <sys/protosw.h>
15 #include <sys/socket.h>
16 #include <sys/socketvar.h>
17 #include <sys/uio.h>
18
19 struct linker_set domain_set;
20
21 OSKITTCP_EVENT_HANDLERS OtcpEvent = { 0 };
22
23 //OSK_UINT OskitDebugTraceLevel = OSK_DEBUG_ULTRA;
24 OSK_UINT OskitDebugTraceLevel = 0;
25
26 KSPIN_LOCK OSKLock;
27
28 /* SPL */
29 unsigned cpl;
30 unsigned net_imask;
31 unsigned volatile ipending;
32 struct timeval boottime;
33
34 void clock_init();
35 int _snprintf(char * buf, size_t cnt, const char *fmt, ...);
36
37 void *fbsd_malloc( unsigned int bytes, char *file, unsigned line, ... ) {
38 if( !OtcpEvent.TCPMalloc ) panic("no malloc");
39 return OtcpEvent.TCPMalloc
40 ( OtcpEvent.ClientData, (OSK_UINT)bytes, (OSK_PCHAR)file, line );
41 }
42
43 void fbsd_free( void *data, char *file, unsigned line, ... ) {
44 if( !OtcpEvent.TCPFree ) panic("no free");
45 OtcpEvent.TCPFree( OtcpEvent.ClientData, data, (OSK_PCHAR)file, line );
46 }
47
48 void InitOskitTCP() {
49 OS_DbgPrint(OSK_MID_TRACE,("Init Called\n"));
50 KeInitializeSpinLock(&OSKLock);
51 OS_DbgPrint(OSK_MID_TRACE,("MB Init\n"));
52 mbinit();
53 OS_DbgPrint(OSK_MID_TRACE,("Rawip Init\n"));
54 rip_init();
55 raw_init();
56 OS_DbgPrint(OSK_MID_TRACE,("Route Init\n"));
57 route_init();
58 OS_DbgPrint(OSK_MID_TRACE,("Init clock\n"));
59 clock_init();
60 OS_DbgPrint(OSK_MID_TRACE,("Init TCP\n"));
61 tcp_init();
62 OS_DbgPrint(OSK_MID_TRACE,("Init routing\n"));
63 domaininit();
64 OS_DbgPrint(OSK_MID_TRACE,("Init Finished\n"));
65 tcp_iss = 1024;
66 }
67
68 void DeinitOskitTCP() {
69 }
70
71 void TimerOskitTCP( int FastTimer, int SlowTimer ) {
72 KIRQL OldIrql;
73
74 /* This function is a special case in which we cannot use OSKLock/OSKUnlock
75 * because we don't enter with the connection lock held */
76
77 OSKLockAndRaise(&OldIrql);
78 if ( SlowTimer ) {
79 tcp_slowtimo();
80 }
81 if ( FastTimer ) {
82 tcp_fasttimo();
83 }
84 OSKUnlockAndLower(OldIrql);
85 }
86
87 void RegisterOskitTCPEventHandlers( POSKITTCP_EVENT_HANDLERS EventHandlers ) {
88 memcpy( &OtcpEvent, EventHandlers, sizeof(OtcpEvent) );
89 }
90
91 void OskitDumpBuffer( OSK_PCHAR Data, OSK_UINT Len )
92 {
93 unsigned int i;
94 char line[81];
95 static const char* hex = "0123456789abcdef";
96
97 for ( i = 0; i < Len; i++ )
98 {
99 int align = i & 0xf;
100 int align3 = (align<<1) + align;
101 unsigned char c = Data[i];
102 if ( !align )
103 {
104 if ( i ) DbgPrint( line );
105 _snprintf ( line, sizeof(line)-1, "%08x: \n", &Data[i] );
106 line[sizeof(line)-1] = '\0';
107 }
108
109 line[10+align3] = hex[(c>>4)&0xf];
110 line[11+align3] = hex[c&0xf];
111 if ( !isprint(c) )
112 c = '.';
113 line[59+align] = c;
114 }
115 if ( Len & 0xf )
116 DbgPrint ( line );
117 }
118
119 /* From uipc_syscalls.c */
120
121 int OskitTCPSocket( void *context,
122 void **aso,
123 int domain,
124 int type,
125 int proto )
126 {
127 struct socket *so;
128
129 OSKLock();
130 int error = socreate(domain, &so, type, proto);
131 if( !error ) {
132 so->so_connection = context;
133 so->so_state |= SS_NBIO;
134 *aso = so;
135 }
136 OSKUnlock();
137
138 return error;
139 }
140
141 int OskitTCPRecv( void *connection,
142 OSK_PCHAR Data,
143 OSK_UINT Len,
144 OSK_UINT *OutLen,
145 OSK_UINT Flags ) {
146 struct uio uio = { 0 };
147 struct iovec iov = { 0 };
148 int error = 0;
149 int tcp_flags = 0;
150
151 OS_DbgPrint(OSK_MID_TRACE,
152 ("so->so_state %x\n", ((struct socket *)connection)->so_state));
153
154 if( Flags & OSK_MSG_OOB ) tcp_flags |= MSG_OOB;
155 if( Flags & OSK_MSG_DONTWAIT ) tcp_flags |= MSG_DONTWAIT;
156 if( Flags & OSK_MSG_PEEK ) tcp_flags |= MSG_PEEK;
157
158 iov.iov_len = Len;
159 iov.iov_base = (char *)Data;
160 uio.uio_iov = &iov;
161 uio.uio_iovcnt = 1;
162 uio.uio_offset = 0;
163 uio.uio_resid = Len;
164 uio.uio_segflg = UIO_SYSSPACE;
165 uio.uio_rw = UIO_READ;
166 uio.uio_procp = NULL;
167
168 OS_DbgPrint(OSK_MID_TRACE,("Reading %d bytes from TCP:\n", Len));
169
170 OSKLock();
171 error = soreceive( connection, NULL, &uio, NULL, NULL /* SCM_RIGHTS */,
172 &tcp_flags );
173 OSKUnlock();
174
175 *OutLen = Len - uio.uio_resid;
176
177 return error;
178 }
179
180 int OskitTCPBind( void *socket,
181 void *nam, OSK_UINT namelen ) {
182 int error = EFAULT;
183 struct socket *so = socket;
184 struct mbuf sabuf;
185 struct sockaddr addr;
186
187 OS_DbgPrint(OSK_MID_TRACE,("Called, socket = %08x\n", socket));
188
189 if (!socket)
190 return OSK_ESHUTDOWN;
191
192 if( nam )
193 addr = *((struct sockaddr *)nam);
194
195 RtlZeroMemory(&sabuf, sizeof(sabuf));
196 sabuf.m_data = (void *)&addr;
197 sabuf.m_len = sizeof(addr);
198
199 addr.sa_family = addr.sa_len;
200 addr.sa_len = sizeof(struct sockaddr);
201
202 OSKLock();
203 error = sobind(so, &sabuf);
204 OSKUnlock();
205
206 OS_DbgPrint(OSK_MID_TRACE,("Ending: %08x\n", error));
207 return (error);
208 }
209
210 int OskitTCPConnect( void *socket, void *nam, OSK_UINT namelen ) {
211 struct socket *so = socket;
212 int error = EFAULT;
213 struct mbuf sabuf;
214 struct sockaddr addr;
215
216 OS_DbgPrint(OSK_MID_TRACE,("Called, socket = %08x\n", socket));
217
218 OSKLock();
219 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
220 error = EALREADY;
221 goto done;
222 }
223
224 OS_DbgPrint(OSK_MIN_TRACE,("Nam: %x\n", nam));
225 if( nam )
226 addr = *((struct sockaddr *)nam);
227
228 RtlZeroMemory(&sabuf, sizeof(sabuf));
229 sabuf.m_data = (void *)&addr;
230 sabuf.m_len = sizeof(addr);
231
232 addr.sa_family = addr.sa_len;
233 addr.sa_len = sizeof(struct sockaddr);
234
235 error = soconnect(so, &sabuf);
236
237 if (error == EINPROGRESS)
238 goto done;
239 else if (error)
240 goto bad;
241
242 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
243 error = EINPROGRESS;
244 goto done;
245 }
246
247 bad:
248 so->so_state &= ~SS_ISCONNECTING;
249
250 if (error == ERESTART)
251 error = EINTR;
252
253 done:
254 OSKUnlock();
255 OS_DbgPrint(OSK_MID_TRACE,("Ending: %08x\n", error));
256 return (error);
257 }
258
259 int OskitTCPDisconnect(void *socket)
260 {
261 int error;
262
263 if (!socket)
264 return OSK_ESHUTDOWN;
265
266 OSKLock();
267 error = sodisconnect(socket);
268 OSKUnlock();
269
270 return error;
271 }
272
273 int OskitTCPShutdown( void *socket, int disconn_type ) {
274 int error;
275
276 if (!socket)
277 return OSK_ESHUTDOWN;
278
279 OSKLock();
280 error = soshutdown( socket, disconn_type );
281 OSKUnlock();
282
283 return error;
284 }
285
286 int OskitTCPClose( void *socket ) {
287 int error;
288
289 if (!socket)
290 return OSK_ESHUTDOWN;
291
292 OSKLock();
293 error = soclose( socket );
294 OSKUnlock();
295
296 return error;
297 }
298
299 int OskitTCPSend( void *socket, OSK_PCHAR Data, OSK_UINT Len,
300 OSK_UINT *OutLen, OSK_UINT flags ) {
301 int error;
302 struct uio uio;
303 struct iovec iov;
304
305 if (!socket)
306 return OSK_ESHUTDOWN;
307
308 iov.iov_len = Len;
309 iov.iov_base = (char *)Data;
310 uio.uio_iov = &iov;
311 uio.uio_iovcnt = 1;
312 uio.uio_offset = 0;
313 uio.uio_resid = Len;
314 uio.uio_segflg = UIO_SYSSPACE;
315 uio.uio_rw = UIO_WRITE;
316 uio.uio_procp = NULL;
317
318 OSKLock();
319 error = sosend( socket, NULL, &uio, NULL, NULL, 0 );
320 OSKUnlock();
321
322 *OutLen = Len - uio.uio_resid;
323
324 return error;
325 }
326
327 int OskitTCPAccept( void *socket,
328 void **new_socket,
329 void *context,
330 void *AddrOut,
331 OSK_UINT AddrLen,
332 OSK_UINT *OutAddrLen,
333 OSK_UINT FinishAccepting ) {
334 struct socket *head = (void *)socket;
335 struct sockaddr *name = (struct sockaddr *)AddrOut;
336 struct socket **newso = (struct socket **)new_socket;
337 struct socket *so = socket;
338 struct sockaddr_in sa;
339 struct mbuf mnam;
340 struct inpcb *inp;
341 int namelen = 0, error = 0, s;
342
343 if (!socket)
344 return OSK_ESHUTDOWN;
345
346 if (!new_socket || !AddrOut)
347 return OSK_EINVAL;
348
349 OS_DbgPrint(OSK_MID_TRACE,("OSKITTCP: Doing accept (Finish %d)\n",
350 FinishAccepting));
351
352 *OutAddrLen = AddrLen;
353
354 if (name)
355 /* that's a copyin actually */
356 namelen = *OutAddrLen;
357
358 OSKLock();
359
360 s = splnet();
361
362 #if 0
363 if ((head->so_options & SO_ACCEPTCONN) == 0) {
364 OS_DbgPrint(OSK_MID_TRACE,("OSKITTCP: head->so_options = %x, wanted bit %x\n",
365 head->so_options, SO_ACCEPTCONN));
366 error = EINVAL;
367 goto out;
368 }
369 #endif
370
371 OS_DbgPrint(OSK_MID_TRACE,("head->so_q = %x, head->so_state = %x\n",
372 head->so_q, head->so_state));
373
374 if ((head->so_state & SS_NBIO) && head->so_q == NULL) {
375 error = EWOULDBLOCK;
376 goto out;
377 }
378
379 /*
380 * At this point we know that there is at least one connection
381 * ready to be accepted. Remove it from the queue.
382 */
383 so = head->so_q;
384
385 inp = so ? (struct inpcb *)so->so_pcb : NULL;
386 if( inp && name ) {
387 ((struct sockaddr_in *)AddrOut)->sin_addr.s_addr =
388 inp->inp_faddr.s_addr;
389 ((struct sockaddr_in *)AddrOut)->sin_port = inp->inp_fport;
390 }
391
392 OS_DbgPrint(OSK_MID_TRACE,("error = %d\n", error));
393 if( FinishAccepting && so ) {
394 head->so_q = so->so_q;
395 head->so_qlen--;
396
397 mnam.m_data = (char *)&sa;
398 mnam.m_len = sizeof(sa);
399
400 error = soaccept(so, &mnam);
401 if (error)
402 goto out;
403
404 so->so_state |= SS_NBIO | SS_ISCONNECTED;
405 so->so_q = so->so_q0 = NULL;
406 so->so_qlen = 0;
407 so->so_head = 0;
408 so->so_connection = context;
409
410 *newso = so;
411
412 OS_DbgPrint(OSK_MID_TRACE,("error = %d\n", error));
413 if (name) {
414 /* check sa_len before it is destroyed */
415 memcpy( AddrOut, &sa, AddrLen < sizeof(sa) ? AddrLen : sizeof(sa) );
416 OS_DbgPrint(OSK_MID_TRACE,("error = %d\n", error));
417 *OutAddrLen = namelen; /* copyout actually */
418 }
419 OS_DbgPrint(OSK_MID_TRACE,("error = %d\n", error));
420 }
421 out:
422 splx(s);
423 OSKUnlock();
424 OS_DbgPrint(OSK_MID_TRACE,("OSKITTCP: Returning %d\n", error));
425 return (error);
426 }
427
428 /* The story so far
429 *
430 * We have a packet. While we store the fields we want in host byte order
431 * outside the original packet, the bsd stack modifies them in place.
432 */
433
434 void OskitTCPReceiveDatagram( OSK_PCHAR Data, OSK_UINT Len,
435 OSK_UINT IpHeaderLen ) {
436 struct mbuf *Ip;
437 struct ip *iph;
438 KIRQL OldIrql;
439
440 /* This function is a special case in which we cannot use OSKLock/OSKUnlock
441 * because we don't enter with the connection lock held */
442
443 OSKLockAndRaise(&OldIrql);
444 Ip = m_devget( (char *)Data, Len, 0, NULL, NULL );
445 if( !Ip )
446 {
447 OSKUnlockAndLower(OldIrql);
448 return; /* drop the segment */
449 }
450
451 //memcpy( Ip->m_data, Data, Len );
452 Ip->m_pkthdr.len = IpHeaderLen;
453
454 /* Do the transformations on the header that tcp_input expects */
455 iph = mtod(Ip, struct ip *);
456 NTOHS(iph->ip_len);
457 iph->ip_len -= sizeof(struct ip);
458
459 OS_DbgPrint(OSK_MAX_TRACE,
460 ("OskitTCPReceiveDatagram: %d (%d header) Bytes\n", Len,
461 IpHeaderLen));
462
463 tcp_input(Ip, IpHeaderLen);
464 OSKUnlockAndLower(OldIrql);
465
466 /* The buffer Ip is freed by tcp_input */
467 }
468
469 int OskitTCPSetSockOpt(void *socket,
470 int level,
471 int optname,
472 char *buffer,
473 int size)
474 {
475 struct mbuf *m;
476 int error;
477
478 if (!socket)
479 return OSK_ESHUTDOWN;
480
481 if (size >= MLEN)
482 return OSK_EINVAL;
483
484 OSKLock();
485 m = m_get(M_WAIT, MT_SOOPTS);
486 if (!m)
487 {
488 OSKUnlock();
489 return OSK_ENOMEM;
490 }
491
492 m->m_len = size;
493
494 memcpy(m->m_data, buffer, size);
495
496 /* m is freed by sosetopt */
497 error = sosetopt(socket, level, optname, m);
498 OSKUnlock();
499
500 return error;
501 }
502
503 int OskitTCPGetSockOpt(void *socket,
504 int level,
505 int optname,
506 char *buffer,
507 int *size)
508 {
509 int error, oldsize = *size;
510 struct mbuf *m;
511
512 if (!socket)
513 return OSK_ESHUTDOWN;
514
515 OSKLock();
516 error = sogetopt(socket, level, optname, &m);
517 if (!error)
518 {
519 *size = m->m_len;
520
521 if (!buffer || oldsize < m->m_len)
522 {
523 m_freem(m);
524 OSKUnlock();
525 return OSK_EINVAL;
526 }
527
528 memcpy(buffer, m->m_data, m->m_len);
529
530 m_freem(m);
531 }
532 OSKUnlock();
533
534 return error;
535 }
536
537 int OskitTCPListen( void *socket, int backlog ) {
538 int error;
539
540 if (!socket)
541 return OSK_ESHUTDOWN;
542
543 OS_DbgPrint(OSK_MID_TRACE,("Called, socket = %08x\n", socket));
544
545 OSKLock();
546 error = solisten( socket, backlog );
547 OSKUnlock();
548
549 OS_DbgPrint(OSK_MID_TRACE,("Ending: %08x\n", error));
550
551 return error;
552 }
553
554 int OskitTCPSetAddress( void *socket,
555 OSK_UINT LocalAddress,
556 OSK_UI16 LocalPort,
557 OSK_UINT RemoteAddress,
558 OSK_UI16 RemotePort ) {
559 struct socket *so = socket;
560 struct inpcb *inp;
561
562 if (!socket)
563 return OSK_ESHUTDOWN;
564
565 OSKLock();
566 inp = (struct inpcb *)so->so_pcb;
567 inp->inp_laddr.s_addr = LocalAddress;
568 inp->inp_lport = LocalPort;
569 inp->inp_faddr.s_addr = RemoteAddress;
570 inp->inp_fport = RemotePort;
571 OSKUnlock();
572
573 return 0;
574 }
575
576 int OskitTCPGetAddress( void *socket,
577 OSK_UINT *LocalAddress,
578 OSK_UI16 *LocalPort,
579 OSK_UINT *RemoteAddress,
580 OSK_UI16 *RemotePort ) {
581 struct socket *so = socket;
582 struct inpcb *inp;
583
584 if (!socket)
585 return OSK_ESHUTDOWN;
586
587 OSKLock();
588 inp = (struct inpcb *)so->so_pcb;
589 *LocalAddress = inp->inp_laddr.s_addr;
590 *LocalPort = inp->inp_lport;
591 *RemoteAddress = inp->inp_faddr.s_addr;
592 *RemotePort = inp->inp_fport;
593 OSKUnlock();
594
595 return 0;
596 }
597
598 int OskitTCPGetSocketError(void *socket) {
599 struct socket *so = socket;
600 int error;
601
602 if (!socket)
603 return OSK_ESHUTDOWN;
604
605 OSKLock();
606 error = so->so_error;
607 OSKUnlock();
608
609 return error;
610 }
611
612 struct ifaddr *ifa_iffind(struct sockaddr *addr, int type)
613 {
614 if( OtcpEvent.FindInterface )
615 return OtcpEvent.FindInterface( OtcpEvent.ClientData,
616 PF_INET,
617 type,
618 addr );
619 else
620 return NULL;
621 }
622
623 void oskittcp_die( const char *file, int line ) {
624 DbgPrint("\n\n*** OSKITTCP: Panic Called at %s:%d ***\n", file, line);
625 ASSERT(FALSE);
626 }
627
628 /* Stuff supporting the BSD network-interface interface */
629 struct ifaddr **ifnet_addrs;
630 struct ifnet *ifnet;
631
632 void
633 ifinit()
634 {
635 }
636
637
638 void
639 if_attach(ifp)
640 struct ifnet *ifp;
641 {
642 panic("if_attach\n");
643 }
644
645 struct ifnet *
646 ifunit(char *name)
647 {
648 return 0;
649 }
650
651 /*
652 * Handle interface watchdog timer routines. Called
653 * from softclock, we decrement timers (if set) and
654 * call the appropriate interface routine on expiration.
655 */
656 void
657 if_slowtimo(arg)
658 void *arg;
659 {
660 #if 0
661 register struct ifnet *ifp;
662 int s = splimp();
663
664 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
665 if (ifp->if_timer == 0 || --ifp->if_timer)
666 continue;
667 if (ifp->if_watchdog)
668 (*ifp->if_watchdog)(ifp->if_unit);
669 }
670 splx(s);
671 timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);
672 #endif
673 }
674
675 /*
676 * Locate an interface based on a complete address.
677 */
678
679 /*ARGSUSED*/
680 struct ifaddr *ifa_ifwithaddr(addr)
681 struct sockaddr *addr;
682 {
683 struct ifaddr *ifaddr = ifa_ifwithnet( addr );
684 struct sockaddr_in *addr_in;
685 struct sockaddr_in *faddr_in;
686
687 if( !ifaddr ) {
688 OS_DbgPrint(OSK_MID_TRACE,("No ifaddr\n"));
689 return NULL;
690 } else {
691 OS_DbgPrint(OSK_MID_TRACE,("ifaddr @ %x\n", ifaddr));
692 }
693
694 addr_in = (struct sockaddr_in *)addr;
695 faddr_in = (struct sockaddr_in *)ifaddr->ifa_addr;
696
697 if( faddr_in->sin_addr.s_addr == addr_in->sin_addr.s_addr )
698 return ifaddr;
699 else
700 return NULL;
701 }
702
703 /*
704 * Locate the point to point interface with a given destination address.
705 */
706 /*ARGSUSED*/
707 struct ifaddr *
708 ifa_ifwithdstaddr(addr)
709 register struct sockaddr *addr;
710 {
711 OS_DbgPrint(OSK_MID_TRACE,("Called\n"));
712 return ifa_iffind(addr, IFF_POINTOPOINT);
713 }
714
715 /*
716 * Find an interface on a specific network. If many, choice
717 * is most specific found.
718 */
719 struct ifaddr *ifa_ifwithnet(addr)
720 struct sockaddr *addr;
721 {
722 struct sockaddr_in *sin;
723 struct ifaddr *ifaddr = ifa_iffind(addr, IFF_UNICAST);
724
725 if( ifaddr )
726 {
727 sin = (struct sockaddr_in *)&ifaddr->ifa_addr;
728
729 OS_DbgPrint(OSK_MID_TRACE,("ifaddr->addr = %x\n",
730 sin->sin_addr.s_addr));
731 }
732
733 return ifaddr;
734 }
735