tweak for building in fedora20
[ipfw-google.git] / kipfw / md_win.c
1 /*
2  * Copyright (C) 2010 Luigi Rizzo, Francesco Magno, Universita` di Pisa
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 /*
27  * kernel variables and functions that are not available in Windows.
28  */
29
30 #include <net/pfil.h> /* provides PFIL_IN and PFIL_OUT */
31 #include <arpa/inet.h>
32 #include <netinet/in.h>                 /* in_addr */
33 #include <ndis.h>
34 #include <sys/mbuf.h>
35 #include <passthru.h>
36
37 /* credentials check */
38 int
39 cred_check(void *_insn,  int proto, struct ifnet *oif,
40     struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,
41     u_int16_t src_port, struct bsd_ucred *u, int *ugid_lookupp,
42     struct sk_buff *skb)
43 {
44         return 0;
45 }
46
47 /*
48  * as good as anywhere, place here the missing calls
49  */
50
51 void *
52 my_alloc(int size)
53 {
54         void *_ret = ExAllocatePoolWithTag(NonPagedPool, size, 'wfpi');
55         if (_ret)
56                 memset(_ret, 0, size);
57         return _ret;
58 }
59
60 void
61 panic(const char *fmt, ...)
62 {
63         printf("%s", fmt);
64         for (;;);
65 }
66
67 int securelevel = 0;
68
69 int ffs(int bits)
70 {
71         int i;
72         if (bits == 0)
73                 return (0);
74         for (i = 1; ; i++, bits >>= 1) {
75                 if (bits & 1)
76                         break;
77         }
78         return (i);
79 }
80
81 void
82 do_gettimeofday(struct timeval *tv)
83 {
84         static LARGE_INTEGER prevtime; //system time in 100-nsec resolution
85         static LARGE_INTEGER prevcount; //RTC counter value
86         static LARGE_INTEGER freq; //frequency
87
88         LARGE_INTEGER currtime;
89         LARGE_INTEGER currcount;
90         if (prevtime.QuadPart == 0) { //first time we ask for system time
91                 KeQuerySystemTime(&prevtime);
92                 prevcount = KeQueryPerformanceCounter(&freq);
93                 currtime.QuadPart = prevtime.QuadPart;
94         } else {
95                 KeQuerySystemTime(&currtime);
96                 currcount = KeQueryPerformanceCounter(&freq);
97                 if (currtime.QuadPart == prevtime.QuadPart) {
98                         //time has NOT changed, calculate time using ticks and DO NOT update
99                         LONGLONG difftime = 0; //difference in 100-nsec
100                         LONGLONG diffcount = 0; //clock count difference
101                         //printf("time has NOT changed\n");
102                         diffcount = currcount.QuadPart - prevcount.QuadPart;
103                         diffcount *= 10000000;
104                         difftime = diffcount / freq.QuadPart;
105                         currtime.QuadPart += difftime;
106                 } else {        
107                         //time has changed, update and return SystemTime
108                         //printf("time has changed\n");
109                         prevtime.QuadPart = currtime.QuadPart;
110                         prevcount.QuadPart = currcount.QuadPart;
111                 }
112         }
113         currtime.QuadPart /= 10; //convert in usec
114         tv->tv_sec = currtime.QuadPart / (LONGLONG)1000000;
115         tv->tv_usec = currtime.QuadPart % (LONGLONG)1000000;
116         //printf("sec %d usec %d\n",tv->tv_sec, tv->tv_usec);
117 }
118
119 int time_uptime_w32()
120 {
121         int ret;
122         LARGE_INTEGER tm;
123         KeQuerySystemTime(&tm);
124         ret = (int)(tm.QuadPart / (LONGLONG)1000000);
125         return ret;
126 }
127
128
129 /*
130  * Windows version of firewall hook. We receive a partial copy of
131  * the packet which points to the original buffers. In output,
132  * the refcount has been already incremented.
133  * The function reconstructs
134  * the whole packet in a contiguous memory area, builds a fake mbuf,
135  * calls the firewall, does the eventual cleaning and returns
136  * to MiniportSend or ProtocolReceive, which will silently return
137  * (dropping packet) or continue its execution (allowing packet).
138  * The memory area contains:
139  * - the fake mbuf, filled with data needed by ipfw, and information
140  *   for reinjection
141  * - the packet data
142  */
143 void hexdump(PUCHAR,int, const char *);
144 static char _if_in[] = "incoming";
145 static char _if_out[] = "outgoing";
146
147 int
148 ipfw2_qhandler_w32(PNDIS_PACKET pNdisPacket, int direction,
149         NDIS_HANDLE Context)
150 {       
151         unsigned int            BufferCount = 0;
152         unsigned                        TotalPacketLength = 0;
153         PNDIS_BUFFER            pCurrentBuffer = NULL;
154         PNDIS_BUFFER            pNextBuffer = NULL;
155         struct mbuf*            m;
156         unsigned char*          payload = NULL;
157         unsigned int            ofs, l;
158         unsigned short          EtherType = 0;
159         unsigned int            i = 0;
160         int                                     ret = 0;
161         PNDIS_BUFFER            pNdisBuffer, old_head, old_tail;
162         NDIS_HANDLE                     PacketPool;
163         PADAPT                          pAdapt;
164         NDIS_STATUS                     Status;
165
166         /* In NDIS, packets are a chain of NDIS_BUFFER. We query
167          * the packet to get a pointer of chain's head, the length
168          * of the chain, and the length of the packet itself.
169          * Then allocate a buffer for the mbuf and the payload.
170          */
171         NdisQueryPacket(pNdisPacket, NULL, &BufferCount,
172                 &pCurrentBuffer, &TotalPacketLength);
173         m = malloc(sizeof(struct mbuf) + TotalPacketLength, 0, 0 );
174         if (m == NULL) //resource shortage, drop the packet
175                 goto drop_pkt;
176
177         /* set mbuf fields to point past the MAC header.
178          * Also set additional W32 info
179          */
180         payload = (unsigned char*)(m + 1);
181         m->m_len = m->m_pkthdr.len = TotalPacketLength-14;
182         m->m_pkthdr.rcvif = (void *)((direction==INCOMING) ? _if_in : NULL);
183         m->m_data = payload + 14; /* past the MAC header */
184         m->direction = direction;
185         m->context = Context;
186         m->pkt = pNdisPacket;
187
188         /* m_skb != NULL is used in the ip_output routine to check
189          * for packets that come from the stack and differentiate
190          * from those internally generated by ipfw.
191          * The pointer is not used, just needs to be non-null.
192          */
193         m->m_skb = (void *)pNdisPacket;
194         /*
195          * Now copy the data from the Windows buffers to the mbuf.
196          */
197         for (i=0, ofs = 0; i < BufferCount; i++) {
198                 unsigned char* src;
199                 NdisQueryBufferSafe(pCurrentBuffer, &src, &l,
200                         NormalPagePriority);
201                 bcopy(src, payload + ofs, l);
202                 ofs += l;
203                 NdisGetNextBuffer(pCurrentBuffer, &pNextBuffer);
204                 pCurrentBuffer = pNextBuffer;
205         }
206         /*
207          * Identify EtherType. If the packet is not IP, simply allow
208          * and don't bother the firewall. XXX should be done before.
209          */
210         EtherType = *(unsigned short*)(payload + 12);
211         EtherType = RtlUshortByteSwap(EtherType);
212         if (EtherType != 0x0800) {
213                 //DbgPrint("ethertype = %X, skipping ipfw\n",EtherType);
214                 free(m, 0);
215                 return PASS;
216         }
217
218         /*
219          * Now build a buffer descriptor to replace the original chain.
220          */
221         pAdapt = Context;
222         PacketPool = direction == OUTGOING ?
223                 pAdapt->SendPacketPoolHandle : pAdapt->RecvPacketPoolHandle;
224         NdisAllocateBuffer(&Status, &pNdisBuffer,
225                 PacketPool, payload, m->m_pkthdr.len+14);
226         if (Status != NDIS_STATUS_SUCCESS)
227                 goto drop_pkt;
228         /*
229          * Save the old buffer pointers, and put the new one
230          * into the chain.
231          */
232         pNdisBuffer->Next = NULL;
233         old_head = NDIS_PACKET_FIRST_NDIS_BUFFER(pNdisPacket);
234         old_tail = NDIS_PACKET_LAST_NDIS_BUFFER(pNdisPacket);
235         NdisReinitializePacket(pNdisPacket);
236         NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
237 #if 0
238         if (direction == INCOMING) {
239                 DBGPRINT(("incoming: proto %u (%s), src %08X, dst %08X, sport %u, dport %u, len %u\n", *(payload+14+9), texify_proto(*(payload+14+9)), *(unsigned int*)(payload+14+12), *(unsigned int*)(payload+14+16), ntohs((*((unsigned short int*)(payload+14+20)))), ntohs((*((unsigned short int*)(payload+14+22)))), TotalPacketLength));
240         } else {
241                 DBGPRINT(("outgoing: proto %u (%s), src %08X, dst %08X, sport %u, dport %u, len %u\n", *(payload+14+9), texify_proto(*(payload+14+9)), *(unsigned int*)(payload+14+12), *(unsigned int*)(payload+14+16), ntohs((*((unsigned short int*)(payload+14+20)))), ntohs((*((unsigned short int*)(payload+14+22)))), TotalPacketLength));
242         }
243 #endif
244         if (direction == INCOMING)
245                 ret = ipfw_check_hook(NULL, &m, NULL, PFIL_IN, NULL);
246         else
247                 ret = ipfw_check_hook(NULL, &m, (struct ifnet*)_if_out, PFIL_OUT, NULL);
248
249         if (m != NULL) {
250                 /* Accept. Restore the old buffer chain, free
251                  * the mbuf and return PASS.
252                  */
253                 //DBGPRINT(("accepted\n"));
254                 NdisReinitializePacket(pNdisPacket);
255                 NDIS_PACKET_FIRST_NDIS_BUFFER(pNdisPacket) = old_head;
256                 NDIS_PACKET_LAST_NDIS_BUFFER(pNdisPacket) = old_tail;
257                 NdisFreeBuffer(pNdisBuffer);
258                 m_freem(m);
259                 return PASS;
260         } else if (ret == 0) {
261                 /* dummynet has kept the packet, will reinject later. */
262                 //DBGPRINT(("kept by dummynet\n"));
263                 return DUMMYNET;
264         } else {
265                 /*
266                  * Packet dropped by ipfw or dummynet. Nothing to do as
267                  * FREE_PKT already freed the fake mbuf
268                  */
269                 //DBGPRINT(("dropped by dummynet, ret = %i\n", ret));
270                 return DROP;
271         }
272 drop_pkt:
273         /* for some reason we cannot proceed. Free any resources
274          * including those received from above, and return
275          * faking success. XXX this must be fixed later.
276          */
277         NdisFreePacket(pNdisPacket);
278         return DROP;
279 }
280
281 /*
282  * Windows reinjection function.
283  * The packet is already available as m->pkt, so we only
284  * need to send it to the right place.
285  * Normally a ndis intermediate driver allocates
286  * a fresh descriptor, while the actual data's ownership is
287  * retained by the protocol, or the miniport below.
288  * Since an intermediate driver behaves as a miniport driver
289  * at the upper edge (towards the protocol), and as a protocol
290  * driver at the lower edge (towards the NIC), when we handle a
291  * packet we have a reserved area in both directions (we can use
292  * only one for each direction at our own discretion).
293  * Normally this area is used to save a pointer to the original
294  * packet, so when the driver is done with it, the original descriptor
295  * can be retrieved, and the resources freed (packet descriptor,
296  * buffer descriptor(s) and the actual data). In our driver this
297  * area is used to mark the reinjected packets as 'orphan', because
298  * the original descriptor is gone long ago. This way we can handle
299  * correctly the resource freeing when the callback function
300  * is called by NDIS.
301  */
302
303 void 
304 netisr_dispatch(int num, struct mbuf *m)
305 {
306         unsigned char*          payload = (unsigned char*)(m+1);
307         PADAPT                          pAdapt = m->context;
308         NDIS_STATUS                     Status;
309         PNDIS_PACKET            pPacket = m->pkt;
310         PNDIS_BUFFER            pNdisBuffer;
311         NDIS_HANDLE                     PacketPool;
312
313         if (num < 0)
314                 goto drop_pkt;
315
316         //debug print
317 #if 0
318         DbgPrint("reinject %s\n", m->direction == OUTGOING ?
319                 "outgoing" : "incoming");
320 #endif
321         NdisAcquireSpinLock(&pAdapt->Lock);
322         if (m->direction == OUTGOING) {
323                 //we must first check if the adapter is going down,
324                 // in this case abort the reinjection
325                 if (pAdapt->PTDeviceState > NdisDeviceStateD0) {
326                         pAdapt->OutstandingSends--;
327                         // XXX should we notify up ?
328                         NdisReleaseSpinLock(&pAdapt->Lock);
329                         goto drop_pkt;
330                 }
331         } else {
332                 /* if the upper miniport edge is not initialized or
333                  * the miniport edge is in low power state, abort
334                  * XXX we should notify the error.
335                  */
336                 if (!pAdapt->MiniportHandle ||
337                     pAdapt->MPDeviceState > NdisDeviceStateD0) {
338                         NdisReleaseSpinLock(&pAdapt->Lock);
339                         goto drop_pkt;
340                 }
341         }
342         NdisReleaseSpinLock(&pAdapt->Lock);
343
344         if (m->direction == OUTGOING) {
345                 PSEND_RSVD      SendRsvd;
346                 /* use the 8-bytes protocol reserved area, the first
347                  * field is used to mark/the packet as 'orphan', the
348                  * second stores the pointer to the mbuf, so in the
349                  * the SendComplete handler we know that this is a
350                  * reinjected packet and can free correctly.
351                  */
352                 SendRsvd = (PSEND_RSVD)(pPacket->ProtocolReserved);
353                 SendRsvd->OriginalPkt = NULL;
354                 SendRsvd->pMbuf = m;
355                 //do the actual send
356                 NdisSend(&Status, pAdapt->BindingHandle, pPacket);
357                 if (Status != NDIS_STATUS_PENDING) {
358                         /* done, call the callback now */
359                         PtSendComplete(m->context, m->pkt, Status);
360                 }
361                 return; /* unconditional return here. */
362         } else {
363                 /* There's no need to check the 8-bytes miniport 
364                  * reserved area since the path going up will be always
365                  * syncronous, and all the cleanup will be done inline.
366                  * If the reinjected packed comes from a PtReceivePacket, 
367                  * there will be no callback.
368                  * Otherwise PtReceiveComplete will be called but will just
369                  * return since all the cleaning is alreqady done */
370                 // do the actual receive. 
371                 ULONG Proc = KeGetCurrentProcessorNumber();
372                 pAdapt->ReceivedIndicationFlags[Proc] = TRUE;
373                 NdisMEthIndicateReceive(pAdapt->MiniportHandle, NULL, payload, 14, payload+14, m->m_len, m->m_len);
374                 NdisMEthIndicateReceiveComplete(pAdapt->MiniportHandle);
375                 pAdapt->ReceivedIndicationFlags[Proc] = FALSE;
376         }
377 drop_pkt:
378         /* NDIS_PACKET exists and must be freed only if
379          * the packet come from a PtReceivePacket, oherwise
380          * m->pkt will ne null.
381          */
382         if (m->pkt != NULL)
383         {
384                 NdisUnchainBufferAtFront(m->pkt, &pNdisBuffer);
385                 NdisFreeBuffer(pNdisBuffer);
386                 NdisFreePacket(m->pkt);
387         }
388         m_freem(m);
389 }
390
391 void win_freem(void *); /* wrapper for m_freem() for protocol.c */
392 void
393 win_freem(void *_m)
394 {
395         struct mbuf *m = _m;
396         m_freem(m);
397 }
398
399 /*
400  * not implemented in linux.
401  * taken from /usr/src/lib/libc/string/strlcpy.c
402  */
403 size_t
404 strlcpy(char *dst, const char *src, size_t siz)
405 {
406         char *d = dst;
407         const char *s = src;
408         size_t n = siz;
409  
410         /* Copy as many bytes as will fit */
411         if (n != 0 && --n != 0) {
412                 do {
413                         if ((*d++ = *s++) == 0)
414                                 break;
415                 } while (--n != 0);
416         }
417
418         /* Not enough room in dst, add NUL and traverse rest of src */
419         if (n == 0) {
420                 if (siz != 0)
421                         *d = '\0';              /* NUL-terminate dst */
422                 while (*s++)
423                         ;
424         }
425
426         return(s - src - 1);    /* count does not include NUL */
427 }
428
429 void CleanupReinjected(PNDIS_PACKET Packet, struct mbuf* m, PADAPT pAdapt)
430 {
431         PNDIS_BUFFER pNdisBuffer;
432
433         NdisQueryPacket(Packet, NULL, NULL, &pNdisBuffer, NULL);
434         NdisUnchainBufferAtFront(Packet, &pNdisBuffer);
435         NdisFreeBuffer(pNdisBuffer);
436         win_freem(m);
437         NdisFreePacket(Packet);
438         ADAPT_DECR_PENDING_SENDS(pAdapt);
439 }
440
441 int
442 ipfw2_qhandler_w32_oldstyle(int direction,
443         NDIS_HANDLE         ProtocolBindingContext,
444     unsigned char*      HeaderBuffer,
445     unsigned int        HeaderBufferSize,
446     unsigned char*      LookAheadBuffer,
447     unsigned int        LookAheadBufferSize,
448     unsigned int        PacketSize)
449 {
450         struct mbuf* m;
451         unsigned char*          payload = NULL;
452         unsigned short          EtherType = 0;
453         int                                     ret = 0;
454         
455         /* We are in a special case when NIC signals an incoming
456          * packet using old style calls. This is done passing
457          * a pointer to the MAC header and a pointer to the
458          * rest of the packet.
459          * We simply allocate space for the mbuf and the
460          * subsequent payload section.
461          */
462         m = malloc(sizeof(struct mbuf) + HeaderBufferSize + LookAheadBufferSize, 0, 0 );
463         if (m == NULL) //resource shortage, drop the packet
464                 return DROP;
465         
466         /* set mbuf fields to point past the MAC header.
467          * Also set additional W32 info.
468          * m->pkt here is set to null because the notification
469          * from the NIC has come with a header+loolahead buffer,
470          * no NDIS_PACKET has been provided.
471          */
472         payload = (unsigned char*)(m + 1);
473         m->m_len = m->m_pkthdr.len = HeaderBufferSize+LookAheadBufferSize-14;
474         m->m_data = payload + 14; /* past the MAC header */
475         m->direction = direction;
476         m->context = ProtocolBindingContext;
477         m->pkt = NULL;
478         
479         /*
480          * Now copy the data from the Windows buffers to the mbuf.
481          */
482         bcopy(HeaderBuffer, payload, HeaderBufferSize);
483         bcopy(LookAheadBuffer, payload+HeaderBufferSize, LookAheadBufferSize);
484         //hexdump(payload,HeaderBufferSize+LookAheadBufferSize,"qhandler");
485         /*
486          * Identify EtherType. If the packet is not IP, simply allow
487          * and don't bother the firewall. XXX should be done before.
488          */
489         EtherType = *(unsigned short*)(payload + 12);
490         EtherType = RtlUshortByteSwap(EtherType);
491         if (EtherType != 0x0800) {
492                 //DbgPrint("ethertype = %X, skipping ipfw\n",EtherType);
493                 free(m, 0);
494                 return PASS;
495         }
496
497         //DbgPrint("incoming_raw: proto %u (%s), src %08X, dst %08X, sport %u, dport %u, len %u\n", *(payload+14+9), texify_proto(*(payload+14+9)), *(unsigned int*)(payload+14+12), *(unsigned int*)(payload+14+16), ntohs((*((unsigned short int*)(payload+14+20)))), ntohs((*((unsigned short int*)(payload+14+22)))), HeaderBufferSize+LookAheadBufferSize);
498         
499         /* Query the firewall */
500         ret = ipfw_check_hook(NULL, &m, NULL, PFIL_IN, NULL);
501
502         if (m != NULL) {
503                 /* Accept. Free the mbuf and return PASS. */
504                 //DbgPrint("accepted\n");
505                 m_freem(m);
506                 return PASS;
507         } else if (ret == 0) {
508                 /* dummynet has kept the packet, will reinject later. */
509                 //DbgPrint("kept by dummynet\n");
510                 return DUMMYNET;
511         } else {
512                 /*
513                  * Packet dropped by ipfw or dummynet. Nothing to do as
514                  * FREE_PKT already freed the fake mbuf
515                  */
516                 //DbgPrint("dropped by dummynet, ret = %i\n", ret);
517                 return DROP;
518         }
519 }
520
521 /* forward declaration because those functions are used only here,
522  * no point to make them visible in passthru/protocol/miniport */
523 int do_ipfw_set_ctl(struct sock *sk, int cmd,
524         void __user *user, unsigned int len);
525 int do_ipfw_get_ctl(struct sock *sk, int cmd,
526         void __user *user, int *len);
527
528 NTSTATUS
529 DevIoControl(
530     IN PDEVICE_OBJECT    pDeviceObject,
531     IN PIRP              pIrp
532     )
533 /*++
534
535 Routine Description:
536
537     This is the dispatch routine for handling device ioctl requests.
538
539 Arguments:
540
541     pDeviceObject - Pointer to the device object.
542
543     pIrp - Pointer to the request packet.
544
545 Return Value:
546
547     Status is returned.
548
549 --*/
550 {
551     PIO_STACK_LOCATION  pIrpSp;
552     NTSTATUS            NtStatus = STATUS_SUCCESS;
553     unsigned long       BytesReturned = 0;
554     unsigned long       FunctionCode;
555     unsigned long       len;
556     struct sockopt              *sopt;
557     int                                 ret = 0;
558     
559     UNREFERENCED_PARAMETER(pDeviceObject);
560     
561     pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
562     
563     /*
564      * Using METHOD_BUFFERED as communication method, the userland
565      * side calls DeviceIoControl passing an input buffer and an output
566      * and their respective length (ipfw uses the same length for both).
567      * The system creates a single I/O buffer, with len=max(inlen,outlen).
568      * In the kernel we can read information from this buffer (which is
569      * directly accessible), overwrite it with our results, and set
570      * IoStatus.Information with the number of bytes that the system must
571      * copy back to userland.
572      * In our sockopt emulation, the initial part of the buffer contains
573      * a struct sockopt, followed by the data area.
574      */
575
576     len = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
577     if (len < sizeof(struct sockopt))
578     {
579         return STATUS_NOT_SUPPORTED; // XXX find better value
580     }
581     sopt = pIrp->AssociatedIrp.SystemBuffer;
582
583     FunctionCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
584
585     len = sopt->sopt_valsize;
586
587     switch (FunctionCode)
588     {
589                 case IP_FW_SETSOCKOPT:
590                         ret = do_ipfw_set_ctl(NULL, sopt->sopt_name, sopt+1, len);
591                         break;
592                         
593                 case IP_FW_GETSOCKOPT:
594                         ret = do_ipfw_get_ctl(NULL, sopt->sopt_name, sopt+1, &len);
595                         sopt->sopt_valsize = len;
596                         //sanity check on len
597                         if (len + sizeof(struct sockopt) <= pIrpSp->Parameters.DeviceIoControl.InputBufferLength)
598                                 BytesReturned = len + sizeof(struct sockopt);
599                         else
600                                 BytesReturned = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
601                         break;
602
603                 default:
604                                 NtStatus = STATUS_NOT_SUPPORTED;
605                                 break;
606     }
607     
608     pIrp->IoStatus.Information = BytesReturned;
609     pIrp->IoStatus.Status = NtStatus;
610     IoCompleteRequest(pIrp, IO_NO_INCREMENT);
611
612     return NtStatus;
613
614
615 void dummynet(void * unused);
616 void ipfw_tick(void * vnetx);
617
618 VOID dummynet_dpc(
619     __in struct _KDPC  *Dpc,
620     __in_opt PVOID  DeferredContext,
621     __in_opt PVOID  SystemArgument1,
622     __in_opt PVOID  SystemArgument2
623     )
624 {
625         dummynet(NULL);
626 }
627
628 VOID ipfw_dpc(
629     __in struct _KDPC  *Dpc,
630     __in_opt PVOID  DeferredContext,
631     __in_opt PVOID  SystemArgument1,
632     __in_opt PVOID  SystemArgument2
633     )
634 {
635         ipfw_tick(DeferredContext);
636 }