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