timer_queue.c

説明を見る。
00001 /*
00002                Kernel AODV  v2.1
00003 National Institute of Standards and Technology
00004                Luke Klein-Berndt
00005 -----------------------------------------------------
00006   Version 2.1 new features:
00007      * Much more stable!
00008      * Added locks around important areas
00009      * Multihop Internet gatewaying now works
00010      * Multicast hack added
00011      * Many bug fixes!
00012 -----------------------------------------------------
00013 
00014 Originally based upon MadHoc code. I am not
00015 sure how much of it is left anymore, but MadHoc
00016 proved to be a great starting point.
00017 
00018 MadHoc was written by - Fredrik Lilieblad,
00019 Oskar Mattsson, Petra Nylund, Dan Ouchterlony
00020 and Anders Roxenhag Mail: mad-hoc@flyinglinux.net
00021 
00022 This software is Open Source under the GNU General Public Licence.
00023 
00024 */
00025 
00026 #include "timer_queue.h"
00027 /****************************************************
00028 
00029    timer_queue
00030 ----------------------------------------------------
00031 A queue of timed events
00032 ****************************************************/
00033 
00034 struct timer_list aodv_timer;
00035 
00036 struct timer_queue_entry *timer_queue=NULL;
00037 extern struct route_table_entry *g_my_entry;
00038 extern u_int32_t g_broadcast_ip;
00039 extern u_int32_t g_my_ip;
00040 rwlock_t timer_lock = RW_LOCK_UNLOCKED;
00041 unsigned long flags;
00042 
00043 void timer_read_lock()
00044 {
00045     read_lock_irqsave(&timer_lock,flags);
00046 }
00047 
00048 void timer_read_unlock()
00049 {
00050    read_unlock_irqrestore(&timer_lock,flags);
00051 }
00052 
00053 void timer_write_lock()
00054 {
00055   write_lock_irqsave(&timer_lock,flags);
00056 }
00057 
00058 void timer_write_unlock()
00059 {
00060   write_unlock_irqrestore(&timer_lock,flags);
00061 }
00062 
00063 
00064 
00065 /****************************************************
00066 
00067    read_timer_queue_proc
00068 ----------------------------------------------------
00069 Prints out the current queue into a buffer when
00070 ever the proc file its read
00071 ****************************************************/
00072 int read_timer_queue_proc(char *buffer, char **buffer_location, off_t offset, int buffer_length,int *eof,void *data)
00073 {
00074     struct timer_queue_entry *tmp;
00075 u_int64_t remainder, numerator;
00076     u_int64_t tmp_time;
00077     int len;
00078     static char *my_buffer;
00079     char temp_buffer[80];
00080 
00081 
00082     /* lock Read */
00083     timer_read_lock();
00084 
00085     my_buffer=buffer;
00086     sprintf(my_buffer,"\nTimer Queue\n---------------------------------\n");
00087 
00088     tmp = timer_queue;
00089 
00090     while (tmp != NULL)
00091     {
00092         tmp_time=tmp->tv-getcurrtime();
00093 
00094         //This is a fix for an error that occurs on ARM Linux Kernels because they do 64bits differently
00095         //Thanks to S. Peter Li for coming up with this fix!
00096         numerator = (tmp_time);
00097         remainder = do_div( numerator, 1000 );
00098         sprintf(temp_buffer,"sec/msec: %lu/%lu\t id:%s\t retries: %u\t ttl: %u\t Type: %d\n", (unsigned long)numerator, (unsigned long)remainder, inet_ntoa(tmp->id), tmp->retries, tmp->ttl,tmp->flags);
00099 
00100         strcat(my_buffer,temp_buffer);
00101         tmp = tmp->next;
00102     }
00103 
00104     sprintf(temp_buffer,"\n---------------------------------\n");
00105     strcat(my_buffer,temp_buffer);
00106 
00107     /* unlock Read */
00108     timer_read_unlock();
00109 
00110     len = strlen(my_buffer);
00111     if (len <= offset+buffer_length) *eof = 1;
00112     *buffer_location = my_buffer + offset;
00113     len -= offset;
00114     if (len>buffer_length) len = buffer_length;
00115     if (len<0) len = 0;
00116     return len;
00117 }
00118 
00119 
00120 
00121 /****************************************************
00122 
00123    print_timer
00124 ----------------------------------------------------
00125 prints the contents of the timer queue to the
00126 console screen
00127 ****************************************************/
00128 void print_timer_queue()
00129 {
00130     struct timer_queue_entry *tmp;
00131     u_int64_t tmp_time;
00132         u_int64_t remainder, numerator;
00133 
00134 
00135     tmp = timer_queue;
00136 
00137     while (tmp != NULL)
00138     {
00139         tmp_time=tmp->tv-getcurrtime();
00140 
00141         //This is a fix for an error that occurs on ARM Linux Kernels because they do 64bits differently
00142         //Thanks to S. Peter Li for coming up with this fix!
00143 
00144         numerator = tmp_time;
00145         remainder = do_div( numerator, 1000 );
00146         printk("sec/msec: %lu/%lu id:%lu size: %d retries: %u ttl: %u\n", (unsigned long)numerator, (unsigned long)remainder, (unsigned long)tmp->id, tmp->size, tmp->retries, tmp->ttl);
00147 
00148         tmp = tmp->next;
00149     }
00150 
00151 }
00152 
00153 
00154 /****************************************************
00155 
00156    timer_rreq
00157 ----------------------------------------------------
00158 Handles the resending of RREQ if a route
00159 reply is not recieved in a certian amount of time
00160 ****************************************************/
00161 int timer_rreq(struct timer_queue_entry *tmp_entry)
00162 {
00163     struct route_table_entry *tmp_route;
00164     struct rreq *tmp_rreq;
00165     u_int32_t rreq_id;
00166 
00167     tmp_rreq=tmp_entry->data;
00168 
00169     /* Check how may time we have sent it already */
00170     if (tmp_entry->retries >= RREQ_RETRIES)
00171     {
00172         /* Sent it maximum times */
00173 
00174         ipq_drop_ip(tmp_rreq->dst_ip);
00175         kfree(tmp_entry->data);
00176 
00177         /* Return error */
00178         return 0;
00179     }
00180     else
00181     {
00182         /* Increment nr of retries */
00183         tmp_entry->retries++;
00184 
00185         /* Check new TTL */
00186         if (tmp_entry->ttl > TTL_THRESHOLD)
00187             tmp_entry->ttl = NET_DIAMETER;
00188         else
00189             tmp_entry->ttl += TTL_INCREMENT;
00190 
00191 
00192         tmp_route = (find_interface_by_ip(tmp_rreq->src_ip))->route_entry;
00193   
00194         (tmp_route->rreq_id)++;
00195 
00196 
00197 
00198         tmp_rreq->rreq_id = htonl(tmp_route->rreq_id); // byte order problem discovered and fixed by Dinesh/ Manish
00199 
00200         if (insert_flood_id_queue_entry(tmp_rreq->src_ip, tmp_rreq->dst_ip,tmp_route->rreq_id,getcurrtime() + tmp_entry->ttl * 2 * NODE_TRAVERSAL_TIME ) <0)
00201           {
00202             printk(KERN_WARNING "AODV: Could not insert into broadcast list\n");
00203             kfree(tmp_entry->data);
00204 
00205             /* Couldn't add to broadcast list */
00206             return -ENOMEM;
00207           }
00208 
00209         /* Send packet again */
00210         local_broadcast( tmp_entry->ttl,tmp_rreq, tmp_entry->size);
00211 
00212 
00213 
00214 
00215         insert_timer_queue_entry(getcurrtime() + NET_TRAVERSAL_TIME, tmp_rreq,tmp_entry->size,tmp_rreq->dst_ip,tmp_entry->retries,tmp_entry->ttl, EVENT_RREQ);
00216 
00217 
00218 
00219     }
00220 
00221     return 0;
00222 }
00223 
00224 
00225 
00226 void timer_neighbor(struct timer_queue_entry *timer_entry)
00227 {
00228     struct neighbor_list_entry  *tmp_entry;
00229     struct route_table_entry *tmp_route;
00230 
00231     tmp_entry = find_neighbor_list_entry(timer_entry->id);
00232 
00233     if (tmp_entry!=NULL)
00234     {
00235         tmp_route=find_route_table_entry(tmp_entry->ip);
00236         if (tmp_route!=NULL)
00237         {
00238 
00239             //link_break(tmp_entry->ip);  we can't delete it directly because that would trigger an error because you are making changes to the route table on an interupt!!!
00240 
00241             tmp_route->lifetime=getcurrtime()-1;
00242             //insert_event_queue_entry(g_my_ip,g_my_ip,NULL,NULL,EVENT_CLEANUP,0,NULL,0);
00243             delete_neighbor_list_entry(tmp_entry->ip);
00244         }
00245     }
00246 }
00247 
00248 /****************************************************
00249 
00250    hello_resend
00251 ----------------------------------------------------
00252 Handles the resending of the Hello message and
00253 also places the hello message back on the
00254 queue so it will be called again
00255 ****************************************************/
00256 int hello_resend(struct timer_queue_entry *tmp_entry)
00257 {
00258     struct rrep *tmp_rrep;
00259     struct interface_list_entry *tmp_interface;
00260     u_int64_t curr_time=getcurrtime();
00261     u_int16_t random_number;
00262 
00263 
00264     tmp_rrep=tmp_entry->data;
00265 
00266     tmp_interface=find_interface_by_ip(tmp_rrep->dst_ip);
00267     if (tmp_interface==NULL)
00268     {
00269 
00270         printk(KERN_WARNING "AODV: HELLO error retrieveing interface\n");
00271         
00272         kfree(tmp_rrep);
00273         
00274         return 0;
00275     }
00276 
00277     tmp_rrep->dst_seq = htonl(tmp_interface->route_entry->dst_seq);
00278 
00279     local_broadcast(1,tmp_rrep, sizeof(struct rrep));
00280     /*    get_random_bytes(&random_number,sizeof(u_int16_t));
00281     random_number=random_number%20;
00282     */
00283     tmp_interface->last_hello=curr_time;
00284     insert_timer_queue_entry(tmp_entry->tv + HELLO_INTERVAL, tmp_rrep,tmp_entry->size,tmp_rrep->dst_ip,tmp_entry->retries,tmp_entry->ttl, EVENT_HELLO);
00285 
00286     return 0;
00287 }
00288 
00289 
00290 
00291 /****************************************************
00292 
00293    timer_cleanup
00294 ----------------------------------------------------
00295 Gets rid of everything in the timer queue.
00296 Should be called before you shutdown the module
00297 ****************************************************/
00298 void timer_cleanup()
00299 {
00300     insert_event_queue_entry(EVENT_CLEANUP,NULL);
00301     insert_timer_queue_entry(getcurrtime() + ACTIVE_ROUTE_TIMEOUT, NULL,0,g_my_ip,0,0, EVENT_CLEANUP);
00302 
00303 }
00304 
00305 /****************************************************
00306 
00307    init_timer_queue
00308 ----------------------------------------------------
00309 Initalizes the timer queue... duh!
00310 ****************************************************/
00311 int init_timer_queue()
00312 {
00313 
00314     init_timer(&aodv_timer);
00315     timer_queue=NULL;
00316     return 0;
00317 }
00318 
00319 /****************************************************
00320 
00321    update_timer_queue
00322 ----------------------------------------------------
00323 Sets the  system alarm for the first event in the
00324 timer queue
00325 ****************************************************/
00326 /*
00327 static unsigned long tvtojiffies(struct timeval *value)
00328 {
00329     unsigned long sec = (unsigned) value->tv_sec;
00330     unsigned long usec = (unsigned) value->tv_usec;
00331     u_int64_t numerator, numerator1;
00332 
00333 
00334         //This is a fix for an error that occurs on ARM Linux Kernels because they do 64bits differently
00335         //Thanks to S. Peter Li for coming up with this fix!
00336 
00337     numerator = ULONG_MAX;
00338     do_div( numerator, HZ );
00339     if (sec > (unsigned long) numerator)
00340         return ULONG_MAX;
00341 
00342     numerator = 1000000;
00343     do_div( numerator, HZ );
00344 
00345     usec += numerator - 1;
00346 
00347     numerator1 = usec;
00348     do_div( numerator1,  numerator );
00349     usec = numerator1;
00350 
00351     return HZ*sec+usec;
00352 }
00353 */
00354 
00355 static unsigned long tvtojiffies(struct timeval *value)
00356 {
00357         unsigned long sec = (unsigned) value->tv_sec;
00358         unsigned long usec = (unsigned) value->tv_usec;
00359 
00360         if (sec > (ULONG_MAX / HZ))
00361                 return ULONG_MAX;
00362         usec += 1000000 / HZ - 1;
00363         usec /= 1000000 / HZ;
00364         return HZ*sec+usec;
00365 }
00366 
00367 
00368 void update_timer_queue()
00369 {
00370     struct timeval delay_time;
00371     u_int64_t currtime;
00372     u_int64_t tv;
00373     u_int64_t remainder, numerator;
00374 
00375     delay_time.tv_sec = 0;
00376     delay_time.tv_usec = 0;
00377 
00378     /* lock Read */
00379     timer_read_lock();
00380   
00381     if (timer_queue == NULL)
00382     {
00383         // No event to set timer for
00384         delay_time.tv_sec = 0;
00385         delay_time.tv_usec = 0;
00386     }
00387     else
00388     {
00389         //* Get the first time value
00390         tv = timer_queue->tv;
00391 
00392         currtime = getcurrtime();
00393 
00394         if (tv <= currtime)
00395         {
00396             // If the event has allready happend, set the timeout to              1 microsecond :-)
00397 
00398 
00399             delay_time.tv_sec = 0;
00400             delay_time.tv_usec = 1;
00401         }
00402         else
00403         {
00404             // Set the timer to the actual seconds / microseconds from now
00405 
00406             //This is a fix for an error that occurs on ARM Linux Kernels because they do 64bits differently
00407         //Thanks to S. Peter Li for coming up with this fix!
00408 
00409           numerator = ( tv - currtime );
00410           remainder = do_div( numerator, 1000 );
00411 
00412             delay_time.tv_sec =  numerator;
00413             delay_time.tv_usec = remainder * 1000;
00414 
00415         }
00416 
00417     }
00418 
00419     if (!timer_pending(&aodv_timer))
00420     {
00421         aodv_timer.function=&timer_queue_signal;
00422         aodv_timer.expires=jiffies + tvtojiffies(&delay_time);
00423         add_timer(&aodv_timer);
00424     }
00425     else
00426     {
00427       mod_timer(&aodv_timer,jiffies + tvtojiffies(&delay_time));
00428     }
00429 
00430     /* lock Read */
00431     timer_read_unlock();
00432 
00433     // Set the timer (in real time)
00434     return;
00435 }
00436 
00437 
00438 
00439 /****************************************************
00440 
00441    timer_queue_signal
00442 ----------------------------------------------------
00443 Gets called when the system alarm goes off. The
00444 function then pulls the first queued event and
00445 acts on it
00446 ****************************************************/
00447 void timer_queue_signal()
00448 {
00449     struct timer_queue_entry *tmp_entry;
00450     u_int64_t currtime;
00451 
00452 
00453 
00454     // Get the first due entry in the queue /
00455     currtime = getcurrtime();
00456     tmp_entry = find_first_timer_queue_entry_due(currtime);
00457     // While there is still events that has timed out
00458 
00459     while (tmp_entry != NULL)
00460     {
00461         switch (tmp_entry->flags)
00462         {
00463         case EVENT_RREQ:
00464             timer_rreq(tmp_entry);
00465             break;
00466 
00467         case EVENT_HELLO:
00468             hello_resend(tmp_entry);
00469             break;
00470 
00471         case EVENT_CLEANUP:
00472             timer_cleanup();
00473             break;
00474 
00475         case EVENT_NEIGHBOR:
00476             timer_neighbor(tmp_entry);
00477             break;
00478 
00479         default:
00480             break;
00481         }
00482 
00483         // Dequeue the entry so that it will not happened again
00484         // delete_timer_queue_entry(tmp_entry);
00485         kfree(tmp_entry);
00486 
00487         // Get new time and check for more timedout entrys
00488         currtime = getcurrtime();
00489         tmp_entry = find_first_timer_queue_entry_due(currtime);
00490     }
00491     update_timer_queue();
00492 
00493 
00494 }
00495 
00496 
00497 /****************************************************
00498 
00499    insert_timer_queue_entry
00500 ----------------------------------------------------
00501 Insert an event into the queue. Also allocates
00502 enough room for the data and copies that too
00503 ****************************************************/
00504 int insert_timer_queue_entry(u_int64_t msec,void *data,int size,u_int32_t id,u_int16_t retries,u_int8_t ttl,unsigned char flags)
00505 {
00506     struct timer_queue_entry *prev_entry;
00507     struct timer_queue_entry *tmp_entry;
00508     struct timer_queue_entry *new_entry;
00509 
00510 
00511     // get memory
00512     if ((new_entry = kmalloc(sizeof(struct timer_queue_entry), GFP_ATOMIC)) == NULL)
00513     {
00514         printk(KERN_WARNING "AODV: Error allocating timer!\n");
00515 
00516         return -ENOMEM;
00517     }
00518 
00519     // copy data
00520     new_entry->tv = msec;
00521     new_entry->id = id;
00522     new_entry->flags = flags;
00523     new_entry->retries=retries;
00524     new_entry->ttl=ttl;
00525     new_entry->size=size;
00526     new_entry->data=data;
00527 
00528     prev_entry=NULL;
00529 
00530     /* lock Write */
00531     timer_write_lock();
00532 
00533 
00534     tmp_entry=timer_queue;
00535 
00536 
00537     while (tmp_entry!=NULL && new_entry->tv > tmp_entry ->tv)
00538     {
00539         prev_entry=tmp_entry;
00540         tmp_entry=tmp_entry->next;
00541     }
00542 
00543 
00544 
00545       if (timer_queue==tmp_entry)
00546         {
00547           new_entry->next=timer_queue;
00548           timer_queue=new_entry;
00549         }
00550       else
00551         {
00552           if (tmp_entry==NULL)  // If at the end of the List
00553             {
00554               new_entry->next=NULL;
00555               prev_entry->next=new_entry;
00556             }
00557           else     // Inserting in to the middle of the list somewhere
00558             {
00559               new_entry->next=prev_entry->next;
00560               prev_entry->next=new_entry;
00561             }
00562         }
00563 
00564     /* unlock Write */
00565     timer_write_unlock();
00566 
00567 
00568     // Update the timer to reflect the new situation
00569     //    update_timer_queue();
00570 
00571 
00572     return 0;
00573 }
00574 
00575 
00576 /****************************************************
00577 
00578    find_first_timer_queue_entry
00579 ----------------------------------------------------
00580 Returns the first entry in the timer queue
00581 ****************************************************/
00582 struct timer_queue_entry *find_first_timer_queue_entry()
00583 {
00584 
00585     return timer_queue;
00586 }
00587 
00588 
00589 /****************************************************
00590 
00591    find_first_timer_queue_entry_of_id
00592 ----------------------------------------------------
00593 Returns the first timer queue entry with a matching
00594 ID
00595 ****************************************************/
00596 struct timer_queue_entry * find_first_timer_queue_entry_of_id(u_int32_t id)
00597 {
00598     struct timer_queue_entry *tmp_entry;
00599 
00600     /* lock Read */
00601     timer_read_lock();
00602 
00603 
00604     tmp_entry=timer_queue;
00605 
00606     while (tmp_entry != NULL && tmp_entry->id != id)
00607         tmp_entry=tmp_entry->next;
00608 
00609     /* unlock Read */
00610     timer_read_unlock();
00611 
00612     return tmp_entry;
00613 }
00614 
00615 /****************************************************
00616 
00617    find_first_timer_queue_entry_of_id_and_flag
00618 ----------------------------------------------------
00619 Returns the first timer queue entry with a matching
00620 ID and flag
00621 ****************************************************/
00622 struct timer_queue_entry * find_first_timer_queue_entry_of_id_and_flag(u_int32_t id, unsigned char flags)
00623 {
00624     struct timer_queue_entry *tmp_entry;
00625 
00626     /* lock Read */
00627     timer_read_lock();
00628 
00629     tmp_entry=timer_queue;
00630 
00631 
00632     while (tmp_entry != NULL && tmp_entry->id != id && tmp_entry->flags!=flags)
00633         tmp_entry=tmp_entry->next;
00634 
00635     /* unlock Read */
00636     timer_read_unlock();
00637 
00638     return tmp_entry;
00639 }
00640 
00641 
00642 /****************************************************
00643 
00644    delete_timer_queue_entry_of_id
00645 ----------------------------------------------------
00646 Deletes the first entry with a matching id
00647 ****************************************************/
00648 void delete_timer_queue_entry_of_id(u_int32_t id, unsigned char flags)
00649 {
00650     struct timer_queue_entry *tmp_entry;
00651     struct timer_queue_entry *prev_entry;
00652     struct timer_queue_entry *dead_entry;
00653     int deleted=0;
00654 
00655     /* lock Write */
00656     timer_write_lock();
00657 
00658     tmp_entry=timer_queue;
00659     prev_entry=NULL;
00660 
00661     while (tmp_entry != NULL)
00662     {
00663         if (tmp_entry->id == id && tmp_entry->flags == flags)
00664         {
00665             if (prev_entry==NULL)
00666                 timer_queue=tmp_entry->next;
00667             else
00668                 prev_entry->next=tmp_entry->next;
00669 
00670             dead_entry=tmp_entry;
00671             tmp_entry=tmp_entry->next;
00672             kfree(dead_entry->data);
00673             kfree(dead_entry);
00674             deleted=1;
00675 
00676         }
00677         else
00678         {
00679             prev_entry=tmp_entry;
00680             tmp_entry=tmp_entry->next;
00681         }
00682     }
00683 
00684     //    if (!deleted)
00685     // printk(KERN_WARNING "Faild to delete %s  -  %d\n",inet_ntoa(id),flags);
00686     /* unlock Write */
00687     timer_write_unlock();
00688 
00689     update_timer_queue();
00690 }
00691 
00692 /****************************************************
00693 
00694    delete_timer_queue_entry
00695 ----------------------------------------------------
00696 Deletes the entry from the timer queue. You
00697 have to do this so the linked list is not broken
00698 ****************************************************/
00699 int delete_timer_queue_entry(struct timer_queue_entry *dead_entry)
00700 {
00701     struct timer_queue_entry *tmp_entry;
00702     struct timer_queue_entry *prev_entry;
00703     /* Is first element */
00704 
00705 
00706     /* lock Write */
00707     timer_write_lock();
00708 
00709     tmp_entry=timer_queue;
00710     prev_entry=NULL;
00711 
00712     while (tmp_entry!=NULL && tmp_entry!=dead_entry)
00713     {
00714         prev_entry=tmp_entry;
00715         tmp_entry=tmp_entry->next;
00716     }
00717     if (tmp_entry==NULL)
00718       {
00719         printk(KERN_WARNING "AODV: Could not find Timer Queue Entry to delete!\n");
00720         timer_write_unlock();
00721         return 1;
00722 
00723       }
00724     if (prev_entry==NULL)
00725         timer_queue=tmp_entry->next;
00726     else
00727         prev_entry->next=tmp_entry->next;
00728 
00729     //kfree(tmp_entry->data);
00730     kfree(tmp_entry);
00731 
00732     //update_timer_queue();
00733 
00734     /* unlock Write */
00735     timer_write_unlock();
00736 
00737     return 0;
00738 }
00739 
00740 
00741 /****************************************************
00742 
00743    remove_first_timer_queue_entry
00744 ----------------------------------------------------
00745 Removes the first timer queue entry
00746 ****************************************************/
00747 
00748 void remove_first_timer_queue_entry()
00749 {
00750     struct timer_queue_entry *dead_entry;
00751 
00752     /* lock Write */
00753     timer_write_lock();
00754 
00755     if (timer_queue!=NULL)
00756     {
00757         dead_entry=timer_queue;
00758         timer_queue=timer_queue->next;
00759         kfree(dead_entry);
00760     }
00761 
00762     /* unlock Write */
00763     timer_write_unlock();
00764 }
00765 
00766 /****************************************************
00767 
00768    find_first_timer_queue_entry_due
00769 ----------------------------------------------------
00770 Returns the first entry in the queue that has a time
00771 that is lower than the argument ie. the first element
00772 if the argument is greater than its tv value.
00773 ****************************************************/
00774 struct timer_queue_entry *find_first_timer_queue_entry_due(u_int64_t tv)
00775 {
00776     struct timer_queue_entry *tmp_entry;
00777 
00778 
00779     /* lock Read */
00780     timer_read_lock();
00781 
00782 
00783     if (timer_queue != NULL)
00784     {
00785         /* If pqe's time is in teh interval */
00786         if ((timer_queue->tv) < tv)
00787           {
00788             tmp_entry=timer_queue;
00789             timer_queue=timer_queue->next;
00790             return tmp_entry;
00791           }
00792     }
00793 
00794     /* unlock read */
00795     timer_read_unlock();
00796 
00797     return NULL;
00798 }

kernel_aodvmに対してThu Nov 10 18:53:11 2005に生成されました。  doxygen 1.4.5