simple examples of how to

Wednesday, October 28, 2009

awk isnum function

function isnum(n) {return n ~ /^[+-]?[0-9]+$/}

how about

function isnum(n) { return n ~ /^[+-]?[0-9]+\.?[0-9]*$/ }

Sunday, October 25, 2009

pipe in linux (from somewhere in the internet...)

Pipes are commonly used for interprocess communication. But the major disadvantage of pipes is that they can be used only by one process (there are readers and writers within the same process) or the processes which share the same file descriptor table (normally the processes and the child processes or threads created by them). Thus pipes have this big limitation: they cannot pass information between unrelated processes. This is because they do not share the same file descriptor table. But if names are given to the pipes, then one would be able to read or write data to them just like a normal file. The processes need not even share anything with each otherFIFO (First In First Out) are also called named pipes. The main features of FIFO are
1. It implements FIFO feature of the pipes
2. They can be opened just like normal files using their names
3. Data can be read from or written to the fifo

Working with FIFO in a Shell
Creating a FIFO

mkfifo

creates fifo- the named pipes

Syntax

mkfifo [options] fifo_name

Example

$ mkfifo fifo

There is one more way by which we can FIFO using mknod. mknod is used to create block or character special files.

$ mknod [OPTION]... NAME TYPE

To create a FIFO fifo1

$ mknod fifo1 p

where p coressponds to file type : pipe (remember FIFO is a named pipe).

Reading/ Writing data from/to a FIFO
Let’s open two terminals
In the first terminal

$ cat > fifo

we are experimenting with the FIFOThis is second line. After opening the fifo in the second terminal for readingusing cat, you will notice the above two lines displayed there.
Now open the second terminal and go to the directory containing the FIFO ‘fifo’

$ cat fifo

we are experimenting with the FIFOThis is second line. After opening the fifo in the second terminal for reading
Now keep on writing to the first terminal. You will notice that every time you press enter, the coressponding line appears in the second terminal.

Pressing CTRL+D in the first terminal terminates writing to the fifo. This also terminates the second process because reading from the fifo now generates a “BROKEN PIPE” signal. The default action for this is to terminate the process.

Let us now see the details of the file ‘fifo’

$ ls -l fifo
prw-r--r-- 1 user user 0 Feb 14 10:05 fifo

The p in the beginning denotes that it is a pipe.

Let’s see more details about the pipe using stat

$ stat fifo
File: `fifo'Size: 0 Blocks: 0 IO Block: 4096 fifo
Device: fd00h/64768d Inode: 1145493 Links: 1
Access: (0644/prw-r--r--) Uid: ( 0/ user) Gid: ( 0/ user)
Access: 2008-02-14 10:05:49.000000000 +0530
Modify: 2008-02-14 10:05:49.000000000 +0530
Change: 2008-02-14 10:05:49.000000000 +0530

If you notice carefully, FIFOs just like a normal file possess all the details like inode number, the number of links to it, the access, modification times, size and the access permissions.

As in the case of pipes, there can be multiple readers and writers to a pipe. Try opening multiple terminals to read from and write to a pipe.

For more updates, check Programming Insights.

Saturday, October 17, 2009

madwifi patches

1. add in-kernel-network-monitoring
2. add "report buffer full" from ieee80211_output to network kernel
3. buffer size control
4. 802.11e enabled with adhoc mode
5. worse than useless ttl-based packet filtering (beyond crap) who would use this?

the following

diff -Nru madwifi-original/ath/if_ath.c madwifi-new/ath/if_ath.c
--- madwifi-original/ath/if_ath.c 2009-10-05 17:25:39.000000000 +0200
+++ madwifi-new/ath/if_ath.c 2009-10-15 12:38:40.000000000 +0200
@@ -467,6 +467,8 @@
MODULE_PARM_DESC(ratectl, "Rate control algorithm [amrr|minstrel|onoe|sample], "
"defaults to '" DEF_RATE_CTL "'");

+static int iknm_portnum=30010;
+
#ifdef AR_DEBUG
static int ath_debug = 0;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52))
@@ -563,6 +565,213 @@
return f;
}

+/* jyyoo (jaeyong): in-kernel-network-monitoring */
+int thread_deliver_ath_hardstart(void* data)
+{
+ struct ath_softc* sc = (struct ath_softc*)data;
+
+ init_waitqueue_head(&sc->sc_queue_send);
+
+ sc->sc_kthread_send_alive = 1;
+ while( sc->sc_kthread_send_alive )
+ {
+ int ret;
+ int h, t;
+ int total_info;
+ int total_packet;
+ int debug_cnt=0;
+
+ mm_segment_t oldmm;
+
+ h = sc->sc_monitor_head;
+ t = sc->sc_monitor_tail;
+
+ if( h < t ) h += MAX_MPARAM;
+
+ total_info = h-t;
+
+ total_packet = total_info / MAX_MPARAM_PERPACKET;
+ if( total_info % MAX_MPARAM_PERPACKET ) total_packet += 1;
+
+ while( h != t )
+ {
+ debug_cnt ++;
+ if( debug_cnt > 30 ) {
+ printk("critical loop detected!!!\n");
+ break;
+ }
+ /* first determine iov_base */
+ sc->sc_iov_msg.iov_base = (char*)&sc->sc_monitor_param[t];
+
+ /* and then determine iov_len */
+ if( sc->sc_monitor_head > sc->sc_monitor_tail )
+ {
+ if( (h - t) > MAX_MPARAM_PERPACKET )
+ {
+ sc->sc_iov_msg.iov_len = MAX_MPARAM_PERPACKET * sizeof(struct monitor_param);
+ t+=MAX_MPARAM_PERPACKET;
+ }
+ else
+ {
+ sc->sc_iov_msg.iov_len = (h-t)*sizeof(struct monitor_param);
+ t = h;
+ }
+ }
+ else
+ {
+ int pre_t=t;
+ if( (h - t) > MAX_MPARAM_PERPACKET )
+ {
+ pre_t+=MAX_MPARAM_PERPACKET;
+ }
+ else
+ {
+ pre_t = h;
+ }
+
+ if( pre_t >= MAX_MPARAM )
+ {
+ sc->sc_iov_msg.iov_len = (MAX_MPARAM - t) * sizeof(struct monitor_param);
+ t = 0;
+ h -= MAX_MPARAM;
+ }
+ else
+ {
+ if( (h - t) > MAX_MPARAM_PERPACKET )
+ {
+ sc->sc_iov_msg.iov_len = MAX_MPARAM_PERPACKET * sizeof(struct monitor_param);
+ t+=MAX_MPARAM_PERPACKET;
+ }
+ else
+ {
+ sc->sc_iov_msg.iov_len = (h-t)*sizeof(struct monitor_param);
+ t = h;
+ }
+
+ }
+ }
+
+ oldmm = get_fs();
+ set_fs(KERNEL_DS);
+ if( (ret = sock_sendmsg( sc->sc_sock_mclient, &sc->sc_msghdr, sc->sc_iov_msg.iov_len )) < 0 )
+ {
+ printk("IKNM: send error: %d\n", ret);
+ }
+ set_fs(oldmm);
+ }
+ sc->sc_monitor_tail = h;
+ if( sc->sc_iknm_enable )
+ interruptible_sleep_on_timeout(&sc->sc_queue_send, HZ/20);
+ else
+ interruptible_sleep_on_timeout(&sc->sc_queue_send, HZ);
+ }
+ complete_and_exit(NULL, 0);
+ return 0;
+}
+/* jyyoo (jaeyong): in-kernel-network-monitoring */
+int thread_deliver_rx_tasklet(void* data)
+{
+ struct ath_softc* sc = (struct ath_softc*)data;
+
+ init_waitqueue_head(&sc->sc_recv_queue_send);
+
+ sc->sc_recv_kthread_send_alive = 1;
+ while( sc->sc_recv_kthread_send_alive )
+ {
+ int ret;
+ int h, t;
+ int total_info;
+ int total_packet;
+ int debug_cnt=0;
+
+ mm_segment_t oldmm;
+
+ h = sc->sc_recv_monitor_head;
+ t = sc->sc_recv_monitor_tail;
+
+ if( h < t ) h += MAX_MPARAM;
+
+ total_info = h-t;
+
+ total_packet = total_info / MAX_MPARAM_PERPACKET;
+ if( total_info % MAX_MPARAM_PERPACKET ) total_packet += 1;
+
+ while( h != t )
+ {
+ debug_cnt ++;
+ if( debug_cnt > 30 ) {
+ printk("critical loop detected!!!\n");
+ break;
+ }
+ /* first determine iov_base */
+ sc->sc_recv_iov_msg.iov_base = (char*)&sc->sc_recv_monitor_param[t];
+
+ /* and then determine iov_len */
+ if( sc->sc_recv_monitor_head > sc->sc_recv_monitor_tail )
+ {
+ if( (h - t) > MAX_MPARAM_PERPACKET )
+ {
+ sc->sc_recv_iov_msg.iov_len = MAX_MPARAM_PERPACKET * sizeof(struct monitor_param_recv);
+
+ t+=MAX_MPARAM_PERPACKET;
+ }
+ else
+ {
+ sc->sc_recv_iov_msg.iov_len = (h-t)*sizeof(struct monitor_param_recv);
+ t = h;
+ }
+ }
+ else
+ {
+ int pre_t=t;
+ if( (h - t) > MAX_MPARAM_PERPACKET )
+ {
+ pre_t+=MAX_MPARAM_PERPACKET;
+ }
+ else
+ {
+ pre_t = h;
+ }
+
+ if( pre_t >= MAX_MPARAM )
+ {
+ sc->sc_recv_iov_msg.iov_len = (MAX_MPARAM - t) * sizeof(struct monitor_param_recv);
+ t = 0;
+ h -= MAX_MPARAM;
+ }
+ else
+ {
+ if( (h - t) > MAX_MPARAM_PERPACKET )
+ {
+ sc->sc_recv_iov_msg.iov_len = MAX_MPARAM_PERPACKET * sizeof(struct monitor_param_recv);
+ t+=MAX_MPARAM_PERPACKET;
+ }
+ else
+ {
+ sc->sc_recv_iov_msg.iov_len = (h-t)*sizeof(struct monitor_param_recv);
+ t = h;
+ }
+ }
+ }
+ oldmm = get_fs();
+ set_fs(KERNEL_DS);
+ if( (ret = sock_sendmsg( sc->sc_recv_sock_mclient, &sc->sc_recv_msghdr, sc->sc_recv_iov_msg.iov_len )) < 0 )
+ {
+ printk("IKNM: send error: %d\n", ret);
+ }
+ set_fs(oldmm);
+ }
+ sc->sc_recv_monitor_tail = h;
+ if( sc->sc_iknm_enable )
+ interruptible_sleep_on_timeout(&sc->sc_recv_queue_send, HZ/2);
+ else
+ interruptible_sleep_on_timeout(&sc->sc_recv_queue_send, HZ);
+ }
+ complete_and_exit(NULL, 0);
+ return 0;
+}
+
+
/* Initialize ath_softc structure */

int
@@ -587,6 +796,10 @@

sc->sc_hwinfo = &generic_hw_info;

+ /* jyyoo add marker */
+ printk("jyyoo marker v.0.1.2\n");
+ ic->ic_enable_ttl_pf = 0;
+ ic->ic_adhoc_edca = 0;
/* Allocate space for dynamically determined maximum VAP count */
sc->sc_bslot =
kmalloc(ath_maxvaps * sizeof(struct ieee80211vap*), GFP_KERNEL);
@@ -1187,6 +1400,168 @@
sc->sc_noise_immunity = -1;
sc->sc_ofdm_weak_det = -1;

+ /* jyyoo (jaeyong): in-kernel-network-monitoring */
+
+ sc->sc_iknm_enable = 1;
+
+ /* just for the heads up */
+ printk("sizeof(struct timeval)=%d\n", sizeof(struct timeval));
+
+ /* default port number: 30001 */
+ sc->sc_port_number = 30001;
+ sc->sc_serv_addr.sin_family = AF_INET;
+ /* default monitor server ip address: 172.17.255.254 (panther) */
+ sc->sc_serv_addr.sin_addr.s_addr = (in_aton("172.17.255.254"));
+ sc->sc_serv_addr.sin_port = htons(sc->sc_port_number);
+
+ sc->sc_serv_addr2.sin_family = AF_INET;
+ sc->sc_serv_addr2.sin_addr.s_addr = htonl(INADDR_ANY);
+ sc->sc_serv_addr2.sin_port = htons(iknm_portnum++);
+ spin_lock_init(&sc->sc_send_lock);
+ sc->sc_monitor_head = 0;
+ sc->sc_monitor_tail = 0;
+ sc->dp_exchange_buffer_drop = 0;
+
+ if( sock_create(AF_INET, SOCK_DGRAM, 0, &sc->sc_sock_mclient) < 0 )
+ {
+ printk("IKNM: Error creating socket\n");
+ sc->sc_sock_mclient = NULL;
+ }
+ else
+ {
+
+ int i;
+ int ret;
+ mm_segment_t oldmm;
+
+ if( sc->sc_sock_mclient->ops->bind( sc->sc_sock_mclient,
+ (struct sockaddr*)&sc->sc_serv_addr2,
+ sizeof(sc->sc_serv_addr2) ) < 0 )
+ {
+ printk("IKNM: Error bind failed\n");
+
+ }
+ else
+ {
+
+ printk("IKNM: socket initiation succeeded; port %d addr: 172.17.255.254\n", sc->sc_port_number);
+
+ for( i=0; i<1024; i++ )
+ sc->sc_msgbuf[i] = i;
+
+
+ sc->sc_msghdr.msg_name = (struct sockaddr*)&sc->sc_serv_addr;
+ sc->sc_msghdr.msg_namelen = sizeof(sc->sc_serv_addr);
+ sc->sc_msghdr.msg_iov = &sc->sc_iov_msg;
+ sc->sc_msghdr.msg_iovlen = 1;
+ sc->sc_msghdr.msg_control = NULL;
+ sc->sc_msghdr.msg_controllen = 0;
+ sc->sc_msghdr.msg_flags = 0;
+
+ sc->sc_iov_msg.iov_base = sc->sc_msgbuf;
+ sc->sc_iov_msg.iov_len = 1024;
+
+ oldmm = get_fs();
+ set_fs(KERNEL_DS);
+
+
+ if( (ret = sock_sendmsg( sc->sc_sock_mclient, &sc->sc_msghdr, sc->sc_iov_msg.iov_len )) < 0 )
+ {
+ printk("IKNM: first send error: %d\n", ret);
+ }
+ else
+ {
+ printk("IKNM: first send succeeded %d\n", ret);
+ }
+
+ set_fs(oldmm);
+ }
+
+ }
+
+ sc->sc_kthread_send_alive = 0;
+
+ sc->sc_kthread_send = kthread_create( thread_deliver_ath_hardstart, sc, "iknm_MAC_monitor" );
+ wake_up_process(sc->sc_kthread_send);
+
+ /* default port number: 30001 */
+ sc->sc_recv_port_number = 30003;
+ sc->sc_recv_serv_addr.sin_family = AF_INET;
+ /* default monitor server ip address: 172.17.255.254 (panther) */
+ sc->sc_recv_serv_addr.sin_addr.s_addr = (in_aton("172.17.255.254"));
+ sc->sc_recv_serv_addr.sin_port = htons(sc->sc_recv_port_number);
+
+ sc->sc_recv_serv_addr2.sin_family = AF_INET;
+ sc->sc_recv_serv_addr2.sin_addr.s_addr = htonl(INADDR_ANY);
+ sc->sc_recv_serv_addr2.sin_port = htons(iknm_portnum++);
+ spin_lock_init(&sc->sc_recv_send_lock);
+ sc->sc_recv_monitor_head = 0;
+ sc->sc_recv_monitor_tail = 0;
+ sc->dp_exchange_buffer_drop = 0;
+
+ if( sock_create(AF_INET, SOCK_DGRAM, 0, &sc->sc_recv_sock_mclient) < 0 )
+ {
+ printk("IKNM: Error creating socket\n");
+ sc->sc_recv_sock_mclient = NULL;
+ }
+ else
+ {
+
+ int i;
+ int ret;
+ mm_segment_t oldmm;
+
+ if( sc->sc_recv_sock_mclient->ops->bind( sc->sc_recv_sock_mclient,
+ (struct sockaddr*)&sc->sc_recv_serv_addr2,
+ sizeof(sc->sc_recv_serv_addr2) ) < 0 )
+ {
+ printk("IKNM: Error bind failed\n");
+
+ }
+ else
+ {
+
+ printk("IKNM: socket initiation succeeded; port %d addr: 172.17.255.254 (monitor_param size:%d)\n", sc->sc_recv_port_number, sizeof(struct monitor_param_recv));
+
+ for( i=0; i<1024; i++ )
+ sc->sc_recv_msgbuf[i] = i;
+ sc->sc_recv_msghdr.msg_name = (struct sockaddr*)&sc->sc_recv_serv_addr;
+ sc->sc_recv_msghdr.msg_namelen = sizeof(sc->sc_recv_serv_addr);
+ sc->sc_recv_msghdr.msg_iov = &sc->sc_recv_iov_msg;
+ sc->sc_recv_msghdr.msg_iovlen = 1;
+ sc->sc_recv_msghdr.msg_control = NULL;
+ sc->sc_recv_msghdr.msg_controllen = 0;
+ sc->sc_recv_msghdr.msg_flags = 0;
+
+ sc->sc_recv_iov_msg.iov_base = sc->sc_recv_msgbuf;
+ sc->sc_recv_iov_msg.iov_len = 1024;
+
+ oldmm = get_fs();
+ set_fs(KERNEL_DS);
+
+
+ if( (ret = sock_sendmsg( sc->sc_recv_sock_mclient, &sc->sc_recv_msghdr, sc->sc_recv_iov_msg.iov_len )) < 0 )
+ {
+ printk("IKNM: first send error: %d\n", ret);
+ }
+ else
+ {
+ printk("IKNM: first send succeeded %d\n", ret);
+ }
+
+ set_fs(oldmm);
+ }
+
+ }
+
+ sc->sc_recv_kthread_send_alive = 0;
+
+ sc->sc_recv_kthread_send = kthread_create( thread_deliver_rx_tasklet, sc, "recv-iknm_MAC_monitor" );
+ wake_up_process(sc->sc_recv_kthread_send);
+
+
+ sc->sc_queue_len = TAIL_DROP_COUNT;
+
return 0;
bad3:
ieee80211_ifdetach(ic);
@@ -3507,6 +3882,9 @@
STAILQ_INIT(&bf_head);

if (SKB_CB(skb)->flags & M_RAW) {
+#ifdef JYD_FUNCTION_CALL_FREQUENCY
+ sc->sc_stats.ast_jyd_ath_hardstart_raw ++;
+#endif
bf = ath_take_txbuf(sc);
if (bf == NULL) {
/* All DMA buffers full, safe to try again. */
@@ -3543,9 +3921,12 @@
ATH_FF_MAGIC_CLR(skb);
an = ATH_NODE(ni);

+#ifdef JYD_FUNCTION_CALL_FREQUENCY
+ sc->sc_stats.ast_jyd_ath_hardstart ++;
+#endif
txq = sc->sc_ac2q[skb->priority];

- if (txq->axq_depth > TAIL_DROP_COUNT) {
+ if (txq->axq_depth > sc->sc_queue_len) {
/* Wish to reserve some DMA buffers, try again later. */
requeue = 1;
goto hardstart_fail;
@@ -3765,9 +4146,15 @@
netif_stop_queue(dev);
sc->sc_devstopped = 1;
/* Stop tracking again we are giving it back*/
+#ifdef JYD_FUNCTION_CALL_FREQUENCY
+ sc->sc_stats.ast_jyd_ath_hardstart_drop ++;
+#endif
ieee80211_skb_untrack(skb);
return NETDEV_TX_BUSY;
}
+#ifdef JYD_FUNCTION_CALL_FREQUENCY
+ sc->sc_stats.ast_jyd_ath_hardstart_silent_drop ++;
+#endif
/* Now free the SKBs */
ieee80211_dev_kfree_skb_list(&skb);
return NETDEV_TX_OK;
@@ -6973,6 +7360,47 @@
}
}

+ /* jyyoo (jaeyong): in-kernel-network-monitor */
+ /* information to put:
+ 1. interface queue occupation length
+ 2. retransmission count
+ 3. receiving error count
+ */
+ if( sc->sc_iknm_enable ) {
+ int next_head;
+ sk_buff_data_t network_header = skb->data + 24 /* sizeof wifi header */ + 8 /* sizeof llc */;
+ if( (*(unsigned char*)(network_header)) == 69 ) // it means IP header with header length 20
+ {
+ sc->dp_exchange_buffer_drop ++;
+ next_head = sc->sc_recv_monitor_head + 1;
+ if( next_head >= MAX_MPARAM ) next_head = next_head - MAX_MPARAM;
+
+ if( next_head == sc->sc_recv_monitor_tail ) // exchange buffer is full, just drop this packet
+ {
+ printk("monitoring packet dropped :%d\n", sc->dp_exchange_buffer_drop);
+ }
+ else // insert into the exchange buffer
+ {
+ int h = sc->sc_recv_monitor_head;
+ struct timeval tv;
+ do_gettimeofday(&tv);
+ sc->sc_recv_monitor_param[h].sec = tv.tv_sec;
+ sc->sc_recv_monitor_param[h].msec = tv.tv_usec;
+ memcpy( sc->sc_recv_monitor_param[h].header, skb->data, HEADER_LEN ); // 14 bytes for ethernet header
+ sc->sc_recv_monitor_head = next_head;
+ }
+
+ {
+ int h,t;
+ h = sc->sc_recv_monitor_head;
+ t = sc->sc_recv_monitor_tail;
+ if( h < t ) h += MAX_MPARAM;
+ if( (h-t) > MAX_MPARAM_PERPACKET && sc->sc_recv_kthread_send_alive )
+ wake_up_interruptible(&sc->sc_recv_queue_send);
+ }
+ }
+ }
+
/*
* Locate the node for sender, track state, and then
* pass the (referenced) node up to the 802.11 layer
@@ -8382,6 +8810,58 @@
try0, keyix, antenna, flags, ctsrate, ctsduration, icvlen, ivlen,
comp);

+ /* jyyoo (jaeyong): in-kernel-network-monitor */
+ /* information to put:
+ 1. interface queue occupation length
+ 2. retransmission count
+ 3. receiving error count
+ */
+ if( sc->sc_iknm_enable ) {
+ int next_head;
+
+ /* first check exchange buffe is full or not */
+ next_head = sc->sc_monitor_head + 1;
+ if( next_head >= MAX_MPARAM ) next_head = next_head - MAX_MPARAM;
+
+ if( next_head == sc->sc_monitor_tail ) // exchange buffer is full, just drop this packet
+ {
+ printk("IKNM: exchange buffer is full,,, packet dropped\n");
+ sc->dp_exchange_buffer_drop ++;
+ }
+ else // insert into the exchange buffer
+ {
+ int h = sc->sc_monitor_head;
+ struct timeval tv;
+ do_gettimeofday(&tv);
+ sc->sc_monitor_param[h].sec = tv.tv_sec;
+ sc->sc_monitor_param[h].msec = tv.tv_usec;
+ /* monitor 4 priority queues */
+ sc->sc_monitor_param[h].qlen[WME_AC_VO] = (u_int8_t)(sc->sc_ac2q[WME_AC_VO]->axq_depth);
+ sc->sc_monitor_param[h].qlen[WME_AC_VI] = (u_int8_t)(sc->sc_ac2q[WME_AC_VI]->axq_depth);
+ sc->sc_monitor_param[h].qlen[WME_AC_BE] = (u_int8_t)(sc->sc_ac2q[WME_AC_BE]->axq_depth);
+ sc->sc_monitor_param[h].qlen[WME_AC_BK] = (u_int8_t)(sc->sc_ac2q[WME_AC_BK]->axq_depth);
+ sc->sc_monitor_param[h].ret = (u_int8_t)sc->sc_stats.ast_tx_longretry + sc->sc_stats.ast_tx_shortretry;
+ sc->sc_monitor_param[h].err = (u_int8_t)sc->sc_stats.ast_rx_phyerr;
+ sc->sc_monitor_param[h].modRate = (u_int8_t)txrate;
+ if( skb->network_header )
+ memcpy( sc->sc_monitor_param[h].header, skb->data, HEADER_LEN ); // 14 bytes for ethernet header
+
+
+ sc->sc_monitor_head = next_head;
+ }
+
+ /* if the buffer is quite large, wake up the sending process */
+
+ {
+ int h,t;
+ h = sc->sc_monitor_head;
+ t = sc->sc_monitor_tail;
+ if( h < t ) h += MAX_MPARAM;
+ if( (h-t) > MAX_MPARAM_PERPACKET && sc->sc_kthread_send_alive )
+ wake_up_interruptible(&sc->sc_queue_send);
+ }
+ }
+
/*
* Formulate first tx descriptor with tx controls.
*/
@@ -10886,6 +11366,137 @@

ATH_LOCK(sc);
switch (cmd) {
+
+ /* jyyoo add to enable TTL-based packet filtering */
+ /* it is a part of work around solution for click output packet filtering */
+ case SIOCGTTLPACKETFILTER:
+ {
+ if( copy_to_user(ifr->ifr_data, &ic->ic_enable_ttl_pf, sizeof(ic->ic_enable_ttl_pf)))
+ {
+ printk("madwifi: siocgttlpacketfilter failed\n");
+ error = -EFAULT;
+ }
+ else
+ {
+ printk("read ttl packet filter : %d\n", ic->ic_enable_ttl_pf);
+ error = 0;
+ }
+ }
+ break;
+ case SIOCSTTLPACKETFILTER:
+ {
+ unsigned char buf [4];
+ if( copy_from_user( buf, ifr->ifr_data, sizeof(buf)))
+ {
+ printk("madwifi: siocsttlpacketfilter failed\n");
+ error = -EFAULT;
+ }
+ else
+ {
+ ic->ic_enable_ttl_pf = *((u_int32_t*)buf);
+ printk("set ttl packet filter : %d\n", ic->ic_enable_ttl_pf);
+ error = 0;
+ }
+ }
+ break;
+ /* jyyoo finish */
+
+ /* jyyoo add to enable adhoc edca */
+ case SIOCGADHOCEDCA:
+ {
+ if( copy_to_user(ifr->ifr_data, &ic->ic_adhoc_edca, sizeof(ic->ic_adhoc_edca)))
+ {
+ printk("madwifi: siocgadhocedca failed\n");
+ error = -EFAULT;
+ }
+ else
+ {
+ printk("read adhoc edca : %d\n", ic->ic_adhoc_edca);
+ error = 0;
+ }
+ }
+ break;
+ case SIOCSADHOCEDCA:
+ {
+ unsigned char buf [4];
+ if( copy_from_user( buf, ifr->ifr_data, sizeof(buf)))
+ {
+ printk("madwifi: siocsadhocedca failed\n");
+ error = -EFAULT;
+ }
+ else
+ {
+ ic->ic_adhoc_edca = *((u_int32_t*)buf);
+ printk("set adhoc edca : %d\n", ic->ic_adhoc_edca);
+ error = 0;
+ }
+ }
+ break;
+ /* jyyoo finish */
+ /* jyyoo (jaeyong) control iknm enable disable */
+ case SIOCGATHIKNM:
+ {
+ if( copy_to_user(ifr->ifr_data, &sc->sc_iknm_enable, sizeof(sc->sc_iknm_enable)))
+ {
+ printk("madwifi: siocathiknm failed\n");
+ error = -EFAULT;
+ }
+ else
+ {
+ printk("madwifi: siocathiknm succeed : %d\n", sc->sc_iknm_enable);
+ error = 0;
+ }
+ }
+ break;
+ case SIOCSATHIKNM:
+ {
+ unsigned char buf[4];
+ if( copy_from_user( buf, ifr->ifr_data, sizeof(buf)))
+ {
+ printk("madwifi: siocsathiknm failed\n");
+ error = -EFAULT;
+ }
+ else
+ {
+ sc->sc_iknm_enable = *((int*)buf);
+ printk("set iknm enable: %d\n", sc->sc_iknm_enable );
+ error = 0;
+ }
+ }
+ break;
+ /* jyyoo (jaeyong) control tx queue len */
+ case SIOCGATHBUFLEN:
+ {
+ if( copy_to_user(ifr->ifr_data, &sc->sc_queue_len, sizeof(sc->sc_queue_len)))
+ {
+ printk("madwifi: siocgathbuflen failed\n");
+ error = -EFAULT;
+ }
+ else
+ {
+ printk("read athbuflen : %d\n", sc->sc_queue_len);
+ error = 0;
+ }
+ }
+ break;
+ case SIOCSATHBUFLEN:
+ {
+ unsigned char buf [4];
+ if( copy_from_user( buf, ifr->ifr_data, sizeof(buf)))
+ {
+ printk("madwifi: siocsathbuflen failed\n");
+ error = -EFAULT;
+ }
+ else
+ {
+ sc->sc_queue_len = *((int*)buf);
+ printk("set athbuflen : %d\n", sc->sc_queue_len);
+ error = 0;
+ }
+ }
+ break;
+
+
case SIOCGATHSTATS:
sc->sc_stats.ast_tx_packets = sc->sc_devstats.tx_packets;
sc->sc_stats.ast_rx_packets = sc->sc_devstats.rx_packets;
diff -Nru madwifi-original/ath/if_athioctl.h madwifi-new/ath/if_athioctl.h
--- madwifi-original/ath/if_athioctl.h 2009-10-05 17:25:39.000000000 +0200
+++ madwifi-new/ath/if_athioctl.h 2009-10-15 12:37:56.000000000 +0200
@@ -42,6 +42,8 @@
#ifndef _DEV_ATH_ATHIOCTL_H
#define _DEV_ATH_ATHIOCTL_H

+#define JYD_FUNCTION_CALL_FREQUENCY
+
struct ath_stats {
u_int32_t ast_watchdog; /* device reset by watchdog */
u_int32_t ast_hardware; /* fatal hardware error interrupts */
@@ -98,6 +100,17 @@
u_int32_t ast_ant_txswitch; /* tx antenna switches */
u_int32_t ast_ant_rx[8]; /* rx frames with antenna */
u_int32_t ast_ant_tx[8]; /* tx frames with antenna */
+
+#ifdef JYD_FUNCTION_CALL_FREQUENCY
+ /* jyyoo add to debug function call frequencies */
+ u_int32_t ast_jyd_ath_hardstart;
+ u_int32_t ast_jyd_ath_hardstart_drop;
+ u_int32_t ast_jyd_ath_hardstart_silent_drop;
+ u_int32_t ast_jyd_ath_hardstart_raw;
+ u_int32_t ast_jyd_ieee80211_hardstart;
+ u_int32_t ast_jyd_ieee80211_hardstart_drop;
+ u_int32_t ast_jyd_ieee80211_hardstart_silent_drop;
+#endif
};

struct ath_diag {
@@ -120,6 +133,22 @@
#define SIOCGATHSTATS (SIOCDEVPRIVATE+0)
#define SIOCGATHDIAG (SIOCDEVPRIVATE+1)
#define SIOCGATHRADARSIG (SIOCDEVPRIVATE+2)
+// jyyoo : buffer len
+#define SIOCSATHBUFLEN (SIOCDEVPRIVATE+3)
+#define SIOCGATHBUFLEN (SIOCDEVPRIVATE+4)
+// jyyoo : in kernel network monitoring
+#define SIOCSATHIKNM (SIOCDEVPRIVATE+5)
+#define SIOCGATHIKNM (SIOCDEVPRIVATE+6)
+// jyyoo : add for per-flow monitoring
+#define SIOCGPFMS_SIGNAL (SIOCDEVPRIVATE+10)
+#define SIOCGPFMS (SIOCDEVPRIVATE+11)
+// jyyoo : add for TTL-based packet filtering
+#define SIOCSTTLPACKETFILTER (SIOCDEVPRIVATE+12)
+#define SIOCGTTLPACKETFILTER (SIOCDEVPRIVATE+13)
+// jyyoo : add for adhoc edca
+#define SIOCSADHOCEDCA (SIOCDEVPRIVATE+14)
+#define SIOCGADHOCEDCA (SIOCDEVPRIVATE+15)
+
#else
#define SIOCGATHSTATS _IOWR('i', 137, struct ifreq)
#define SIOCGATHDIAG _IOWR('i', 138, struct ath_diag)
diff -Nru madwifi-original/ath/if_athvar.h madwifi-new/ath/if_athvar.h
--- madwifi-original/ath/if_athvar.h 2009-10-05 17:25:39.000000000 +0200
+++ madwifi-new/ath/if_athvar.h 2009-10-15 12:37:28.000000000 +0200
@@ -47,9 +47,17 @@
#include "ah_os.h"
#include "if_athioctl.h"
#include
+#include
#include "net80211/ieee80211.h" /* XXX for WME_NUM_AC */
#include
#include
+#include /* for in_aton */
+#include
+#include
+#include
+#include
+#include
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
# include
#endif
@@ -58,6 +66,7 @@
#define irqs_disabled() 0
#endif

+
/*
* Deduce if tasklets are available. If not then
* fall back to using the immediate work queue.
@@ -596,6 +605,34 @@
(_tqs)->axq_link = NULL; \
} while (0)

+
+/* jyyoo (jaeyong): in-kernel-network-monitoring */
+#define HEADER_LEN 76
+struct monitor_param {
+ int sec;
+ int msec;
+ u_int8_t qlen[4];
+ u_int8_t ret;
+ u_int8_t err;
+ u_int8_t modRate;
+ u_int8_t reserved;
+ char header[HEADER_LEN]; /* including ethernet, ip, tcp (+option) header */
+};
+/* MAX_MPARAM basically determines the tradeoff between cpu efficiency and memory efficiency */
+#define HEADER_LEN 76
+struct monitor_param_recv {
+ int sec;
+ int msec;
+ char header[HEADER_LEN]; /* including ethernet, ip, tcp (+option) header */
+};
+/* MAX_MPARAM basically determines the tradeoff between cpu efficiency and memory efficiency */
+/* we use 8KB as the buffer for exchanging the header from process context of outgoing packet and kernel thread */
+/* 8192 / 92 = 85 */
+#define MAX_MPARAM 85
+/* 1440 / 92 = 15 */
+#define MAX_MPARAM_PERPACKET 15
+
+
/*
* concat buffers from one queue to other
*/
@@ -839,6 +876,59 @@
* detected radars */
u_int32_t sc_nexttbtt;
u_int64_t sc_last_tsf;
+
+ /* jyyoo (jaeyong): in-kernel-network-monitor */
+ struct socket* sc_recv_sock_mclient; /* monitor client */
+ int sc_recv_port_number; /* server port */
+ struct sockaddr_in sc_recv_serv_addr; /* server ip address */
+ struct iovec sc_recv_iov_msg; /* message structure */
+ struct msghdr sc_recv_msghdr; /* message header structure */
+ char sc_recv_msgbuf[1440];
+
+ struct sockaddr_in sc_recv_serv_addr2; /* server ip address */
+
+ /* kernel thread for sending the network info to server */
+ struct task_struct* sc_recv_kthread_send;
+ wait_queue_head_t sc_recv_queue_send;
+ int sc_recv_kthread_send_alive;
+
+ /* buffer for sharing between kernel thread and the process of outgoing packet */
+ struct monitor_param_recv sc_recv_monitor_param[MAX_MPARAM];
+ int sc_recv_monitor_head;
+ int sc_recv_monitor_tail;
+
+ spinlock_t sc_recv_send_lock;
+ /* jyyoo (jaeyong): in-kernel-network-monitor */
+ struct socket* sc_sock_mclient; /* monitor client */
+ int sc_port_number; /* server port */
+ struct sockaddr_in sc_serv_addr; /* server ip address */
+ struct iovec sc_iov_msg; /* message structure */
+ struct msghdr sc_msghdr; /* message header structure */
+ char sc_msgbuf[1440];
+
+ struct sockaddr_in sc_serv_addr2; /* server ip address */
+
+ /* kernel thread for sending the network info to server */
+ struct task_struct* sc_kthread_send;
+ wait_queue_head_t sc_queue_send;
+ int sc_kthread_send_alive;
+
+ /* buffer for sharing between kernel thread and the process of outgoing packet */
+ struct monitor_param sc_monitor_param[MAX_MPARAM];
+ int sc_monitor_head;
+ int sc_monitor_tail;
+
+ spinlock_t sc_send_lock;
+
+ /* jyyoo (jaeyong): control tx queue len */
+ int sc_queue_len;
+
+ /* debugging param */
+ int dp_exchange_buffer_drop;
+
+ /* in-kernel-network-monitor enable/disable toggle */
+ int sc_iknm_enable;
+
};

typedef void (*ath_callback) (struct ath_softc *);
diff -Nru madwifi-original/net80211/ieee80211_output.c madwifi-new/net80211/ieee80211_output.c
--- madwifi-original/net80211/ieee80211_output.c 2009-10-05 17:25:39.000000000 +0200
+++ madwifi-new/net80211/ieee80211_output.c 2009-10-16 23:23:00.000000000 +0200
@@ -53,6 +53,8 @@
#include "if_ethersubr.h"
#include "if_media.h"

+#include
+
#include
#include
#include
@@ -84,13 +86,22 @@
{
struct ieee80211vap *vap = ni->ni_vap;
struct ether_header *eh = (struct ether_header *) skb->data;
+ struct ieee80211com *ic = ni->ni_ic;
int v_wme_ac = 0, d_wme_ac = 0;

/* default priority */
skb->priority = WME_AC_BE;

- if (!(ni->ni_flags & IEEE80211_NODE_QOS))
- return 0;
+ /* jyyoo add to enable ad-hoc edca */
+
+ if( !ic->ic_adhoc_edca )
+ {
+ if (!(ni->ni_flags & IEEE80211_NODE_QOS))
+ return 0;
+ }
+
+ /* jyyoo end */
+

/*
* If node has a vlan tag then all traffic
@@ -111,7 +122,8 @@
ni->ni_stats.ns_tx_vlanmismatch++;
return 1;
}
- if (ni->ni_flags & IEEE80211_NODE_QOS) {
+ if (ni->ni_flags & IEEE80211_NODE_QOS || ic->ic_adhoc_edca) {
+
v_pri = (tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
switch (v_pri) {
case 1:
@@ -206,6 +218,7 @@
struct net_device *parent = ic->ic_dev;
struct ieee80211_node *ni = NULL;
struct ether_header *eh;
+ int re=0;

/* reset the skb of new frames reaching this layer BEFORE
* we invoke ieee80211_skb_track. */
@@ -230,10 +243,43 @@
#endif
goto bad;
}
+
+#ifdef JYD_FUNCTION_CALL_FREQUENCY
+ /* jyyoo to debug function call frequencies */
+ {
+ struct net_device* parent_dev = vap->iv_ic->ic_dev;
+ struct ath_softc* sc = parent_dev->priv;
+ sc->sc_stats.ast_jyd_ieee80211_hardstart ++;
+ }
+#endif
+
+ /*
+ * jyyoo : hack to support click
+ * desc: click user-level do not filter the local output packet properly
+ * because iptables can not filter the local output
+ * appropriately. if we use iptables to filter the local
+ * ouput packet, then all the click packets are also filtered out.
+ * The trick is as follows:
+ * ip uses default ttl as IPDEFTTL (64). We filter out ttl of IPDEFTTL (64)
+ * and use pass packets with ttl IPDEFTTL -1 (63). the local packet of ttl IPDEFTTL (64)
+ * will be filtered and we can manually decrease the ttl.
+ */
+ if( ic->ic_enable_ttl_pf )
+ {
+ const struct iphdr *ip = (struct iphdr *)
+ (skb->data + sizeof (struct ether_header));
+ if( ip->version == IPVERSION && ip->ttl == IPDEFTTL )
+ {
+ printk("JYD: packet filtered\n");
+ goto bad;
+ }
+ }
+ /* jyyoo finish */
+

if (vap->iv_opmode == IEEE80211_M_MONITOR) {
ieee80211_monitor_encap(vap, skb);
- ieee80211_parent_queue_xmit(skb);
+ re = ieee80211_parent_queue_xmit(skb);
return NETDEV_TX_OK;
}

@@ -296,15 +342,50 @@
SKB_CB(skb1)->ni = ieee80211_find_txnode(vap->iv_xrvap,
eh->ether_dhost);
/* Ignore this return code. */
- ieee80211_parent_queue_xmit(skb1);
+ re = ieee80211_parent_queue_xmit(skb1);
}
}
#endif
ieee80211_unref_node(&ni);
- ieee80211_parent_queue_xmit(skb);
+ re = ieee80211_parent_queue_xmit(skb);
+
+ if( re == 1 )
+ {
+#ifdef JYD_FUNCTION_CALL_FREQUENCY
+ /* jyyoo to debug function call frequencies */
+ {
+ struct net_device* parent_dev = vap->iv_ic->ic_dev;
+ struct ath_softc* sc = parent_dev->priv;
+ sc->sc_stats.ast_jyd_ieee80211_hardstart_drop ++;
+ }
+#endif
+
+ /* jyyoo : note
+ * to make the complete driver, we have to stop
+ * queue a bit and wake when it is avilable,
+ * currently, not figured when we have to wake
+ * the queue (netif_wake_queue).
+ * It is probably related when ath(wifi0)-buffer
+ * is sufficiently drained out
+ */
+ // netif_stop_queue(dev);
+
+ //return NETDEV_TX_BUSY;
+ // ENOUBUFS will be directly delivered to raw socket send function
+ return -ENOBUFS;
+ }
return NETDEV_TX_OK;

bad:
+#ifdef JYD_FUNCTION_CALL_FREQUENCY
+ /* jyyoo to debug function call frequencies */
+ {
+ struct net_device* parent_dev = vap->iv_ic->ic_dev;
+ struct ath_softc* sc = parent_dev->priv;
+ sc->sc_stats.ast_jyd_ieee80211_hardstart_silent_drop ++;
+ }
+#endif
+
if (skb != NULL)
ieee80211_dev_kfree_skb(&skb);
if (ni != NULL)
@@ -316,8 +397,9 @@
* skb is consumed in all cases
*/

-void ieee80211_parent_queue_xmit(struct sk_buff *skb) {
+int ieee80211_parent_queue_xmit(struct sk_buff *skb) {
struct ieee80211vap *vap = skb->dev->priv;
+ int re=0;

vap->iv_devstats.tx_packets++;
vap->iv_devstats.tx_bytes += skb->len;
@@ -327,9 +409,18 @@
skb->dev = vap->iv_ic->ic_dev;

if (netif_queue_stopped(skb->dev))
- ieee80211_dev_kfree_skb(&skb);
+ {
+ vap->iv_devstats.tx_dropped++;
+ re=1;
+// ieee80211_dev_kfree_skb(&skb); // jyyoo disabled the code
+ ieee80211_skb_untrack(skb);
+ }
else if (dev_queue_xmit(skb) == NET_XMIT_DROP)
+ {
vap->iv_devstats.tx_dropped++;
+ re=1;
+ }
+ return re;
}

/*
diff -Nru madwifi-original/net80211/ieee80211_proto.h madwifi-new/net80211/ieee80211_proto.h
--- madwifi-original/net80211/ieee80211_proto.h 2009-10-05 17:25:39.000000000 +0200
+++ madwifi-new/net80211/ieee80211_proto.h 2009-10-14 20:17:08.000000000 +0200
@@ -73,7 +73,7 @@
struct sk_buff *, int, int, u_int64_t);
void ieee80211_sta_pwrsave(struct ieee80211vap *, int);
int ieee80211_hardstart(struct sk_buff *, struct net_device *);
-void ieee80211_parent_queue_xmit(struct sk_buff *);
+int ieee80211_parent_queue_xmit(struct sk_buff *); // jyyoo modify
int ieee80211_send_nulldata(struct ieee80211_node *);
int ieee80211_send_qosnulldata(struct ieee80211_node *, int);
int ieee80211_send_mgmt(struct ieee80211_node *, int, int);
diff -Nru madwifi-original/net80211/ieee80211_var.h madwifi-new/net80211/ieee80211_var.h
--- madwifi-original/net80211/ieee80211_var.h 2009-10-05 17:25:39.000000000 +0200
+++ madwifi-new/net80211/ieee80211_var.h 2009-10-05 19:48:35.000000000 +0200
@@ -450,6 +450,15 @@
u_int8_t ic_chanchange_tbtt;
u_int8_t ic_chanchange_chan;

+
+ /* jyyoo add: enable to DEFTTL filtering to support user-level click
+ * to be able to filter out the original kernel-generated packets
+ */
+ u_int32_t ic_enable_ttl_pf;
+
+ /* jyyoo add: enable adhoc edca */
+ u_int32_t ic_adhoc_edca;
+
/* Global debug flags applicable to all VAPs */
int ic_debug;
/* used for reference tracking/counting. Nodes are shared between VAPs,
diff -Nru madwifi-original/tools/athstats.c madwifi-new/tools/athstats.c
--- madwifi-original/tools/athstats.c 2009-10-05 17:25:39.000000000 +0200
+++ madwifi-new/tools/athstats.c 2009-10-15 12:46:31.000000000 +0200
@@ -279,6 +279,17 @@
"phyerr",
"rssi",
"rate");
+#ifdef JYD_FUNCTION_CALL_FREQUENCY
+ printf(" %8s %8s %8s %8s %8s %8s %8s",
+ "athxmit",
+ "athraw",
+ "athdrop",
+ "athsdrop",
+ "netxmit",
+ "netdrop",
+ "netsdrop"
+ );
+#endif
putchar('\n');
fflush(stdout);
line = 0;
@@ -290,7 +301,7 @@
err(1, ifr.ifr_name);
if (!getifstats(ifr.ifr_name, &icur, &ocur))
err(1, ifr.ifr_name);
- printf("%8lu %8lu %7u %7u %7u %6u %6u %6u %7u %4u %3uM\n",
+ printf("%8lu %8lu %7u %7u %7u %6u %6u %6u %7u %4u %3uM",
(icur - itot) -
(cur.ast_rx_mgt - total.ast_rx_mgt),
ocur - otot,
@@ -303,6 +314,19 @@
cur.ast_rx_phyerr - total.ast_rx_phyerr,
cur.ast_rx_rssi,
rate);
+
+#ifdef JYD_FUNCTION_CALL_FREQUENCY
+ printf("%8lu %8lu %8lu %8lu %8lu %8lu %8lu",
+ cur.ast_jyd_ath_hardstart - total.ast_jyd_ath_hardstart,
+ cur.ast_jyd_ath_hardstart_raw - total.ast_jyd_ath_hardstart_raw,
+ cur.ast_jyd_ath_hardstart_drop - total.ast_jyd_ath_hardstart_drop,
+ cur.ast_jyd_ath_hardstart_silent_drop - total.ast_jyd_ath_hardstart_silent_drop,
+ cur.ast_jyd_ieee80211_hardstart - total.ast_jyd_ieee80211_hardstart,
+ cur.ast_jyd_ieee80211_hardstart_drop - total.ast_jyd_ieee80211_hardstart_drop,
+ cur.ast_jyd_ieee80211_hardstart_silent_drop - total.ast_jyd_ieee80211_hardstart_silent_drop );
+#endif
+
+ printf("\n");
total = cur;
itot = icur;
otot = ocur;
diff -Nru madwifi-original/tools/wlanconfig.c madwifi-new/tools/wlanconfig.c
--- madwifi-original/tools/wlanconfig.c 2009-10-05 17:25:39.000000000 +0200
+++ madwifi-new/tools/wlanconfig.c 2009-10-05 19:54:01.000000000 +0200
@@ -61,6 +61,7 @@
#include "net80211/ieee80211.h"
#include "net80211/ieee80211_crypto.h"
#include "net80211/ieee80211_ioctl.h"
+#include "ath/if_athioctl.h"
#include "do_multi.h"

/*
@@ -201,6 +202,91 @@
err(1, "unknown 'list' option: %s", arg);
} else /* NB: for compatibility */
list_stations(ifname);
+ /* jyyoo (jaeyong) tx queue len control */
+ } else if ( streq(cmd, "command")) {
+ if( argc == 5 )
+ {
+ struct ifreq ifr;
+ int s;
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if( s < 0 )
+ err(1, "socket");
+ ifname = argv[1];
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if( streq(argv[3], "stxqlen"))
+ {
+ int value=atoi(argv[4]);
+ ifr.ifr_data = (caddr_t) &value;
+ if( ioctl(s, SIOCSATHBUFLEN, &ifr) < 0 )
+ err(1, ifr.ifr_name);
+ } else if( streq(argv[3], "setiknm"))
+ {
+ int value=atoi(argv[4]);
+ ifr.ifr_data = (caddr_t) &value;
+ if( ioctl(s, SIOCSATHIKNM, &ifr) < 0 )
+ err(1, ifr.ifr_name);
+ }
+ else if (streq(argv[3], "sttlpf"))
+ {
+ int value=atoi(argv[4]);
+ ifr.ifr_data = (caddr_t) &value;
+ if( ioctl(s, SIOCSTTLPACKETFILTER, &ifr) < 0 )
+ err(1, ifr.ifr_name);
+ }
+ else if (streq(argv[3], "sadhocedca"))
+ {
+ int value=atoi(argv[4]);
+ ifr.ifr_data = (caddr_t) &value;
+ if( ioctl(s, SIOCSADHOCEDCA, &ifr) < 0 )
+ err(1, ifr.ifr_name);
+ }
+ close(s);
+ }
+ else if( argc == 4 )
+ {
+ struct ifreq ifr;
+ int s;
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if( s < 0 )
+ err(1, "socket");
+ ifname = argv[1];
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if( streq(argv[3], "gtxqlen"))
+ {
+ int value;
+ ifr.ifr_data = (caddr_t) &value;
+ if( ioctl(s, SIOCGATHBUFLEN, &ifr) < 0 )
+ err(1, ifr.ifr_name);
+ printf("queue len: %d\n", value);
+ } else if( streq(argv[3], "getiknm"))
+ {
+ int value;
+ ifr.ifr_data = (caddr_t) &value;
+ if( ioctl(s, SIOCGATHIKNM, &ifr) < 0 )
+ err(1, ifr.ifr_name);
+ printf("iknm : %d\n", value);
+ }
+ if( streq(argv[3], "gttlpf"))
+ {
+ int value;
+ ifr.ifr_data = (caddr_t) &value;
+ if( ioctl(s, SIOCGTTLPACKETFILTER, &ifr) < 0 )
+ err(1, ifr.ifr_name);
+ printf("ttl packet filter mode: %d\n", value);
+ }
+ if( streq(argv[3], "gadhocedca"))
+ {
+ int value;
+ ifr.ifr_data = (caddr_t) &value;
+ if( ioctl(s, SIOCGADHOCEDCA, &ifr) < 0 )
+ err(1, ifr.ifr_name);
+ printf("adhoc edca: %d\n", value);
+ }
+
+ close(s);
+
+ }
+
} else
usage();

@@ -288,6 +374,7 @@
fprintf(stderr, " wlanmode [sta|adhoc|ap|monitor|wds|ahdemo] [bssid | -bssid] [nosbeacon]\n");
fprintf(stderr, "usage: wlanconfig athX destroy\n");
fprintf(stderr, "usage: wlanconfig athX list [active|ap|caps|chan|freq|keys|scan|sta|wme]\n");
+ fprintf(stderr, "usage: wlanconfig wifiX command [ [s|g]ttlpf | [s|g]adhocedca ]\n");
exit(-1);
}

Linux Networking Kernel Function Map V-0.1


Hope it helps to understand linux networking kernel

Friday, October 16, 2009

bypassing socket buffer using raw socket... interesting

setsockopt HDRINCL 'error code 22, Invalid arg' OpenBSD 3.3 using gcc 2.95.3

Asked by crizza in OpenBSD

Tags: hdrincl, setsockopt

Hi all. Im having problems allowing the kernel to let me include my own ip header.

I am writing a network/firewall and protocol analysis tool for my work.

Running on x86/OpenBSD 3.3 platform using gcc 2.95.3 with no special opts apart from debugging.

The src compiles ok, but when run; 'perror' recieves error code '22' 'invalid arg' from setsockopt ( i presume ) and I cannot understand why???

I have tested the prog bypassing the setsockopt function and it works ok, alas with the kernel ip header included ;(

Please forgive me if its a glaringly obvious error on my part as I am returning to c & *nix after a few years in the wilderness.

N.B Apologies, but my code seems to have lost all its tabs when i posted it



Many thanks for any help offered

Chris

--------------------------------------------------

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "decs.h"

int main( void )
{
unsigned int tport;
unsigned short uno, s;
struct iphead *iphead;
struct tcphead *tcphead;
struct sockaddr_in dst;
char dgram[BUFFER];
tport = 1500;
uno = 1;

if( getuid() ) {
printf("ALERT: You need to be r00t\n");
exit( 0 );
}

if ( !( s = socket( AF_INET, SOCK_RAW, IPPROTO_TCP ) ) )
perror("socket error");

// cast dgram to struct and point *iphead at element
iphead = ( struct iphead *) dgram;
// as above but with size of ip_header offset
tcphead = ( struct tcphead *) dgram + sizeof( struct iphead );

dst.sin_family = AF_INET;
dst.sin_port = htons( tport );
dst.sin_addr.s_addr = inet_addr( "192.168.0.7" );
memset( dgram, 0, BUFFER );

// custom values
iphead->ip_hl = 5;
iphead->ip_v = 4;
iphead->ip_tos = 0;
iphead->ip_len = BUFFER;
iphead->ip_id = htonl( 1234 );
iphead->ip_off = 0;
iphead->ip_ttl = 255;
iphead->ip_p = 6; // tcp
iphead->ip_sum = 0; // set to 0 by default
iphead->ip_src.s_addr = inet_addr( "192.168.0.1" );
iphead->ip_dst.s_addr = dst.sin_addr.s_addr;
tcphead->th_sport = htons( 1234 );
tcphead->th_dport = htons( tport );
tcphead->th_seq = random();
tcphead->th_ack = 0;
tcphead->th_x2 = 0;
tcphead->th_off = 0;
tcphead->th_flags = TH_SYN; // init new connection
tcphead->th_win = htonl( MAX_WINDOW );
tcphead->th_sum = 0;
tcphead->th_urp = 0; // no urgency flags

// generate chksum
iphead->ip_sum = chksum( ( unsigned short *)dgram, iphead->ip_len >> 1 );

// header check
if ( setsockopt( s,
IPPROTO_IP,
IP_HDRINCL,
&uno,
sizeof( uno ) ) < style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> perror( "Alert: setsockopt cannot set HDRINCL" );
exit( 1 );
}

// kill with control-c
while( 1 ) {
if( sendto( s,
dgram,
sizeof( dgram ),
0,
( struct sockaddr * ) &dst,
sizeof( dst ) ) < style="padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "> perror( "Alert: sendto failed" );
exit( 1 );
} else {
printf( "." );
}
}
exit( 0 );
}


--------------------------------------------------

// Decs.h

#ifndef H_DECS
#define H_DECS
#define BUFFER sizeof( struct iphead ) + sizeof( struct tcphead )
#define MAX_WINDOW 65535

__BEGIN_DECLS
unsigned short chksum( unsigned short *, int );
void chkhdr( unsigned short );
__END_DECLS

/* initial command line opts */
typedef struct opts {
unsigned char *cfg; // absolute path
unsigned char *host; // dest host
unsigned short int port; // dest port
unsigned short int pkts; // number of packets to send
}cli_opts;

struct iphead {
unsigned char ip_hl, ip_v; // 4 bits respectively
unsigned char ip_tos; // limo or taxi???
unsigned short int ip_len; // total len of header and data
unsigned short int ip_id; // help assemble fragments
unsigned short ip_off; // 3bit control flags, 13bit offset. Do i frag?
unsigned char ip_ttl; // --ttl each hop. if 0 then destroy
unsigned char ip_p; // next level protocol
unsigned short int ip_sum; // header checksum
struct in_addr ip_src, ip_dst; // source and dest
};

struct tcphead {
unsigned short int th_sport; // source port
unsigned short int th_dport; // destination port
unsigned int th_seq; // seq number of first data octet in segment
unsigned int th_ack; // next seq num expected to recieve
unsigned char th_x2, th_off; /* x2 reserved for future use ( must be 0 )
* data_off indicates where data begins */
unsigned char th_flags; /* TH_URG: urgent, TH_ACK: yup, TH_PSH, do not
* buffer segment push straight thro stack
* TH_RST: tell peer to terminate
* TH_SYN: init new connect
* TH_FIN: close connection
* control bits */
unsigned short int th_win; /* amount of data octets to be accepted
* including original seq_num octet */
unsigned short int th_sum; // initial value = 0
unsigned short int th_urp; // only used if TH_URG is set in tcp_flags
};


/* standard BSD checksum */
unsigned short chksum ( unsigned short *addr, int len ) {
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;

/* 32 bit accumulator 'sum', add sequential 16 bit words to it '*w'.
* At the end fold back all the carry bits from top 16 bits into
* lower 16 bits */
while ( nleft > 1 ) {
sum += *w++;
nleft -= 2;
}


// mop up odd byte, if necessary
if ( nleft == 1 ) {
*( u_char * ) ( &answer ) = *( u_char * )w ;
sum += answer;
}

// add back carry outs from top 16 bits to lower 16 bits
sum = ( sum >> 16 ) + ( sum + 0xffff ); // add hi 16 to low 16
sum += ( sum >> 16 ); // add carry
answer = ~sum; // truncate to 16bits
return ( answer );
}

// check kernel hasnt inserted header
void chkhdr( unsigned short sockd ) {

}

#endif
--------------------------------------------------View the Solution FREE for 30 Days

how linux system call works?

check it out, so cool

http://www.ibm.com/developerworks/linux/library/l-system-calls/index.html

Thursday, October 15, 2009

stupid madwifi virtual device handling

Madwifi athX virtual devices always send TX_OK to networking kernel,

look into ieee80211_hardstart function at net80211/ieee80211_output.c

at the end of the function, it returns NETDEV_TX_OK.

We have to change it to check whether ieee80211_paranet_queue_xmit is succeeded or not and return the result.
Be sure not to free the skb before returning NETDEV_TX_BUSY.
Network kernel will try to free the skb AGAIN!!

Linux network kernel does not allow virtual device is busy!!

http://lxr.linux.no/linux+v2.6.26.6/net/core/dev.c#L1733

1733                                rc = 0;
1734                                if (!dev_hard_start_xmit(skb, dev)) {
1735                                        HARD_TX_UNLOCK(dev); 
1736                                        goto out; 
1737                                } 
1738                        } 
1739                        HARD_TX_UNLOCK(dev); 
1740                        if (net_ratelimit()) 
1741                                printk(KERN_CRIT "Virtual device %s asks to " 
1742                                       "queue packet!\n", dev->name);

if dev_hard_start_xmit failed, it does not report the reason to upper layer.
Look, rc is zero (which means TX_OK),

How about 
rc = dev_hard_start_xmit(), to report that the virtual device is going crazy ?

Saturday, October 10, 2009

Simply print stack trace...

lookup

warn_on_slowpath()

or you can use dump_stack()

Debugging linux kernel

1 Debugging Linux Kernel Lockup / Panic / Oops

Here are some notes on how to debug Linux kernel lockups – both "hard lockups" and "soft lockups" – and other panic, BUG, and oops situations. I am not an expert in this, but I figured incomplete information was better than no information, so here we go:

1. One way of confirming that you are the victim of a lockup is to note that the keyboard “caps lock” light does not respond to the “caps lock” key. Similarly the the “num lock” light won’t respond to the “num lock” key. Furthermore, the machine will not respond to ctrl-alt-delete.

Some people take this symptom as their definition of a hard lockup ... but beware that there is a situation that the kernel calls a soft lockup that exhibits the same symptom.

One way a soft lockup can occur is when the machine goes into a loop with interrupts turned off. This commonly happens if a device driver uses spinlocks improperly.

2. It is good to enable "Detect Soft Lockup" in the kernel. I believe everybody should do this, routinely, even if they are not expecting kernel bugs. To enable this:
 make menuconfig          \--> Kernel Hacking            \--> Detect Soft Lockups 

and then of course recompile your kernel, install the newly compiled kernel, and reboot.

For slightly more information, see the associated with this configuration option. As it says (in part) there:

Say Y here to enable the kernel to detect "soft lockups", which are bugs that cause the kernel to loop in kernel mode for more than 10 seconds, without giving other tasks a chance to run.

When a soft-lockup is detected, the kernel will print the current stack trace (which you should report), but the system will stay locked up. This feature has negligible overhead.

3. If there is a kernel “panic” or “BUG” or “oops”, you will want to capture the stack trace.

In some smallish subset of cases, the stack trace will be saved in the log files, but you should not count on this.

Far and away the best way to do this is to set up a “serial console”. That is, you arrange for console i/o (including oops messages) to appear on a serial port.

Getting this to work requires the following steps:

        make menuconfig          \--> Device Drivers            \--> Character devices              \--> Serial drivers                \--> Console on 8250/16550 and compatible serial port 

Then, in your /boot/grub/menu.lst file, add a boot option, namely

          console=ttyS0,115200 

or more explicitly, you need a grub stanza something like this:

     title Linux (serial console)         root (hd0,2)         kernel /boot/vmlinuz-2.6.99 ro root=/dev/sda3 console=ttyS0,115200 console=tty0 

Here tty0 refers to “the” PC screen (i.e. the one hooked to “the” graphics card via the VGA interface or some such). Meanwhile, ttyS0 refers to the lowest-numbered serial line. Note that ttyS0 is what Microsoft calls com1, and ttyS1 is what they call com2, et cetera; the MS numbers are systematically one unit higher.

You are not required to explicitly specify the baudrate (115200) of the serial line, but I recommend you do so. Of course you are free to use another serial line such as ttyS1 if you prefer. In any case, you must use the correct capitalization (capital S). Note that you can specify more than one console=... option, as in the example above. If you specify none, you get tty0 by default. If you specify only ttyS0, you get that instead of tty0. If you want both, you must specify both.

Tangential remark: Choosing to log kernel messages to the serial port is independent of choosing to permit logins on that serial port; you can choose either or both or neither.

If you choose both, it allows you to administer a system that has no screen at all.

Edit /etc/inittab to tell init to spawn a getty on the chosen serial line. I recommend you leave at least one runlevel where the getty is not spawned, for convenience if you ever need to use that serial port for something else. You may also need to edit /etc/securetty if you want to permit root logins on the serial line.

If you want to interact with the grub menu via the serial line, you must reconfigure grub accordingly. See the grub info pages. (You can skip this task if you are content to let grub boot the default kernel without interaction, which is often the case. Just don’t make a mistake with your grub configuration, or you’ll be locked out until you hook up a screen.)

Then of course you must hook up a serial cable from your computer (#1) to some other computer (#2). We assume computer #2 will remain running even if/when computer #1 crashes. On computer #2, run some communication program such as Kermit to allow you to talk to the serial line, and log the traffic to a disk file.

Computer #2 doesn’t need to be a Linux box. If it is a windows box, you can install Kermit-for-windows, or just use the built-in “hyperterm” application to make the connection and log the traffic.

As for the cable itself, you need “null modem” functionality. This just involves crossing a couple of wires. In many cases, if the cable has female connectors on both ends, it will have this functionality built in. In particular, a so-called LapLink cable has null-modem functionality built in. Conversely, if the cable looks like an extension cord (male on one end, female on the other) it most likely does not have null-modem functionality, and you will need a separate dongle (both to perform the sex-change operation and to cross the required wires).

To test that it is working, try something like

       echo "Hi there." > /dev/console 

and verify that the message is seen by computer #2.

If you have two computers, you can use each to ride herd on the other. All you need is two cables. Just use ttyS0 as the console on each one, and monitor it with ttyS1 on the other. Presumably they won’t both crash at the same time. If you have a large number of computers, you can connect them in a big daisy chain: ABCDEA. If you have an even number of machines, you might consider connecting them in pairs, but the daisy chain is just as easy, and isn’t limited to even numbers. If machine N crashes, you can ssh to machine N+1 (via its ethernet interface) to collect the logged information; we don’t need to rely on the serial links for all of our communication.

4. If you are debugging Linux device drivers, additional steps are needed. The problem is that the normal Linux serial-port driver is interrupt driven, so if your driver crashes with the interrupts off, you’ll never see the stack trace on the serial console. The fix for this is simple:
 make menuconfig          \--> Kernel Hacking            \--> Early printk 

The point here is that by selecting this option, you get a non-interrupt-dependent printk (not just an “early” printk). This trick is not very well documented or widely known, so be glad that somebody told you about it.

There are some mild downsides to the early printk option; see the menuconfig for this option for details.

5. I’m not entirely sure what the kernel calls “hard” lockup. I suppose it is any lockup so horrible that it cannot be detected by the aforementioned soft lockup detector.

The simplest way to escape from a hard lockup and get a stack trace is by means of a watchdog timer. For info on watchdog timers, read /usr/src/linux/Documentation/watchdog/*.txt.

If you are running on a system that has an Intel 82801 “I/O Controller Hub” chip (which includes most of the reasonably modern Intel-based systems) then life is simple: you can use the TCO timer and route it to the processor’s NMI line (Non-Maskable Interrupt).

To make this happen:

 make menuconfig           \--> Device Drivers             \--> Character devices               \--> Watchdog Cards                 \--> Intel i8xx TCO Timer/Watchdog                 \--> Intel TCO Timer/Watchdog 

Make it a module. Load it with modprobe iTCO-wdt.

Note that in some older kernels the option was named differently
 make menuconfig           \--> Device Drivers             \--> Character devices               \--> Watchdog Cards                 \--> Intel i8xx TCO Timer/Watchdog 
The module was loaded with modprobe i8xx-tco.

You can tickle it with the simple userspace program in section 2, or the even simpler program mentioned in /usr/src/linux/Documentation/watchdog/watchdog.txt. That program is advertised as “Example Watchdog Driver” but it’s not a driver in the usual sense of the word; it’s really an “Example Watchdog Daemon” or something like that.

Alternatively, you can tickle it using something like echo > /dev/watchdog every so often. Use echo -n V > /dev/watchdog to make the watchdog stop watching (so you can stop tickling, without causing a reboot).

If you don’t have an 82801 chip, you’ll have to buy one of the hardware cards described in the aforementioned watchdog.txt file.

6. There is also a thing called “softdog” aka “soft watchdog” aka “software watchdog” ... but I’ve never figured out what it’s good for.
  • For soft lockups, it is not needed; the aforementioned soft lockup detector works fine.
  • For hard lockups, it is not effective.
  • I guess you could use it to check the health of some critical userspace application ... but in this case I would think that userspace timers would be a more appropriate solution.

If you’re still interested, you can find it at:

 make menuconfig           \--> Device Drivers             \--> Character devices               \--> Watchdog Cards                 \--> Software watchdog 

7. Another way of performing the “watchdog” task is via an external power controller, aka controlled power strip. An example is the RPC-S6, which has six independently-controlled power outlets, and accepts control signals via a serial port. There are similar products that accept control signals via a parallel port or via IP.

There are at least two ways to proceed:

  • You can have two or more power controllers, such that power to each machine comes from a strip controlled by some other machine.
  • Suppose you have only one power controller, and it is controlled by machine A. You can set up a watchdog function (aka heartbeat function) on one of the outlets, and use that outlet to power machine A. That means that if machine A ever hangs, the power controller will cycle power to that outlet, causing a reboot.

    Of course if machine A is not hung, you have programmatic control of all the machines plugged into the power controller. This includes control of machine A itself. Beware that any command to power down machine Ais irreversible, unless the same command brings the power back up later.

2 Example Watchdog Daemon Program

#include \
#include \
#include \
#include \

#include

typedef void (*sighandler_t)(int);

int fd;

void handler(int sig) {
write(fd, "V", 1);
fprintf(stdout, "Bye (%d).\n", sig);
exit(0);
}

void inst(const int sig){
sighandler_t rslt = signal(sig, handler);
if (rslt == SIG_ERR) {
fprintf(stderr, "Could not set up signal handler: ");
perror(0);
exit(1);
}
}

int main(int argc, const char *argv[]) {

inst(SIGHUP); // hangup
inst(SIGINT); // often tied to ^C
inst(SIGTERM); // default for kill command

fd = open("/dev/watchdog", O_WRONLY);
if (fd == -1) {
fprintf(stderr, "Could not open /dev/watchdog: ");
perror(0);
// exit(1);
}
while (1) {
write(fd, "\0", 1);
fsync(fd);
sleep(10);
}
}

3  References

1.
Glenn Turner “Remote Serial Console HOWTO” http://www.tldp.org/HOWTO/Remote-Serial-Console-HOWTO/