Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

packets.c

Go to the documentation of this file.
00001 /*! \file packets.c
00002           This file contains the low level DHCP packet manipulation tools.
00003  */
00004 
00005 #include "packets.h"
00006 #include "modem.h"
00007 #include "flock.h"
00008 #include "dstring.h"
00009 #include <unistd.h>
00010 #include <time.h>
00011 
00012 
00013 static char* dater();
00014 static void get_remote_address (struct sockaddr_in *sender, char *ip, int *port);
00015 
00016 /*! \brief Order used to print standard oprions (other than option 82).
00017  */
00018 
00019 static int order[256] = {1, 3, 15, 6, 0, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255}; 
00020 
00021 /*! \brief This file descriptor is defined in the main server source (dhcp.c).
00022            It is used to synchronize access to the dump file.
00023  */
00024 
00025 extern int dump_sync_fd; 
00026 
00027 /* -------------------------------------------------------------------------- */
00028 /* DEBUG MANAGEMENT                                                           */
00029 /* -------------------------------------------------------------------------- */
00030 
00031 /*! \brief Debug flag. */
00032 
00033 static int debug = 0;
00034 
00035 /*! \brief Default value for the log file (an empty string).
00036  */
00037 
00038 static char default_log_file[] = "\0";
00039 
00040 /*! \brief Pointer to a given zero terminated string of characters that represents the path to the log file.
00041  */
00042 
00043 static char *log_file = default_log_file;
00044 
00045 /*! \brief This is a handler to a fake loggin service.
00046     \author Denis BEURIVE
00047  */
00048 
00049 static int my_fake_syslog (const char *file, const char * fmt,...) { return 0; }
00050 
00051 /*! \brief Logging service. by default it is assigned to the fake logging service that does nothing.
00052     \author Denis BEURIVE
00053  */
00054 
00055 static int (*my_syslog) (const char *file, const char * fmt,...) = my_fake_syslog;
00056 
00057 /*! \brief Assign a logging service to the packet module.
00058     \author Denis BEURIVE
00059     \param dbg Verbosity level.
00060     \param logfile Pointer to a zero terminated string of characters that represents the path to the log file.
00061     \param logger Pointer to a given logging service.
00062     \remark <UL>
00063               <LI>If 'logger' is set to NULL, then the logging service is not activated.
00064               <LI>If 'logfile' is set to NULL, then the logging service is not activated.
00065               <LI>If 'logfile' points to an empty string, then the logging service is not activated.
00066             </UL>
00067  */
00068 
00069 void packet_logging_service (int dbg,
00070                              char *logfile,
00071                              int (*logger) (const char *file, const char * fmt,...))
00072 {
00073   if ((logger != NULL) && (logfile != NULL))
00074   { if (logfile[0] != 0) { my_syslog = logger; log_file = logfile; } }
00075 
00076   debug = dbg;
00077 }
00078 
00079 /* -------------------------------------------------------------------------- */
00080 /* END OF DEBUG MANAGEMENT                                                    */
00081 /* -------------------------------------------------------------------------- */
00082 
00083 
00084 
00085 
00086 
00087 
00088 
00089 
00090 
00091 /*! \brief Buffer used to store the client hardware address (with ':' as separator between bytes).
00092  */
00093 
00094 static char chaddr[DHCP_P_STR_HADDR_SIZE];
00095 
00096 /*! \brief Buffer used to store the client hardware address (without separator between bytes).
00097  */
00098 
00099 static char chaddr_exact[DHCP_P_STR_HADDR_SIZE_EXACT];
00100 
00101 /*! \brief Buffer used to store the server names.
00102  */
00103 
00104 static char sname[DHCP_P_STR_SNAME_SIZE];
00105 
00106 /*! \brief Buffer used to store the boot file.
00107  */
00108 
00109 static char file[DHCP_P_STR_FILE_SIZE];
00110 
00111 /*! \brief Buffer used to store the host name.
00112  */
00113 
00114 static char myhostname[256];
00115 
00116 /*! \brief Initialize the dump service for DHCP packets.
00117     \remark The function MUSR be called before any call to packet_dump().
00118  */
00119 
00120 void packet_init_dump_service ()
00121 {
00122   memset ((void*)myhostname, 0, 256);
00123   gethostname (myhostname, 255);
00124 }
00125 
00126 /*! \brief This array contains the human readable description for all options.
00127  */
00128 
00129 static char* descriptions[256] =
00130 {
00131   /*   0 */   "Pad",
00132   /*   1 */   "Subnet Mask",
00133   /*   2 */   "Time Offset",
00134   /*   3 */   "Router",
00135   /*   4 */   "Time Server",
00136   /*   5 */   "Name Server",
00137   /*   6 */   "Domain Name Server",
00138   /*   7 */   "Log Server",
00139   /*   8 */   "Cookie Server",
00140   /*   9 */   "LPR Server",
00141   /*  10 */   "Impress Server",
00142   /*  11 */   "Resource Location Server",
00143   /*  12 */   "Host Name",
00144   /*  13 */   "Boot File Size",
00145   /*  14 */   "Merit Dump File",
00146   /*  15 */   "Domain Name",
00147   /*  16 */   "Swap Server",
00148   /*  17 */   "Root Path",
00149   /*  18 */   "Extensions Path",
00150   /*  19 */   "IP Forwarding Enable/Disable",
00151   /*  20 */   "Non-Local Source Routing Enable/Disable",
00152   /*  21 */   "Policy Filter",
00153   /*  22 */   "Maximum Datagram Reassembly Size",
00154   /*  23 */   "Default IP Time-to-live",
00155   /*  24 */   "Path MTU Aging Timeout",
00156   /*  25 */   "Path MTU Plateau Table",
00157   /*  26 */   "Interface MTU",
00158   /*  27 */   "All Subnets are Local",
00159   /*  28 */   "Broadcast Address",
00160   /*  29 */   "Perform Mask Discovery",
00161   /*  30 */   "Mask Supplier",
00162   /*  31 */   "Perform Router Discovery",
00163   /*  32 */   "Router Solicitation Address",
00164   /*  33 */   "Static Route",
00165   /*  34 */   "Trailer Encapsulation",
00166   /*  35 */   "ARP Cache Timeout",
00167   /*  36 */   "Ethernet Encapsulation",
00168   /*  37 */   "TCP Default TTL",
00169   /*  38 */   "TCP Keepalive Interval",
00170   /*  39 */   "TCP Keepalive Garbage",
00171   /*  40 */   "Network Information Service Domain",
00172   /*  41 */   "Network Information Servers",
00173   /*  42 */   "Network Time Protocol Servers",
00174   /*  43 */   "Vendor Specific Information",
00175   /*  44 */   "NetBIOS over TCP/IP Name Server",
00176   /*  45 */   "NetBIOS over TCP/IP Datagram Distribution Server",
00177   /*  46 */   "NetBIOS over TCP/IP Node Type",
00178   /*  47 */   "NetBIOS over TCP/IP Scope",
00179   /*  48 */   "X Window System Font Server",
00180   /*  49 */   "X Window System Display Manager",
00181   /*  50 */   "Requested IP Address",
00182   /*  51 */   "IP Address Lease Time",
00183   /*  52 */   "Option Overload",
00184   /*  53 */   "DHCP Message Type",
00185   /*  54 */   "Server Identifier",
00186   /*  55 */   "Parameter Request List",
00187   /*  56 */   "Message",
00188   /*  57 */   "Maximum DHCP Message Size",
00189   /*  58 */   "Renewal (T1) Time Value",
00190   /*  59 */   "Rebinding (T2) Time Value",
00191   /*  60 */   "Vendor class identifier",
00192   /*  61 */   "Client-identifier",
00193   /*  62 */   "TAG_NDS_IPDOMAIN",
00194   /*  63 */   "TAG_NDS_IPINFO",
00195   /*  64 */   "Network Information Service+ Domain",
00196   /*  65 */   "Network Information Service+ Servers",
00197   /*  66 */   "TFTP server name",
00198   /*  67 */   "Bootfile name",
00199   /*  68 */   "Mobile IP Home Agent",
00200   /*  69 */   "Simple Mail Transport Protocol (SMTP) Server",
00201   /*  70 */   "Post Office Protocol (POP3) Server",
00202   /*  71 */   "Network News Transport Protocol (NNTP) Server",
00203   /*  72 */   "Default World Wide Web (WWW) Server",
00204   /*  73 */   "Default Finger Server",
00205   /*  74 */   "Default Internet Relay Chat (IRC) Server",
00206   /*  75 */   "StreetTalk Server",
00207   /*  76 */   "StreetTalk Directory Assistance (STDA) Server",
00208   /*  77 */   "TAG_USER_CLASS",
00209   /*  78 */   "TAG_SLP_DA",
00210   /*  79 */   "TAG_SLP_SCOPE",
00211   /*  80 */   "TAG_SLP_NAMING_AUTH",
00212   /*  81 */   "TAG_CLIENT_FQDN",
00213   /*  82 */   "Agent Circuit ID",
00214   /*  83 */   "TAG_AGENT_REMOTE",
00215   /*  84 */   "TAG_AGENT_MASK",
00216   /*  85 */   "TAG_NDS_SERVERS",
00217   /*  86 */   "TAG_NDS_TREE_NAME",
00218   /*  87 */   "TAG_NDS_CONTEXT",
00219   /*  88 */   "TAG_TZ_STRING",
00220   /*  89 */   "TAG_FQDN_OPTION",
00221   /*  90 */   "TAG_AUTH",
00222   /*  91 */   "TAG_VINES_SERVERS",
00223   /*  92 */   "TAG_SERVER_RANK",
00224   /*  93 */   "TAG_CLIENT_ARCH",
00225   /*  94 */   "TAG_CLIENT_NDI",
00226   /*  95 */   "TAG_LDAP_URL",
00227   /*  96 */   "TAG_6OVER4",
00228   /*  97 */   "TAG_CLIENT_GUID",
00229   /*  98 */   "TAG_OPEN_GROUP_UAP",
00230   /*  99 */   "Unknown option",
00231   /* 100 */   "Printer Name",
00232   /* 101 */   "TAG_MDHCP_SERVER",
00233   /* 102 */   "Unknown option",
00234   /* 103 */   "Unknown option",
00235   /* 104 */   "Unknown option",
00236   /* 105 */   "Unknown option",
00237   /* 106 */   "Unknown option",
00238   /* 107 */   "Unknown option",
00239   /* 108 */   "Unknown option",
00240   /* 109 */   "Unknown option",
00241   /* 110 */   "TAG_IPX_COMPAT",
00242   /* 111 */   "Unknown option",
00243   /* 112 */   "TAG_NETINFO_PARENT",
00244   /* 113 */   "TAG_NETINFO_PARENT_TAG",
00245   /* 114 */   "TAG_URL",
00246   /* 115 */   "TAG_FAILOVER",
00247   /* 116 */   "TAG_DISABLE_AUTOCONF",
00248   /* 117 */   "TAG_NS_SEARCH",
00249   /* 118 */   "TAG_IP",
00250   /* 119 */   "Unknown option",
00251   /* 120 */   "Unknown option",
00252   /* 121 */   "Unknown option",
00253   /* 122 */   "Unknown option",
00254   /* 123 */   "Unknown option",
00255   /* 124 */   "Unknown option",
00256   /* 125 */   "Unknown option",
00257   /* 126 */   "TAG_EXTENDED_REQUEST",
00258   /* 127 */   "TAG_EXTENDED_OPTION",
00259   /* 128 */   "Unknown option",
00260   /* 129 */   "Unknown option",
00261   /* 130 */   "Unknown option",
00262   /* 131 */   "Unknown option",
00263   /* 132 */   "Unknown option",
00264   /* 133 */   "Unknown option",
00265   /* 134 */   "Unknown option",
00266   /* 135 */   "Unknown option",
00267   /* 136 */   "Unknown option",
00268   /* 137 */   "Unknown option",
00269   /* 138 */   "Unknown option",
00270   /* 139 */   "Unknown option",
00271   /* 140 */   "Unknown option",
00272   /* 141 */   "Unknown option",
00273   /* 142 */   "Unknown option",
00274   /* 143 */   "Unknown option",
00275   /* 144 */   "Unknown option",
00276   /* 145 */   "Unknown option",
00277   /* 146 */   "Unknown option",
00278   /* 147 */   "Unknown option",
00279   /* 148 */   "Unknown option",
00280   /* 149 */   "Unknown option",
00281   /* 150 */   "Unknown option",
00282   /* 151 */   "Unknown option",
00283   /* 152 */   "Unknown option",
00284   /* 153 */   "Unknown option",
00285   /* 154 */   "Unknown option",
00286   /* 155 */   "Unknown option",
00287   /* 156 */   "Unknown option",
00288   /* 157 */   "Unknown option",
00289   /* 158 */   "Unknown option",
00290   /* 159 */   "Unknown option",
00291   /* 160 */   "Unknown option",
00292   /* 161 */   "Unknown option",
00293   /* 162 */   "Unknown option",
00294   /* 163 */   "Unknown option",
00295   /* 164 */   "Unknown option",
00296   /* 165 */   "Unknown option",
00297   /* 166 */   "Unknown option",
00298   /* 167 */   "Unknown option",
00299   /* 168 */   "Unknown option",
00300   /* 169 */   "Unknown option",
00301   /* 170 */   "Unknown option",
00302   /* 171 */   "Unknown option",
00303   /* 172 */   "Unknown option",
00304   /* 173 */   "Unknown option",
00305   /* 174 */   "Unknown option",
00306   /* 175 */   "Unknown option",
00307   /* 176 */   "Unknown option",
00308   /* 177 */   "Unknown option",
00309   /* 178 */   "Unknown option",
00310   /* 179 */   "Unknown option",
00311   /* 180 */   "Unknown option",
00312   /* 181 */   "Unknown option",
00313   /* 182 */   "Unknown option",
00314   /* 183 */   "Unknown option",
00315   /* 184 */   "Unknown option",
00316   /* 185 */   "Unknown option",
00317   /* 186 */   "Unknown option",
00318   /* 187 */   "Unknown option",
00319   /* 188 */   "Unknown option",
00320   /* 189 */   "Unknown option",
00321   /* 190 */   "Unknown option",
00322   /* 191 */   "Unknown option",
00323   /* 192 */   "Unknown option",
00324   /* 193 */   "Unknown option",
00325   /* 194 */   "Unknown option",
00326   /* 195 */   "Unknown option",
00327   /* 196 */   "Unknown option",
00328   /* 197 */   "Unknown option",
00329   /* 198 */   "Unknown option",
00330   /* 199 */   "Unknown option",
00331   /* 200 */   "Unknown option",
00332   /* 201 */   "Unknown option",
00333   /* 202 */   "Unknown option",
00334   /* 203 */   "Unknown option",
00335   /* 204 */   "Unknown option",
00336   /* 205 */   "Unknown option",
00337   /* 206 */   "Unknown option",
00338   /* 207 */   "Unknown option",
00339   /* 208 */   "Unknown option",
00340   /* 209 */   "Unknown option",
00341   /* 210 */   "Unknown option",
00342   /* 211 */   "Unknown option",
00343   /* 212 */   "Unknown option",
00344   /* 213 */   "Unknown option",
00345   /* 214 */   "Unknown option",
00346   /* 215 */   "Unknown option",
00347   /* 216 */   "Unknown option",
00348   /* 217 */   "Unknown option",
00349   /* 218 */   "Unknown option",
00350   /* 219 */   "Unknown option",
00351   /* 220 */   "Unknown option",
00352   /* 221 */   "Unknown option",
00353   /* 222 */   "Unknown option",
00354   /* 223 */   "Unknown option",
00355   /* 224 */   "Unknown option",
00356   /* 225 */   "Unknown option",
00357   /* 226 */   "Unknown option",
00358   /* 227 */   "Unknown option",
00359   /* 228 */   "Unknown option",
00360   /* 229 */   "Unknown option",
00361   /* 230 */   "Unknown option",
00362   /* 231 */   "Unknown option",
00363   /* 232 */   "Unknown option",
00364   /* 233 */   "Unknown option",
00365   /* 234 */   "Unknown option",
00366   /* 235 */   "Unknown option",
00367   /* 236 */   "Unknown option",
00368   /* 237 */   "Unknown option",
00369   /* 238 */   "Unknown option",
00370   /* 239 */   "Unknown option",
00371   /* 240 */   "Unknown option",
00372   /* 241 */   "Unknown option",
00373   /* 242 */   "Unknown option",
00374   /* 243 */   "Unknown option",
00375   /* 244 */   "Unknown option",
00376   /* 245 */   "Unknown option",
00377   /* 246 */   "Unknown option",
00378   /* 247 */   "Unknown option",
00379   /* 248 */   "Unknown option",
00380   /* 249 */   "Unknown option",
00381   /* 250 */   "Unknown option",
00382   /* 251 */   "Unknown option",
00383   /* 252 */   "Unknown option",
00384   /* 253 */   "Unknown option",
00385   /* 254 */   "Unknown option",
00386   /* 255 */   "End",
00387 };
00388 
00389 
00390 /***** BEGIN CODE *****/
00391 
00392 
00393 /* -------------------------------------------------------------- */
00394 /* Packet's initialisation                                        */
00395 /* -------------------------------------------------------------- */
00396 
00397 
00398 /*! \brief Returns a string that describes the type of DHCP packet.
00399     \author Denis BEURIVE
00400     \param type Value of the option 53 (DHCP Message Type).
00401     \return The function returns a pointer to a zero terminated string that represents the type of the packet.
00402     \warning The string is returned in a statically allocated buffer, which subsequent calls will overwrit. Do not try to free it!
00403  */
00404 
00405 char* packets_type_to_char (int type)
00406 {
00407   static char DHCPDISCOVER_S[] = "DHCPDISCOVER";
00408   static char DHCPOFFER_S[]    = "DHCPOFFER"; 
00409   static char DHCPREQUEST_S[]  = "DHCPREQUEST";
00410   static char DHCPDECLINE_S[]  = "DHCPDECLINE";
00411   static char DHCPACK_S[]      = "DHCPACK";
00412   static char DHCPNAK_S[]      = "DHCPNAK";
00413   static char DHCPRELEASE_S[]  = "DHCPRELEASE";
00414   static char DHCPINFORM_S[]   = "DHCPINFORM";
00415   static char DEFAULT_S[]      = "Unknown type";
00416 
00417   switch (type)
00418   {
00419     case DHCPDISCOVER: return DHCPDISCOVER_S;  
00420     case DHCPOFFER:    return DHCPOFFER_S; 
00421     case DHCPREQUEST:  return DHCPREQUEST_S;
00422     case DHCPDECLINE:  return DHCPDECLINE_S;
00423     case DHCPACK:      return DHCPACK_S;
00424     case DHCPNAK:      return DHCPNAK_S;
00425     case DHCPRELEASE:  return DHCPRELEASE_S;
00426     case DHCPINFORM:   return DHCPINFORM_S;
00427     default:           return DEFAULT_S;
00428   }
00429 
00430   return DEFAULT_S;
00431 }
00432 
00433 /*! \brief Initialize the packet's data before writing options.
00434     \author Denis BEURIVE
00435     \param p Pointer to the packet to initialize.
00436     \warning You must always call this function before calling packets_set_option().
00437              Once you have set all the options you want to set, then you must call packets_close_option().
00438              The shema is:
00439              <UL>
00440                 <LI>Call packets_init_option_writer(). Note that packets_clear() calls packets_init_option_writer(). 
00441                 <LI>Call packets_set_option() for all options you want to set.
00442                 <LI>Call packets_close_option().
00443              </UL>
00444  */
00445 
00446 void packets_init_option_writer (struct dhcp_packet *p)
00447 {
00448   (p->ctrl).opt_pointer = p->options;
00449 
00450   *((p->ctrl).opt_pointer) = 99;    (p->ctrl).opt_pointer += 1;
00451   *((p->ctrl).opt_pointer) = 130;   (p->ctrl).opt_pointer += 1;
00452   *((p->ctrl).opt_pointer) = 83;    (p->ctrl).opt_pointer += 1;
00453   *((p->ctrl).opt_pointer) = 99;    (p->ctrl).opt_pointer += 1;
00454 
00455   /* 236 fixed bytes + the magic number */
00456 
00457   (p->ctrl).taille = 236+4;
00458 }
00459 
00460 /*! \brief Initialize the packet's data before reading options.
00461     \author Denis BEURIVE
00462     \param p Pointer to the packet to initialize.
00463     \warning You must always call this function before calling packets_parse_options(). Note that packets_clear() calls
00464              packets_init_option_reader().
00465  */
00466 
00467 void packets_init_option_reader (struct dhcp_packet *p)
00468 {
00469   int i;
00470 
00471   /* We skip the 4 bytes reserved for the magic number */
00472 
00473   (p->ctrl).opt_pointer_reader = p->options + 4;
00474 
00475   for (i=0; i<256; i++)
00476   {
00477     ((p->ctrl).list[i]).code = 0;
00478     ((p->ctrl).list[i]).len  = 0;
00479     memset ((void*)((p->ctrl).list[i]).value, 0, VALUE_MAX_SIZE);
00480   }
00481 
00482   memset ((void*)(&((p->ctrl).dslam_data)), 0, sizeof(struct dhcp82));
00483 }
00484 
00485 /*! \brief Clear the content of a packet and intialize it for read/write option.
00486     \author Denis BEURIVE
00487     \param p Pointer to the packet to clear.
00488  */
00489 
00490 void packets_clear (struct dhcp_packet *p)
00491 {
00492   memset ((void*)p, 0, PACKET_SIZE);
00493   packets_init_option_writer (p);     /* Set the minimum size of the packet (and do other things)        */
00494   packets_init_option_reader (p);     /* Set access pointer to begining of options (and do other things) */
00495 }
00496 
00497 /*! \brief Clear the option's part of a given packet.
00498     \author Denis BEURIVE
00499     \param p Pointer to the packet that you want to clear the option's part.
00500  */
00501 
00502 void packets_options_clear (struct dhcp_packet *p) { memset ((void*)(p->options), 0, OPTION_SIZE); }
00503 
00504 
00505 
00506 
00507 /* -------------------------------------------------------------- */
00508 /* Setter and getter methods                                      */
00509 /* -------------------------------------------------------------- */
00510 
00511 
00512 /*! \brief Set the packet's opcode.
00513     \author Denis BEURIVE
00514     \param p Pointer to the packet.
00515     \param op Valur of the opcode (should be 1 or 2).
00516  */
00517 
00518 void packets_set_op (struct dhcp_packet *p, int op) { p->op = ((unsigned char)op) & 0x000000FF; }
00519 
00520 /*! \brief Get the packet's opcode.
00521     \author Denis BEURIVE
00522     \param p Pointer to the packet.
00523     \return The function returns the packet's opcode.
00524  */
00525 
00526 unsigned char packets_get_op (struct dhcp_packet *p) { return p->op; }
00527 
00528 /*! \brief Set the type of hardware address (field 'htype').
00529     \author Denis BEURIVE
00530     \param p Pointer to the packet.
00531     \param htype Value that represents the type of hardware address.
00532  */
00533 
00534 void packets_set_htype (struct dhcp_packet *p, int htype) { p->htype = ((unsigned char)htype) & 0x000000FF; }
00535 
00536 /*! \brief Get the type of hardware address (field 'htype').
00537     \author Denis BEURIVE
00538     \param p Pointer to the packet.
00539     \return The function returns the type of hardware address (field 'htype').
00540  */
00541 
00542 unsigned char packets_get_htype (struct dhcp_packet *p) { return p->htype; }
00543 
00544 /*! \brief Set the length of the binary representation of the hardware address (field 'hlen').
00545     \author Denis BEURIVE
00546     \param p Pointer to the packet.
00547     \param hlen Lenght, in bytes, of the binary representation of the hardware address.
00548  */
00549 
00550 void packets_set_hlen (struct dhcp_packet *p, int hlen) { p->hlen = ((unsigned char)hlen) & 0x000000FF; }
00551 
00552 /*! \brief Get the length of the binary representation of the hardware address (field 'hlen').
00553     \author Denis BEURIVE
00554     \param p Pointer to the packet.
00555     \return The function returns the length of the binary representation of the hardware address (field 'hlen').
00556  */
00557 
00558 unsigned char packets_get_hlen (struct dhcp_packet *p) { return p->hlen; }
00559 
00560 /*! \brief Set the number of hops (field 'hops').
00561     \author Denis BEURIVE
00562     \param p Pointer to the packet.
00563     \param hops Number of hops.
00564  */
00565 
00566 void packets_set_hops (struct dhcp_packet *p, int hops) { p->hops = ((unsigned char)hops) & 0x000000FF; }
00567 
00568 /*! \brief Get the number of hops (field 'hops').
00569     \author Denis BEURIVE
00570     \param p Pointer to the packet.
00571     \return The function returns the number of hops (field 'hops').
00572  */
00573 
00574 unsigned char packets_get_hops (struct dhcp_packet *p) { return p->hops; }
00575 
00576 /*! \brief Set the transaction ID (field 'xid').
00577     \author Denis BEURIVE
00578     \param p Pointer to the packet.
00579     \param xid Transaction ID.
00580  */
00581 
00582 void packets_set_xid (struct dhcp_packet *p, unsigned long int xid) { p->xid = htonl(xid); } 
00583 
00584 /*! \brief Get the transaction ID (field 'xid'.
00585     \author Denis BEURIVE
00586     \param p Pointer to the packet.
00587     \return The function returns the transaction ID (field 'xid').
00588  */
00589 
00590 unsigned long int packets_get_xid (struct dhcp_packet *p) { return ntohl(p->xid); }
00591 
00592 /*! \brief Set the number of seconds (field 'secs').
00593     \author Denis BEURIVE
00594     \param p Pointer to the packet.
00595     \param secs Number of seconds.
00596  */ 
00597 
00598 void packets_set_secs (struct dhcp_packet *p, unsigned short int secs) { p->secs =  htons(secs); }
00599 
00600 /*! \brief Get the number of seconds (field 'secs').
00601     \author Denis BEURIVE
00602     \param p Pointer to the packet.
00603     \return The function returns the number of seconds (field 'secs').
00604  */
00605 
00606 unsigned short int packets_get_secs (struct dhcp_packet *p) { return ntohs (p->secs); }
00607 
00608 /*! \brief Set the packet's flags (field (flags').
00609     \author Denis BEURIVE
00610     \param p Pointer to the packet.
00611     \param flags Flags.
00612  */
00613 
00614 void packets_set_flags (struct dhcp_packet *p, unsigned short int flags) { p->flags = htons(flags); }
00615 
00616 /*! \brief Get the packet's flags (field (flags').
00617     \author Denis BEURIVE
00618     \param p Pointer to the packet.
00619     \return The function returns the packet's flags (field (flags').
00620  */
00621 
00622 unsigned short int packets_get_flags (struct dhcp_packet *p) { return htons(p->flags); }
00623 
00624 /*! \brief Set the client's IP address (field 'ciaddr').
00625     \author Denis BEURIVE
00626     \param p Pointer to the packet.
00627     \param ciaddr Pointer to a zero terminated string of characters that represents the IP address of the client in
00628                   standard numbers-and-dots notation.
00629     \return If the IP address is valid, the function returns the value 0. Otherwize, the function returns the value 1.
00630  */
00631 
00632 int packets_set_ciaddr (struct dhcp_packet *p, char *ciaddr) 
00633 {
00634   struct in_addr inp;
00635   int    rc;
00636 
00637   rc = inet_aton (ciaddr, &inp);
00638   if (rc == 0) { return 1; }
00639   p->ciaddr = inp.s_addr;
00640   return 0;
00641 }
00642 
00643 /*! \brief Set the client's IP address (field 'ciaddr'). The field 'ciaddr' is given as an unsigned long integer in network byte order.
00644     \author Denis BEURIVE
00645     \param p Pointer to the packet.
00646     \param ciaddr IP address of the client in RAW format (4 bytes in network byte order).
00647  */
00648 
00649 void packets_set_bin_ciaddr (struct dhcp_packet *p, unsigned long int ciaddr)
00650 { p->ciaddr = ciaddr; }
00651 
00652 
00653 /*! \brief Get the client's IP address (field 'ciaddr').
00654     \author Denis BEURIVE
00655     \param p Pointer to the packet.
00656     \return The function return a pointer to a zero terminated string of characters that represents the IP address of the client
00657             in standard numbers-and-dots notation.
00658     \warning The string is returned in a statically allocated buffer, which subsequent calls will overwrite. Do not try to free it!
00659  */
00660 
00661 char* packets_get_ciaddr (struct dhcp_packet *p)
00662 {
00663   struct in_addr   inp;
00664   static char      ip[16];
00665   
00666   inp.s_addr = p->ciaddr;
00667   memset ((void*)ip, 0, 16);
00668   strncpy (ip, inet_ntoa(inp), 15);
00669   return ip;
00670 }
00671 
00672 /*! \brief Get the client's IP address (field 'ciaddr') as a 4 bytes integer in network byte order.
00673     \author Denis BEURIVE
00674     \param p Pointer to the packet.
00675     \return The function returns a 4 bytes long integer in network byte order that represents thet IP address (field 'ciaddr').
00676  */
00677 
00678 unsigned long int packets_get_bin_ciaddr (struct dhcp_packet *p)
00679 { return p->ciaddr; }
00680 
00681 /*! \brief Set the field 'Your IP address' (field 'yiaddr').
00682     \author Denis BEURIVE
00683     \param p Pointer to the packet.
00684     \param yiaddr Pointer to a zero terminated string of characters that represents the IP address in
00685                   standard numbers-and-dots notation.
00686     \return If the IP address is valid, the function returns the value 0. Otherwize, the function returns the value 1.
00687  */
00688 
00689 int packets_set_yiaddr (struct dhcp_packet *p, char *yiaddr)
00690 {
00691   struct in_addr inp;
00692   int    rc;
00693 
00694   rc = inet_aton (yiaddr, &inp);
00695   if (rc == 0) { return 1; }
00696   p->yiaddr = inp.s_addr;
00697   return 0;
00698 }
00699 
00700 /*! \brief Get the field 'yiaddr' ("Your IP address").
00701     \author Denis BEURIVE
00702     \param p Pointer to the packet.
00703     \return The function returns a pointer to a zero terminated string of characters that represents the IP address
00704             in standard numbers-and-dots notation.
00705     \warning The string is returned in a statically allocated buffer, which subsequent calls will overwrite. Do not try to free it!
00706  */
00707 
00708 char* packets_get_yiaddr (struct dhcp_packet *p)
00709 {
00710   struct in_addr inp;
00711   static char    ip[16];
00712 
00713   inp.s_addr = p->yiaddr;
00714   memset ((void*)ip, 0, 16);
00715   strncpy (ip, inet_ntoa(inp), 15);
00716   return ip;
00717 }
00718 
00719 /*! \brief Set the server IP address (field 'siaddr).
00720     \author Denis BEURIVE
00721     \param p Pointer to the packet.
00722     \param siaddr Pointer to a zero terminated string of characters that represents the IP address in standard numbers-and-dots notation.
00723     \return If the IP address is valid, the function returns the value 0. Otherwize, the function returns the value 1.
00724  */
00725 
00726 int packets_set_siaddr (struct dhcp_packet *p, char *siaddr)
00727 {
00728   struct in_addr inp;
00729   int    rc;
00730 
00731   rc = inet_aton (siaddr, &inp);
00732   if (rc == 0) { return 1; }
00733   p->siaddr = inp.s_addr;
00734   return 0;
00735 }
00736 
00737 /*! \brief Get the server IP address (field 'siaddr).
00738     \author Denis BEURIVE
00739     \param p Pointer to the packet.
00740     \return The function returns a pointer to a zero terminated string of characters that represents the IP address
00741             in standard numbers-and-dots notation.
00742     \warning The string is returned in a statically allocated buffer, which subsequent calls will overwrite. Do not try to free it!
00743  */
00744 
00745 char* packets_get_siaddr (struct dhcp_packet *p)
00746 {
00747   struct in_addr inp;
00748   static char    ip[16];
00749 
00750   inp.s_addr = p->siaddr;
00751   memset ((void*)ip, 0, 16);
00752   strncpy (ip, inet_ntoa(inp), 15);
00753   return ip;
00754 }
00755 
00756 /*! \brief Set the gateway IP address (field 'giaddr').
00757     \author Denis BEURIVE
00758     \param p Pointer to the packet.
00759     \param giaddr Pointer to a zero terminated string of characters that represents the IP address in standard numbers-and-dots notation.
00760     \return If the IP address is valid, the function returns the value 0. Otherwize, the function returns the value 1.
00761  */
00762 
00763 int packets_set_giaddr (struct dhcp_packet *p, char *giaddr)
00764 {
00765   struct in_addr inp;
00766   int    rc;
00767 
00768   rc = inet_aton (giaddr, &inp);
00769   if (rc == 0) { return 1; }
00770   p->giaddr = inp.s_addr;
00771   return 0;
00772 }
00773 
00774 /*! \brief Set the gateway IP address (field 'giaddr'). The IP address is given as 4 bytes entity in network byte order.
00775     \author Denis BEURIVE
00776     \param p Pointer to the packet.
00777     \param giaddr 4 bytes in network byte order that represents an IP address. 
00778  */
00779 
00780 void packets_set_bin_giaddr (struct dhcp_packet *p, unsigned long int giaddr)
00781 { p->giaddr = giaddr; }
00782 
00783 /*! \brief Get the gateway IP address (field 'giaddr').
00784     \author Denis BEURIVE
00785     \param p Pointer to the packet.
00786     \return The function returns a pointer to a zero terminated string of characters that represents the
00787             IP address in standard numbers-and-dots notation.
00788     \warning The string is returned in a statically allocated buffer, which subsequent calls will overwrite. Do not try to free it!
00789  */
00790 
00791 char* packets_get_giaddr (struct dhcp_packet *p)
00792 {
00793   struct in_addr inp;
00794   static char    ip[16];
00795 
00796   inp.s_addr = p->giaddr;
00797   memset ((void*)ip, 0, 16);
00798   strncpy (ip, inet_ntoa(inp), 15);
00799   return ip;
00800 }
00801 
00802 /*! \brief Get the gateway IP address (field 'giaddr'). IP address is returned as a 4 bytes integer in network byte order.
00803     \author Denis BEURIVE
00804     \param p Pointer to the packet.
00805     \return The function returns the IP address that represents the field 'giaddr'.
00806  */ 
00807 
00808 unsigned long int packets_get_bin_giaddr (struct dhcp_packet *p)
00809 { return p->giaddr; } 
00810 
00811 /*! \brief Set the client hardware address (field 'chaddr').
00812     \author Denis BEURIVE
00813     \param p Pointer to the packet.
00814     \param chaddr Pointer to 16 bytes long buffer that represents the binary representation of the client's hardware address.
00815     \warning If the client hardware address is only 6 bytes long, the 10 last bytes must be set to 0.
00816  */
00817 
00818 void packets_set_chaddr (struct dhcp_packet *p, char *chaddr) { memcpy ((void*)p->chaddr, (void*)chaddr, 16); }
00819 
00820 /*! \brief Get the client hardware address (field 'chaddr').
00821     \author Denis BEURIVE
00822     \param p Pointer to the packet.
00823     \return The function returns a zero terminated string of characters that represents the hardware address of
00824             the client in standard ':' notation.
00825     \warning The string is returned in a statically allocated buffer,
00826              which subsequent calls will overwrite. Do not try to free it!
00827  */ 
00828 
00829 char* packets_get_chaddr (struct dhcp_packet *p)
00830 {
00831   int  len, i, pp;
00832   char *c;
00833 
00834   len = ((int)packets_get_hlen(p)) & 0x000000FF;
00835   c   = p->chaddr;
00836   pp  = 0;
00837 
00838   if (len > 16) { len = 16; }
00839 
00840   memset ((void*)chaddr, 0, DHCP_P_STR_HADDR_SIZE);
00841 
00842   for (i=0; i<len; i++)
00843   {
00844     chaddr[pp++] = int_to_char (((*c) & 0xF0) >> 4);
00845     chaddr[pp++] = int_to_char ((*c) & 0x0F);
00846     c += 1;
00847     if (i < len-1) { chaddr[pp++] = ':'; }
00848   }
00849 
00850   return chaddr;
00851 }
00852 
00853 /*! \brief Return a literal representation of the client hardware address. 
00854            This function is identical to the function packets_get_chaddr(), except that the returned string
00855            does not contain ':'.
00856     \author Denis BEURIVE
00857     \param p Pointer to the packet.
00858     \return The function returns a zero terminated string of characters that represents the hardware address of
00859             the client.
00860     \warning The string is returned in a statically allocated buffer,                                                         which subsequent calls will overwrite. Do not try to free it!
00861  */
00862 
00863 char* packets_get_chaddr_no_separator (struct dhcp_packet *p)
00864 {
00865   int  len, i, pp;
00866   char *c;
00867 
00868   len = ((int)packets_get_hlen(p)) & 0x000000FF;
00869   c   = p->chaddr;
00870   pp  = 0;
00871 
00872   if (len > 16) { len = 16; }
00873 
00874   memset ((void*)chaddr_exact, 0, DHCP_P_STR_HADDR_SIZE_EXACT);
00875 
00876   for (i=0; i<len; i++)
00877   {
00878     chaddr_exact[pp++] = int_to_char (((*c) & 0xF0) >> 4);
00879     chaddr_exact[pp++] = int_to_char ((*c) & 0x0F);
00880     c += 1;
00881   }
00882 
00883   return chaddr_exact;
00884 } 
00885 
00886 /*! \brief Get the client hardware address (field 'chaddr'). The hardware address is returned as RAW buffer.
00887     \author Denis BEURIVE
00888     \param p Pointer to the packet.
00889     \warning The RAW buffer is returned in a statically allocated buffer that points to the
00890              packet's data pointed by 'p'! Do <B>NOT</B> modify it!.
00891  */
00892 
00893 char* packets_get_bin_chaddr (struct dhcp_packet *p)
00894 { return p->chaddr; }
00895 
00896 /*! \brief Set the server name (field 'sname').
00897     \author Denis BEURIVE
00898     \param p Pointer to the packet.
00899     \param sname Pointer to a sero terminated string that represents the name of the server.
00900  */
00901 
00902 void packets_set_sname (struct dhcp_packet *p, char *sname) { strncpy (p->sname, sname, DHCP_P_STR_SNAME_SIZE-1); }
00903 
00904 /*! \brief Get the server name (field 'sname').
00905     \author Denis BEURIVE
00906     \param p Pointer to the packet.
00907     \return The function returns a zero terminated string of characters that represents name of the server.
00908     \warning The string is returned in a statically allocated buffer, which subsequent calls will overwrite. Do not try to free it!
00909  */
00910 
00911 char* packets_get_sname (struct dhcp_packet *p)
00912 {
00913   memset ((void*)sname, 0, DHCP_P_STR_SNAME_SIZE);
00914   strncpy (sname, p->sname, DHCP_P_STR_SNAME_SIZE-1);
00915   return sname;
00916 }
00917 
00918 /*! \brief Set the boot file (field 'file').
00919     \author Denis BEURIVE
00920     \param p Pointer to the packet.
00921     \param file Pointer to a zero terminated string that represents the path to the boot file.
00922  */
00923 
00924 void packets_set_file (struct dhcp_packet *p, char *file) { strncpy (p->file, file, DHCP_P_STR_FILE_SIZE-1); }
00925 
00926 /*! \brief Get the path to the boot file (field 'file').
00927     \author Denis BEURIVE
00928     \param p Pointer to the packet.
00929     \return The function returns a zero terminated string of characters that represents the pat to the boot file.
00930     \warning The string is returned in a statically allocated buffer, which subsequent calls will overwrite. Do not try to free it!
00931  */
00932 
00933 char* packets_get_file (struct dhcp_packet *p)
00934 {
00935   memset ((void*)file, 0, DHCP_P_STR_FILE_SIZE);
00936   strncpy (file, p->file, DHCP_P_STR_FILE_SIZE-1);
00937   return file;
00938 }
00939 
00940 /*! \brief Set a given DHCP option.
00941     \author Denis BEURIVE
00942     \param p Pointer to the packet.
00943     \param option Option's code (from 1 to 254 included).
00944     \param value Pointer to a buffer that contains tha binary representation of the option's value.
00945     \param len Number of bytes for the buffer pointed by 'value'.
00946     \return Upon successful completion, the function returns the value 0. Otherwize, it returns the value 1.
00947     \warning You must call packets_init_option_writer() before! The proper way to operate is:
00948              <UL>
00949                <LI>Call packets_init_option_writer().
00950                <LI>Call packets_set_option() for all options you wan to set.
00951                <LI>Call packets_close_option().
00952              </UL>
00953  */
00954 
00955 int packets_set_option (struct dhcp_packet *p, unsigned char option, char *value, int len)
00956 {
00957   int i;
00958 
00959   if (len > VALUE_MAX_SIZE) { return 1; }
00960 
00961   *((p->ctrl).opt_pointer) = option;                     (p->ctrl).opt_pointer += 1;
00962   *((p->ctrl).opt_pointer) = ((char)len) & 0x000000FF;   (p->ctrl).opt_pointer += 1;
00963   (p->ctrl).taille += 2;
00964 
00965   for (i=0; i<len; i++)
00966   {
00967     *((p->ctrl).opt_pointer) = *(value + i);
00968     (p->ctrl).opt_pointer += 1;
00969     (p->ctrl).taille      += 1;
00970   }
00971 
00972   return 0;
00973 }
00974 
00975 /*! \brief Terminate the option's part cleanly.
00976     \author Denis BEURIVE
00977     \param p Pointer to the packet.
00978     \warning You MUST call this function when you don't need to write any more option.
00979              The proper way to operate is:
00980     \warning You must call packets_init_option_writer() before! The proper way to operate is:
00981              <UL>
00982                <LI>Call packets_init_option_writer().
00983                <LI>Call packets_set_option() for all options you wan to set.
00984                <LI>Call packets_close_option().
00985              </UL>
00986  */
00987 
00988 void packets_close_option (struct dhcp_packet *p)
00989 {
00990    *((p->ctrl).opt_pointer)  = 0xFF;
00991    (p->ctrl).taille         += 1;
00992 }
00993 
00994 /*! \brief Read options from a given packet.
00995     \author Denis BEURIVE
00996     \param p Pointer to the packet.
00997     \return Upon successful completion, the function returns the value 0.
00998             Otherwise, the function returns the value 1.
00999     \warning You MUST call packets_init_option_reader() first!
01000  */
01001 
01002 int packets_parse_options (struct dhcp_packet *p)
01003 {
01004   int           inopt = 0;
01005   int           len, i, total;
01006   int           dslam_vendor;
01007   unsigned char code;
01008 
01009   packets_init_option_reader (p);
01010   dslam_vendor = DSLAM_UNKNOWN;
01011 
01012   /* ------------------------------------------------------------ */
01013   /* If (p->ctrl).taille has been set, then use the value         */
01014   /* ((p->ctrl).taille - 236). Otherwize, use the maximum size    */
01015   /* defined for an option, that is: OPTION_SIZE.                 */
01016   /*                                                              */
01017   /* We skip the 4 bytes at the beginning of the option's part.   */
01018   /*                                                              */
01019   /* In all cases, total MUST be less than OPTION_SIZE - 4.       */
01020   /* ------------------------------------------------------------ */
01021 
01022   total = (((p->ctrl).taille > (236 + 4)) ? ((p->ctrl).taille - 236) : OPTION_SIZE) - 4;
01023 
01024   if (total > OPTION_SIZE - 4) { return 1; }
01025   
01026 
01027   if (debug > 0)
01028   {
01029     my_syslog (log_file,
01030     "[DEBUG] [%s:%d] packets_parse_options: Size of the option's part total = %d",
01031     __FILE__, __LINE__, total);
01032   }
01033 
01034   while (1)
01035   {
01036     if (debug > 1)
01037     { my_syslog (log_file,
01038       "[DEBUG] [%s:%d] packets_parse_options: total = %d", __FILE__, __LINE__, total); } 
01039 
01040     if (inopt == 0)
01041     {
01042       if (*((p->ctrl).opt_pointer_reader) == 0x00)
01043       {
01044         (p->ctrl).opt_pointer_reader += 1; if (--total < 1) { return 1; }
01045         continue;
01046       }
01047 
01048       if (*((p->ctrl).opt_pointer_reader) == 0xFF)  { break; }
01049 
01050       code = *((p->ctrl).opt_pointer_reader);
01051       (p->ctrl).opt_pointer_reader += 1; if (--total < 1) { return 1; }
01052       inopt = 1;
01053       continue;
01054     }
01055 
01056     len = (int)(*((p->ctrl).opt_pointer_reader)) & 0x000000FF;
01057 
01058     ((p->ctrl).list[code]).code = code;
01059     ((p->ctrl).list[code]).len  = len;
01060     (p->ctrl).opt_pointer_reader += 1; if (--total < 1) { return 1; }
01061 
01062     if (len > VALUE_MAX_SIZE) { return 1; }
01063     for (i=0; i<len; i++)
01064     {
01065       (((p->ctrl).list[code]).value)[i] = *((p->ctrl).opt_pointer_reader);
01066       (p->ctrl).opt_pointer_reader += 1; if (--total < 1) { return 1; }
01067 
01068       if (debug > 0)
01069       {
01070         my_syslog (log_file,
01071         "[DEBUG] [%s:%d] packets_parse_options: Size of the option's part total = %d",
01072         __FILE__, __LINE__, total);
01073       }
01074     }
01075 
01076     inopt = 0;
01077   }
01078 
01079   /* ------------------------------------------------------------ */
01080   /* If option 82 is set, then parse it                           */
01081   /* Please note that the format of the option 82 depends on the  */
01082   /* DSLAM's vendor.                                              */
01083   /*  - Utstarcom: size is exactly 28 bytes                       */
01084   /*               and vendor ID is 0X79D.                        */
01085   /*  - Alcatel                                                   */
01086   /* ------------------------------------------------------------ */
01087 
01088   if (((p->ctrl).list[82]).code != 0) /* Begin OPTION 82 processing block */
01089   {
01090     if (((p->ctrl).list[82]).len ==  28)  /* Begin UTSTARCOM's processing block */ 
01091     {
01092       struct m_dhcp82    *mask;
01093       unsigned long int  vid, nasip;
01094       unsigned short int vlanid, node, vci;
01095   
01096       mask = (struct m_dhcp82*)((p->ctrl).list[82]).value;
01097   
01098       /* ---------------------------------------------------------- */
01099       /* Skip alignement problems                                   */ 
01100       /* ---------------------------------------------------------- */
01101   
01102       vid = 0;
01103       vid = (mask->vendor_id[0] << 24) |
01104             (mask->vendor_id[1] << 16) |
01105             (mask->vendor_id[2] << 8)  |
01106             mask->vendor_id[3];
01107   
01108       vlanid = 0;
01109       vlanid = (mask->vlan_id[0] << 8) |
01110                mask->vlan_id[1];
01111   
01112       nasip = 0;
01113       nasip = (mask->nas_ip[0] << 24) |
01114               (mask->nas_ip[1] << 16) |
01115               (mask->nas_ip[2] << 8)  |
01116               mask->nas_ip[3];
01117   
01118       node = (mask->node_id[0] << 8) |
01119              mask->node_id[1];
01120   
01121       vci = (mask->vci[0] << 8) |
01122             mask->vci[1]; 
01123 
01124       /* ---------------------------------------------------------- */
01125       /* If vendor is Utstarcom, then proceed.                      */
01126       /* ---------------------------------------------------------- */
01127 
01128       if (vid == 0x0000079D) 
01129       {
01130         if (debug > 0)
01131         {
01132           my_syslog (log_file,
01133           "[DEBUG] [%s:%d] packets_parse_options: Vendor ID for UTSTARCOM found",
01134           __FILE__, __LINE__);
01135         }
01136 
01137         /* -------------------------------------------------------- */
01138         /* Sanity checks                                            */ 
01139         /* -------------------------------------------------------- */
01140     
01141         if (mask->sub_option != 2)
01142         {
01143           my_syslog (log_file,
01144           "[WARNING] [%s:%d] Invalid value for option 82 sub-option (%d instead of 2)",
01145           __FILE__, __LINE__, (int)mask->sub_option);
01146           return 1; 
01147         }
01148     
01149         if (mask->length != 26)
01150         {
01151           my_syslog (log_file,
01152           "[WARNING] [%s:%d] Invalid value for option 82 length (%d instead of 26)",
01153           __FILE__, __LINE__, (int)mask->length);
01154           return 1; 
01155         }
01156     
01157         (p->ctrl).dslam_data.sub_option = mask->sub_option;
01158         (p->ctrl).dslam_data.length     = mask->length;
01159         (p->ctrl).dslam_data.vendor_id  = vid;
01160         (p->ctrl).dslam_data.port_type  = mask->port_type;
01161         (p->ctrl).dslam_data.version    = mask->version;
01162         (p->ctrl).dslam_data.vlan_id    = vlanid;
01163     
01164         memcpy ((void*)(p->ctrl).dslam_data.nas_mac, mask->nas_mac, 6);
01165         memset ((void*)((p->ctrl).dslam_data.node_id), 0, NODE_BUFFER_SIZE);
01166         snprintf ((p->ctrl).dslam_data.node_id, NODE_BUFFER_SIZE-1, "%u", node);
01167     
01168         (p->ctrl).dslam_data.nas_ip      = nasip;
01169         (p->ctrl).dslam_data.shelf       = mask->shelf       + 1;  /* Add 1 ??? Why */
01170         (p->ctrl).dslam_data.numero_slot = mask->numero_slot + 1;  /* Add 1 ??? Why */
01171         (p->ctrl).dslam_data.numero_port = mask->numero_port + 1;  /* Add 1 ??? Why */
01172         (p->ctrl).dslam_data.vpi         = mask->vpi;
01173         (p->ctrl).dslam_data.vci         = vci;
01174 
01175         dslam_vendor = DSLAM_UTSTARCOM;
01176       }
01177     }  /* End UTSTARCOM processing block */
01178 
01179 
01180     /* ------------------------------------------------------------ */
01181     /* If this is not an Utstarcom, then we assume that it is an    */
01182     /* Alcatel.                                                     */ 
01183     /* First byte should be "01" (sub-option).                      */
01184     /* Second byte should be the length of sub-option).             */
01185     /*                                                              */
01186     /*                        Minimum  Maximum                      */
01187     /* Sub-option code:       1        1                            */
01188     /* Sub-option length:     1        1                            */
01189     /* Node:                  0        20                           */
01190     /* String "atm":          3        3                            */
01191     /* One character "space": 1        1                            */
01192     /* Rack:                  1        1                            */
01193     /* One character "/":     1        1                            */
01194     /* Shelf:                 1        1                            */
01195     /* One character "/":     1        1                            */
01196     /* Slot:                  2        2                            */
01197     /* One character "/":     1        1                            */ 
01198     /* Port:                  2        2                            */
01199     /* One character ":":     1        1                            */
01200     /* VPI:                   1        3                            */
01201     /* One character ".":     1        1                            */
01202     /* VCI:                   1        3                            */
01203     /* One character "STX":   1        1                            */
01204     /* Other characters:      0        11                           */
01205     /*                        -------- --------                     */
01206     /*                        20       55                           */
01207     /*                                                              */
01208     /* The character "STX" has the ASCII code 2.                    */
01209     /* It should be followed by a character "New line" (ASCII code  */
01210     /* 10, in decimal).                                             */
01211     /* The other characters should be the phone number.             */
01212     /* ------------------------------------------------------------ */
01213 
01214     if (dslam_vendor == DSLAM_UNKNOWN) /* Begin ALCATEL procesing block */
01215                                        /* The loop "while" is used beacause we need the "break" */ 
01216     {
01217       while (
01218               (((p->ctrl).list[82]).len >= 20)
01219               &&
01220               (((p->ctrl).list[82]).len < VALUE_MAX_SIZE)
01221             )
01222       {
01223         char          *c, *v82, value82[VALUE_MAX_SIZE], node[NODE_BUFFER_SIZE], rack[2], shelf[2], slot[3], port[3];
01224         char          vpi[4], vci[4], vlanid[7];
01225         unsigned char subopt, subopt_length;
01226 
01227 
01228         if (debug > 0)
01229         {
01230           my_syslog (log_file,
01231           "[DEBUG] [%s:%d] packets_parse_options: Is it an ALCATEL DSLAM?",
01232           __FILE__, __LINE__);
01233         }
01234 
01235         memset ((void*)value82, 0,    VALUE_MAX_SIZE);
01236         memset ((void*)node,    0,    NODE_BUFFER_SIZE);
01237         memset ((void*)rack,    0,    2);
01238         memset ((void*)shelf,   0,    2);
01239         memset ((void*)slot,    0,    3);
01240         memset ((void*)port,    0,    3);
01241         memset ((void*)vpi,     0,    4);
01242         memset ((void*)vci,     0,    4);
01243         memset ((void*)vlanid,  0,    7);
01244 
01245         /* -------------------------------------------------------- */
01246         /* Note that the string pointed by 'value82' should be      */
01247         /* zero-terminated, because:                                */
01248         /* (((p->ctrl).list[82]).len < VALUE_MAX_SIZE)              */
01249         /* -------------------------------------------------------- */
01250 
01251         memcpy ((void*)value82, (void*)((p->ctrl).list[82]).value, ((p->ctrl).list[82]).len);
01252         v82 = value82;
01253 
01254         /* -------------------------------------------------------- */
01255         /* Extract the sub-option's data.                           */
01256         /* -------------------------------------------------------- */
01257 
01258         subopt        = value82[0];   /* Should be "01" for ALCATEL              */
01259         subopt_length = value82[1];   /* Should be between 17 and 40 for ALCATEL */
01260 
01261         if (debug > 0)
01262         {
01263           my_syslog (log_file,
01264           "[DEBUG] [%s:%d] packets_parse_options: OPT82 = [%s]",
01265           __FILE__, __LINE__, value82);
01266 
01267           my_syslog (log_file,
01268           "[DEBUG] [%s:%d] packets_parse_options: Sub-Option=%u and Sub-Option length=%u",
01269           __FILE__, __LINE__, subopt, subopt_length);
01270         }
01271 
01272         /* -------------------------------------------------------- */
01273         /* Look for the string " atm ".                             */
01274         /* Extract the node.                                        */
01275         /* Skip the string " atm ".                                 */
01276         /* -------------------------------------------------------- */
01277 
01278         v82 = value82 + 2;
01279         c   = strstr (v82, " atm ");
01280         if (c == NULL)
01281         {
01282           my_syslog (log_file,
01283           "[WARNING] [%s:%d] packets_parse_options: Can not find the string ' atm '!",
01284           __FILE__, __LINE__);
01285           return 1;
01286         }
01287 
01288         if (c != v82) { 
01289                         int length;
01290                         length = (int)(c - v82);
01291                         if (length >= NODE_BUFFER_SIZE) { break; }
01292                         memcpy ((void*)node, (void*)v82, length);
01293                         v82 = c;
01294                       }
01295 
01296         v82 += 5;
01297 
01298         /* -------------------------------------------------------- */
01299         /* Extract the Rack                                         */
01300         /* Skip the character "/".                                  */
01301         /* -------------------------------------------------------- */
01302 
01303         if ((*v82 < 48) || (*v82 > 57))
01304         {
01305           my_syslog (log_file,
01306           "[WARNING] [%s:%d] packets_parse_options: Rack is not numeric!",
01307           __FILE__, __LINE__);
01308           return 1;
01309         }
01310 
01311         if (*(v82+1) != '/')
01312         {
01313           my_syslog (log_file,
01314           "[WARNING] [%s:%d] packets_parse_options: No character '/' after Rack!",
01315           __FILE__, __LINE__);
01316           return 1;
01317         }
01318 
01319         rack[0] = *v82;
01320         v82 += 2;
01321 
01322         /* -------------------------------------------------------- */
01323         /* Extract the shelf.                                       */
01324         /* Skip the character "/".                                  */
01325         /* -------------------------------------------------------- */
01326 
01327         if ((*v82 < 48) || (*v82 > 57)) 
01328         {
01329           my_syslog (log_file,
01330           "[WARNING] [%s:%d] packets_parse_options: Shelf is not numeric!",
01331           __FILE__, __LINE__);
01332           return 1;
01333         }
01334 
01335         if (*(v82+1) != '/')
01336         {
01337           my_syslog (log_file,
01338           "[WARNING] [%s:%d] packets_parse_options: No character '/' after Rack!",
01339           __FILE__, __LINE__);
01340           return 1;
01341         }
01342 
01343         shelf[0] = *v82;
01344         v82 += 2;
01345 
01346         /* -------------------------------------------------------- */
01347         /* Extract the slot.                                        */
01348         /* Skip the character "/".                                  */
01349         /* -------------------------------------------------------- */
01350 
01351         if ((*v82 < 48) || (*v82 > 57))
01352         {
01353           my_syslog (log_file,
01354           "[WARNING] [%s:%d] packets_parse_options: Slot is not numeric!",
01355           __FILE__, __LINE__);
01356           return 1;
01357         }
01358  
01359         if ((*(v82+1) < 48) || (*(v82+1) > 57))
01360         {
01361           my_syslog (log_file,
01362           "[WARNING] [%s:%d] packets_parse_options: Slot is not numeric!",
01363           __FILE__, __LINE__);
01364           return 1;
01365         }
01366 
01367         if (*(v82+2) != '/')
01368         {
01369           my_syslog (log_file,
01370           "[WARNING] [%s:%d] packets_parse_options: No character '/' after Slot!",
01371           __FILE__, __LINE__);
01372           return 1;
01373         }
01374 
01375         slot[0] = *v82;
01376         slot[1] = *(v82 + 1);
01377         v82 += 3;
01378 
01379         /* -------------------------------------------------------- */
01380         /* Extract the port.                                        */
01381         /* Skip the character ":".                                  */
01382         /* -------------------------------------------------------- */
01383 
01384         if ((*v82 < 48) || (*v82 > 57))
01385         {
01386           my_syslog (log_file,
01387           "[WARNING] [%s:%d] packets_parse_options: Port is not numeric!",
01388           __FILE__, __LINE__);
01389           return 1;
01390         }
01391 
01392         if ((*(v82+1) < 48) || (*(v82+1) > 57))
01393         {
01394           my_syslog (log_file,
01395           "[WARNING] [%s:%d] packets_parse_options: Port is not numeric!",
01396           __FILE__, __LINE__);
01397           return 1;
01398         }
01399 
01400         if (*(v82+2) != ':')
01401         {
01402           my_syslog (log_file,
01403           "[WARNING] [%s:%d] packets_parse_options: No character ':' after Port!",
01404           __FILE__, __LINE__);
01405           return 1;
01406         }
01407 
01408         port[0] = *v82;
01409         port[1] = *(v82+1);
01410         v82 += 3;
01411 
01412         /* -------------------------------------------------------- */
01413         /* Extract the VPI.                                         */
01414         /* Skip the character ".".                                  */
01415         /* -------------------------------------------------------- */
01416 
01417         c = strstr (v82, ".");
01418         if (c == NULL)
01419         {
01420           my_syslog (log_file,
01421           "[WARNING] [%s:%d] packets_parse_options: No character '.' after VPI!",
01422           __FILE__, __LINE__);
01423           return 1;
01424         }
01425 
01426         if (c == v82)
01427         {
01428           my_syslog (log_file,
01429           "[WARNING] [%s:%d] packets_parse_options: Empty VPI!",
01430           __FILE__, __LINE__);
01431           return 1;
01432         }
01433         else {
01434                int length;
01435                length = (int)(c - v82);
01436                if (length > 3)
01437                {
01438                  my_syslog (log_file,
01439                  "[WARNING] [%s:%d] packets_parse_options: VPI size is %d  (too long, max is 3)!",
01440                  __FILE__, __LINE__, length);
01441                  return 1;
01442                }
01443                memcpy ((void*)vpi, (void*)v82, length);
01444              }
01445         v82 = c + 1;
01446 
01447         /* -------------------------------------------------------- */
01448         /* Extract the VCI.                                         */
01449         /* -------------------------------------------------------- */
01450 
01451         c = strstr (v82, "\2");   /* look for character "STX = Start of text" */
01452         if (c == NULL)
01453         {
01454           my_syslog (log_file,
01455           "[WARNING] [%s:%d] packets_parse_options: No character '.' after VCI!",
01456           __FILE__, __LINE__);
01457           return 1;
01458         }
01459 
01460         if (c == v82)
01461         {
01462           my_syslog (log_file,
01463           "[WARNING] [%s:%d] packets_parse_options: Empty VCI!",
01464           __FILE__, __LINE__);
01465           return 1;
01466         }
01467         else {
01468                int length;
01469                length = (int)(c - v82);
01470                if (length > 3)
01471                {
01472                  my_syslog (log_file,
01473                  "[WARNING] [%s:%d] packets_parse_options: VCI size is %d  (too long, max is 3)!",
01474                  __FILE__, __LINE__, length);
01475                  return 1;
01476                }
01477                memcpy ((void*)vci, (void*)v82, length);
01478              }
01479 
01480         /* Note that the string pointed by 'value82' should be      */
01481         /* zero-terminated (see earlier comment).                   */
01482 
01483         v82 = c + 1;  /* This may point to character '0' */
01484 
01485         /* -------------------------------------------------------- */
01486         /* Now assign values to data structure.                     */
01487         /* -------------------------------------------------------- */
01488 
01489         (p->ctrl).dslam_data.sub_option = (unsigned char)subopt;
01490         (p->ctrl).dslam_data.length     = (unsigned char)subopt_length;
01491         (p->ctrl).dslam_data.vendor_id  = 0;
01492         (p->ctrl).dslam_data.port_type  = 0;
01493         (p->ctrl).dslam_data.version    = 0;
01494         
01495         memset ((void*)(p->ctrl).dslam_data.nas_mac,   0, 6);
01496         memset ((void*)((p->ctrl).dslam_data.node_id), 0, NODE_BUFFER_SIZE);
01497         strncpy ((p->ctrl).dslam_data.node_id, node, NODE_BUFFER_SIZE-1);
01498 
01499         (p->ctrl).dslam_data.nas_ip      = 0;
01500         (p->ctrl).dslam_data.shelf       = (unsigned char)(atoi(shelf));
01501         (p->ctrl).dslam_data.numero_slot = (unsigned char)(atoi(slot));
01502         (p->ctrl).dslam_data.numero_port = (unsigned char)(atoi(port));
01503         (p->ctrl).dslam_data.vpi         = (unsigned short int)(atoi(vpi));  /* 999 < 65535 => that's OK */
01504         (p->ctrl).dslam_data.vci         = (unsigned short int)(atoi(vci));  /* 999 < 65535 => that's OK */
01505 
01506         /* -------------------------------------------------------- */
01507         /* The Vlan ID is compose [VPI+VCI]                         */ 
01508         /* The maximum size for VPI is 3 characters.                */
01509         /* The maximum size for VCI is 3 characters.                */
01510         /* -------------------------------------------------------- */
01511 
01512         strncpy  (vlanid, vpi, 3);
01513         strncat  (vlanid, vci, 3);
01514 
01515         (p->ctrl).dslam_data.vlan_id = (unsigned int)(atoi(vlanid)); /* Maximum is 999999 => that's OK */
01516 
01517         dslam_vendor = DSLAM_ALCATEL;
01518         break;
01519       }
01520     } /* End ALCATEL procesing block */
01521 
01522     /* ------------------------------------------------------------ */
01523     /* If we could not find the vendor, then we don't know how to  */
01524     /* parse the option's string.                                  */
01525     /* ------------------------------------------------------------ */
01526 
01527     (p->ctrl).dslam_data.constructor = dslam_vendor;
01528 
01529     if (dslam_vendor == DSLAM_UNKNOWN)
01530     {
01531       my_syslog (log_file,
01532       "[DEBUG] [%s:%d] packets_parse_options: Could not find the DSLAM's vendor!",
01533       __FILE__, __LINE__); 
01534       return 1;
01535     }
01536   } /* End OPTION 82 processing block */
01537 
01538   return 0;
01539 }
01540 
01541 /*! \brief Get a specific option.
01542     \author Denis BEURIVE
01543     \param p Pointer to the packet.
01544     \param option Option's code (value between 1 and 254 included).
01545     \param len Pointer to an integer used to store the size of the option's value.
01546     \param value Pointer to a pointer that will point to the option's value.
01547     \return Upon successful completion, the function returns the value 0.
01548             Otherwize, the function returns the value 1.
01549     \warning You must call packets_parse_options() first. The proper way to operate is:
01550              <UL>
01551                <LI>Call packets_init_option_reader().
01552                <LI>Call packets_parse_options().
01553                <LI>Call packets_get_option() for all options you want to extract.
01554              </UL>
01555  */
01556 
01557 int packets_get_option (struct dhcp_packet *p, int option, int *len, unsigned char **value)
01558 {
01559   if (((p->ctrl).list[option]).code == 0) { return 1; }
01560 
01561   *len   = ((p->ctrl).list[option]).len;
01562   *value = ((p->ctrl).list[option]).value;
01563 
01564   return 0;
01565 }
01566 
01567 /*! \brief Get the type of packet (value of option 53 (DHCP Message Type).
01568     \author Denis BEURIVE
01569     \param p Pointer to the packet.
01570     \return Upon successful completion, the function returns the numerical representation of the message type.
01571             This could be:
01572             <UL>
01573               <LI>DHCPDISCOVER (1)
01574               <LI>DHCPOFFER (2)
01575               <LI>DHCPREQUEST (3)
01576               <LI>DHCPDECLINE (4)
01577               <LI>DHCPACK (5)
01578               <LI>DHCPNAK (6)
01579               <LI>DHCPRELEASE (7)
01580               <LI>DHCPINFORM (8)
01581             </UL>
01582             If an error occured, the function returns the value -1.
01583     \warning You must call packets_parse_options() first. The proper way to operate is:
01584              <UL>
01585                <LI>Call packets_init_option_reader().
01586                <LI>Call packets_parse_options().
01587                <LI>Call packets_get_option() for all options you want to extract (you may skip this step).
01588                <LI>Call packets_get_message_type(). 
01589              </UL>
01590  */
01591 
01592 int packets_get_message_type (struct dhcp_packet *p)
01593 {
01594   int            rc, len;
01595   unsigned char  *value;
01596 
01597   rc = packets_get_option (p, 53, &len, &value);
01598   if (rc == 1) { return -1; }
01599 
01600   return ((int)*value) & 0x000000FF;
01601 }
01602 
01603 /*! \brief Get the subnet mask associated with a given packet.
01604     \author Denis BEURIVE
01605     \param p Pointer to the packet.
01606     \return Upon successful completion, the function returns a non NULL pointer to a zero terminated string of
01607             characters that represents the network mask. Otherwise the function returns the value NULL.
01608     \warning The returned string can only be used until the next call to packets_get_subnet_mask().
01609              The string is returned in a statically allocated buffer, which subsequent calls will overwrite.
01610              Do not try to free it!
01611  */
01612 
01613 char* packets_get_subnet_mask (struct dhcp_packet *p)
01614 {
01615   int            rc, len;
01616   unsigned char  *value;
01617   static char    subvalue[OPTIONS_OPTION_VALUE_SIZE];
01618 
01619   memset ((void*)subvalue, 0, OPTIONS_OPTION_VALUE_SIZE);
01620 
01621   rc = packets_get_option (p, 1, &len, &value);
01622   if (rc == 1) { return NULL; }
01623 
01624   memcpy ((void*)subvalue, (void*)value, (len < OPTIONS_OPTION_VALUE_SIZE) ? len : OPTIONS_OPTION_VALUE_SIZE-1);
01625 
01626   return subvalue;
01627 }
01628 
01629 /*! \brief Return a zero terminated string of characters the represents the DSLAM's node ID from the option 82.
01630     \author Denis BEURIVE
01631     \param p Pointer to the packet.
01632     \return The function returns the DSLAM's node ID.
01633     \warning You must call packets_parse_options() first. The proper way to operate is:
01634              <UL>
01635                <LI>Call packets_init_option_reader().
01636                <LI>Call packets_parse_options().
01637                <LI>Call packets_get_option() for all options you want to extract (you may skip this step).
01638                <LI>Call packets_get_message_type(). 
01639                <LI>Call packets_get_node_id().
01640              </UL>
01641  */
01642 
01643 char* packets_get_node_id (struct dhcp_packet *p)
01644 { return (p->ctrl).dslam_data.node_id; }
01645 
01646 /*! \brief Return the DSLAM's shelf from the option 82.
01647     \author Denis BEURIVE
01648     \param p Pointer to the packet.
01649     \return The function returns the DSLAM's shelf.
01650     \warning You must call packets_parse_options() first. The proper way to operate is:
01651              <UL>
01652                <LI>Call packets_init_option_reader().
01653                <LI>Call packets_parse_options().
01654                <LI>Call packets_get_option() for all options you want to extract (you may skip this step).
01655                <LI>Call packets_get_message_type(). 
01656                <LI>Call packets_get_shelf().
01657              </UL>
01658  */
01659 
01660 unsigned char packets_get_shelf (struct dhcp_packet *p)
01661 { return (p->ctrl).dslam_data.shelf; }
01662 
01663 /*! \brief Return the DSLAM's slot number from the option 82.
01664     \author Denis BEURIVE
01665     \param p Pointer to the packet.
01666     \return The function returns the DSLAM's slot number.
01667     \warning You must call packets_parse_options() first. The proper way to operate is:
01668              <UL>
01669                <LI>Call packets_init_option_reader().
01670                <LI>Call packets_parse_options().
01671                <LI>Call packets_get_option() for all options you want to extract (you may skip this step).
01672                <LI>Call packets_get_message_type(). 
01673                <LI>Call packets_get_numero_slot().
01674              </UL>
01675  */
01676 
01677 unsigned char packets_get_numero_slot (struct dhcp_packet *p)
01678 { return (p->ctrl).dslam_data.numero_slot; } 
01679 
01680 /*! \brief Return the DSLAM's VCI from the option 82.
01681     \author Denis BEURIVE
01682     \param p Pointer to the packet.
01683     \return The function returns the DSLAM's VCI.
01684     \warning You must call packets_parse_options() first. The proper way to operate is:
01685              <UL>
01686                <LI>Call packets_init_option_reader().
01687                <LI>Call packets_parse_options().
01688                <LI>Call packets_get_option() for all options you want to extract (you may skip this step).
01689                <LI>Call packets_get_message_type().
01690                <LI>Call packets_get_vci().
01691              </UL>
01692  */
01693 
01694 unsigned short int packets_get_vci (struct dhcp_packet *p)
01695 { return (p->ctrl).dslam_data.vci; }
01696 
01697 /*! \brief Return the DSLAM's port number from the option 82.
01698     \author Denis BEURIVE
01699     \param p Pointer to the packet.
01700     \return The function returns the DSLAM's port number.
01701     \warning You must call packets_parse_options() first. The proper way to operate is:
01702              <UL>
01703                <LI>Call packets_init_option_reader().
01704                <LI>Call packets_parse_options().
01705                <LI>Call packets_get_option() for all options you want to extract (you may skip this step).
01706                <LI>Call packets_get_message_type(). 
01707                <LI>Call packets_get_numero_port().
01708              </UL>
01709  */
01710 
01711 unsigned char packets_get_numero_port (struct dhcp_packet *p)
01712 { return (p->ctrl).dslam_data.numero_port; }
01713 
01714 /*! \brief Return the DSLAM's VLAN ID from the option 82.
01715     \author Denis BEURIVE
01716     \param p Pointer to the packet.
01717     \return The function returns the DSLAM's VLAN ID.
01718     \warning You must call packets_parse_options() first. The proper way to operate is:
01719              <UL>
01720                <LI>Call packets_init_option_reader().
01721                <LI>Call packets_parse_options().
01722                <LI>Call packets_get_option() for all options you want to extract (you may skip this step).
01723                <LI>Call packets_get_message_type().
01724                <LI>Call packets_get_vlan_id().
01725              </UL>
01726  */
01727 
01728 unsigned short int packets_get_vlan_id (struct dhcp_packet *p)
01729 { return (p->ctrl).dslam_data.vlan_id; }
01730 
01731 /*! \brief Size of the buffer used to write data in function packet_dump().
01732     \remark the value 4096 should be more than enough, since it is much bigger than the maximum DHCP packet size.
01733  */
01734 
01735 #define BUFFER_SIZE 4096
01736 
01737 /*! \brief Dump the DHCP packet in a file (in human readable format).
01738     \author Denis BEURIVE
01739     \param p Pointer to the packet.
01740     \param file Path to the output file.
01741     \param csv Path to the CSV file.
01742     \param from Internet address of the sender. If NULL, then a character '-' is printed.
01743     \param to Internet address of the addressee. If NULL, then a character '-' is printed.
01744     \return Upon successful completion, the function returns the value 0. Otherwise, it returns the value 1.
01745     \warning If the function could not allocate memory, it calls the function "exit()" with status value 1.
01746              You must call packet_init_dump_service() before you can use this function.
01747  */
01748 
01749 int packet_dump (struct dhcp_packet *p, char *file, char *csv, struct sockaddr_in *from, struct sockaddr_in *to)
01750 {
01751   FILE                *out, *csvfd;
01752   int                 iout, icsvfd;
01753   int                 i, j, k, len, port_from, port_to, type, modem_manufacturor, size, o;
01754   unsigned char       *c, *value;
01755   char                addresse_from[16], addresse_to[16], buffer[BUFFER_SIZE], buff82[BUFFER_SIZE], *s, *sopt;
01756   static unsigned int mark = 0;
01757   dstring             ds, dsoptions;
01758 
01759 
01760 
01761   if (debug > 0)
01762   { my_syslog (log_file, "[DEBUG] [%s:%d] Calling packet_dump()", __FILE__, __LINE__); }
01763 
01764 
01765 
01766   memset ((void*)buff82, 0, BUFFER_SIZE);
01767 
01768   iout = open (file, O_CREAT | O_WRONLY | O_APPEND | O_LARGEFILE, S_IRWXU | S_IRWXG | S_IRWXO);
01769   if (iout == -1)
01770   {
01771     my_syslog (log_file, "[WARNING] [%s:%d] Could not open file '%s' open() failed - %s",
01772                __FILE__, __LINE__,
01773                file,
01774                strerror(errno));
01775     return 1;
01776   }
01777 
01778   out = fdopen (iout, "a");
01779   if (out == NULL)
01780   {
01781     my_syslog (log_file, "[WARNING] [%s:%d] Could not \"fdopen()\" file '%s' - %s",
01782                __FILE__, __LINE__,
01783                file,
01784                strerror(errno));
01785     return 1;
01786   }
01787 
01788   /* ------------------------------------------------------------ */
01789   /* Get the modem's manufacturor.                                */
01790   /* ------------------------------------------------------------ */
01791 
01792   modem_manufacturor = get_modem_manufacturor(p);
01793 
01794   /* ------------------------------------------------------------ */
01795   /* Parse options                                                */
01796   /* ------------------------------------------------------------ */
01797 
01798   if (packets_parse_options(p) == 1)
01799   {
01800     my_syslog (log_file,
01801                "[WARNING] [%s:%d] Error while parsing packet, drop packet", __FILE__, __LINE__);
01802     fclose (out);
01803     return 1;
01804   }
01805 
01806   /* ------------------------------------------------------------ */
01807   /* Allocate dynamic strings.                                    */
01808   /* ------------------------------------------------------------ */
01809 
01810   if (dstring_init (&ds, 2048) == 1)
01811   {
01812     my_syslog (log_file,
01813                "[FATAL] [%s:%d] Can not allocate memory for dynamic string (ds)!",
01814                __FILE__, __LINE__);
01815     fclose (out);
01816     exit (1);
01817   }
01818 
01819   if (dstring_init (&dsoptions, 2048) == 1)
01820   {
01821     my_syslog (log_file,
01822                "[FATAL] [%s:%d] Can not allocate memory for dynamic string (dsoptions)!",
01823                __FILE__, __LINE__);
01824     fclose (out);
01825     exit (1);
01826   }
01827 
01828   /* ------------------------------------------------------------ */
01829   /* Get "from" and "to" address.                                 */
01830   /* ------------------------------------------------------------ */
01831 
01832   if (from != NULL)
01833   { memset ((void*)addresse_from, 0, 16); get_remote_address (from, addresse_from, &port_from); }
01834 
01835   if (to   != NULL)
01836   { memset ((void*)addresse_to,   0, 16); get_remote_address (to,   addresse_to,   &port_to);   }
01837 
01838   /* ------------------------------------------------------------ */
01839   /* Lock dump file (using synchronization file)                  */
01840   /* ------------------------------------------------------------ */
01841 
01842   if (dump_sync_fd != -1)
01843   {
01844     if (lock_file (dump_sync_fd) == 1)
01845     {
01846       my_syslog (log_file,
01847                  "[ERROR] [%s:%d] Could not lock dump file! Continue processing anyway...",
01848                  __FILE__, __LINE__);
01849     }
01850   }
01851 
01852   /* ------------------------------------------------------------ */
01853   /* Print date and mark (auto increment)                         */
01854   /* ------------------------------------------------------------ */
01855 
01856   fprintf (out, "%s (%u)\n\n", dater(), mark);
01857 
01858   memset ((void*)buffer, 0, BUFFER_SIZE);
01859   snprintf  (buffer, BUFFER_SIZE, "%s;%u;%s;", dater(), mark, myhostname);
01860   mark++;
01861   if (dstring_add (&ds, buffer, strlen(buffer)) == 1)
01862   {
01863     my_syslog (log_file,
01864                "[FATAL] [%s:%d] Can not allocate memory!",
01865                __FILE__, __LINE__);
01866     fclose (out);
01867     exit (1);
01868   }
01869 
01870   /* ------------------------------------------------------------ */
01871   /* Print sender's TCP data (IP and port)                        */
01872   /* ------------------------------------------------------------ */
01873 
01874   memset ((void*)buffer, 0, BUFFER_SIZE);
01875 
01876   if (from != NULL)
01877   {
01878     fprintf (out, "%s (%d) => ", addresse_from, port_from);
01879     snprintf (buffer, BUFFER_SIZE, "IN;%s;%d;", addresse_from, port_from);
01880   }
01881   else
01882   {
01883     fprintf (out, "- => ");
01884     snprintf (buffer, BUFFER_SIZE, "OUT;-;-;"); 
01885   }
01886 
01887   if (dstring_add (&ds, buffer, strlen(buffer)) == 1)
01888   {
01889     my_syslog (log_file,
01890                "[FATAL] [%s:%d] Can not allocate memory!",
01891                __FILE__, __LINE__);
01892     fclose (out);
01893     exit (1);
01894   }
01895 
01896   /* ------------------------------------------------------------ */
01897   /* Print receiver's TCP data (IP and port)                      */
01898   /* ------------------------------------------------------------ */
01899 
01900   memset ((void*)buffer, 0, BUFFER_SIZE);
01901 
01902   if (to != NULL)
01903   {
01904     fprintf (out, "%s (%d)", addresse_to, port_to);
01905     snprintf (buffer, BUFFER_SIZE, "%s;%d;", addresse_to, port_to);
01906   }
01907   else
01908   {
01909     fprintf (out, "-");
01910     snprintf (buffer, BUFFER_SIZE, "-;-;");
01911   }
01912 
01913   if (dstring_add (&ds, buffer, strlen(buffer)) == 1)
01914   {
01915     my_syslog (log_file,
01916                "[FATAL] [%s:%d] Can not allocate memory!",
01917                __FILE__, __LINE__);
01918     fclose (out);
01919     exit (1);
01920   }
01921 
01922   /* ------------------------------------------------------------ */
01923   /* Print the message type                                       */
01924   /* ------------------------------------------------------------ */
01925 
01926   type = packets_get_message_type(p);
01927   fprintf (out, " %s", packets_type_to_char(type));
01928   fprintf (out, "\n\n");
01929 
01930   memset ((void*)buffer, 0, BUFFER_SIZE);
01931   snprintf (buffer, BUFFER_SIZE, "%s;", packets_type_to_char(type));
01932   if (dstring_add (&ds, buffer, strlen(buffer)) == 1)
01933   {
01934     my_syslog (log_file,
01935                "[FATAL] [%s:%d] Can not allocate memory!",
01936                __FILE__, __LINE__);
01937     fclose (out);
01938     exit (1);
01939   }
01940 
01941   /* ------------------------------------------------------------ */
01942   /* Dump fixed fields                                            */
01943   /* ------------------------------------------------------------ */
01944 
01945   fprintf (out, "Number of bytes                : %u\n",  (unsigned int)((p->ctrl).taille));
01946   fprintf (out, "Opcode                         : %u\n",  ((unsigned int)packets_get_op(p)) & 0x000000FF);
01947   fprintf (out, "Hardware type                  : %u\n",  ((unsigned int)packets_get_htype(p)) & 0x000000FF);
01948   fprintf (out, "Hardware address length        : %u\n",  ((unsigned int)packets_get_hlen(p)) & 0x000000FF);
01949   fprintf (out, "Hop count                      : %u\n",  ((unsigned int)packets_get_hops(p)) & 0x000000FF);
01950   fprintf (out, "Transaction ID                 : %lu\n",     packets_get_xid(p));
01951   fprintf (out, "Ellapsed time                  : %hu\n",     packets_get_secs(p));
01952   fprintf (out, "Flags                          : %hu\n",     packets_get_flags(p));
01953   fprintf (out, "Client IP address              : %s\n",      packets_get_ciaddr(p));
01954   fprintf (out, "Your IP address                : %s\n",      packets_get_yiaddr(p));
01955   fprintf (out, "Server IP address              : %s\n",      packets_get_siaddr(p));
01956   fprintf (out, "Gateway IP address             : %s\n",      packets_get_giaddr(p));
01957   fprintf (out, "Client hardware address        : %s (%s)\n", packets_get_chaddr(p), id_manufacturor_to_string(modem_manufacturor));
01958   fprintf (out, "Server host name               : %s\n",      packets_get_sname(p));
01959   fprintf (out, "Boot file name                 : %s\n",      packets_get_file(p));
01960   fprintf (out, "\n");
01961 
01962   memset ((void*)buffer, 0, BUFFER_SIZE);
01963   snprintf (buffer, BUFFER_SIZE, "%u;%u;%u;%u;%u;%lu;%hu;%hu;%s;%s;%s;%s;%s;%s;%s;%s;",
01964             (unsigned int)((p->ctrl).taille),
01965             ((unsigned int)packets_get_op(p)) & 0x000000FF,
01966             ((unsigned int)packets_get_htype(p)) & 0x000000FF,
01967             ((unsigned int)packets_get_hlen(p)) & 0x000000FF,
01968             ((unsigned int)packets_get_hops(p)) & 0x000000FF,
01969             packets_get_xid(p),
01970             packets_get_secs(p),
01971             packets_get_flags(p),
01972             packets_get_ciaddr(p),
01973             packets_get_yiaddr(p),
01974             packets_get_siaddr(p),
01975             packets_get_giaddr(p),
01976             packets_get_chaddr(p),
01977             packets_get_sname(p),
01978             packets_get_file(p),
01979             id_manufacturor_to_string(modem_manufacturor));
01980 
01981   if (dstring_add (&ds, buffer, strlen(buffer)) == 1)
01982   {
01983     my_syslog (log_file,
01984                "[FATAL] [%s:%d] Can not allocate memory!",
01985                __FILE__, __LINE__);
01986     fclose (out);
01987     exit (1);
01988   }
01989 
01990   /* ------------------------------------------------------------ */
01991   /* Print The options                                            */
01992   /* ------------------------------------------------------------ */
01993 
01994   fprintf (out, "Options:\n\n");
01995 
01996   for (o=0; o<256; o++)
01997   {
01998     /* ---------------------------------------------------------- */
01999     /* Print options in the correct order                         */
02000     /* (that is: 1, 3, 15, 6,...)                                 */ 
02001     /* ---------------------------------------------------------- */
02002 
02003     i = order[o];   
02004 
02005     /* ---------------------------------------------------------- */
02006     /* Special options                                            */
02007     /* ---------------------------------------------------------- */
02008 
02009     if ((i==1 || i==3 || i==15 || i==6) && (((p->ctrl).list[i]).code == 0))
02010     {
02011       char aux[]=";";
02012       if (dstring_add (&dsoptions, aux, strlen(aux)) == 1)
02013       {
02014          my_syslog (log_file,
02015                     "[FATAL] [%s:%d] Can not allocate memory!",
02016                     __FILE__, __LINE__);
02017          fclose (out);
02018          exit (1);
02019       } 
02020       continue;
02021     }
02022 
02023     /* ---------------------------------------------------------- */
02024     /* Standard options                                           */
02025     /* ---------------------------------------------------------- */
02026 
02027     if (((p->ctrl).list[i]).code == 0) { continue; }
02028 
02029     len   = ((p->ctrl).list[i]).len;
02030     value = ((p->ctrl).list[i]).value;
02031 
02032     fprintf (out, "\t%3d (%s) ", i, descriptions[i]);
02033 
02034     /* --- CSV */
02035 
02036     if (i != 82)
02037     {
02038        if (! (i==1 || i==3 || i==15 || i==6))
02039        {
02040          memset ((void*)buffer, 0, BUFFER_SIZE);
02041          snprintf (buffer, BUFFER_SIZE, "%3d|%s|", i, descriptions[i]);
02042          if (dstring_add (&dsoptions, buffer, strlen(buffer)) == 1)
02043          {
02044            my_syslog (log_file,
02045                       "[FATAL] [%s:%d] Can not allocate memory!",
02046                       __FILE__, __LINE__);
02047            fclose (out);
02048            exit (1);
02049          }
02050        }
02051     }
02052 
02053     /* --- */
02054 
02055     memset ((void*)buffer, 0, BUFFER_SIZE);
02056     c = value;
02057 
02058     for (j=0; j<len; j++)
02059     {
02060       fprintf (out, "%c%c ",
02061                      int_to_char (((*c) & 0xF0) >> 4),  
02062                      int_to_char ((*c) & 0x0F));
02063 
02064       /* --- CSV */
02065 
02066          if (i != 82)
02067          {
02068             snprintf (buffer, BUFFER_SIZE, "%c%c",
02069                       int_to_char (((*c) & 0xF0) >> 4),
02070                       int_to_char ((*c) & 0x0F));
02071             if (dstring_add (&dsoptions, buffer, strlen(buffer)) == 1)
02072             {
02073               my_syslog (log_file,
02074                          "[FATAL] [%s:%d] Can not allocate memory!",
02075                          __FILE__, __LINE__);
02076               fclose (out);
02077               exit (1);
02078             }
02079          }
02080 
02081       /* --- */
02082 
02083       c++;
02084     }
02085 
02086     /* --- CSV */
02087 
02088        if (i != 82)
02089        {
02090           if (dstring_add (&dsoptions, ";", 1) == 1)
02091           {
02092             my_syslog (log_file,
02093                        "[FATAL] [%s:%d] Can not allocate memory!",
02094                        __FILE__, __LINE__);
02095             fclose (out);
02096             exit (1);
02097           }
02098        }
02099 
02100     /* --- */
02101 
02102     fprintf (out, "\n");
02103 
02104     /* ---------------------------------------------------------- */
02105     /* Options 82                                                 */
02106     /* ---------------------------------------------------------- */
02107 
02108     if ((i==82) && (((p->ctrl).list[i]).code != 0))
02109     {
02110       fprintf (out, "\t\tsub option:  %u\n",    (p->ctrl).dslam_data.sub_option);
02111       fprintf (out, "\t\tlength:      %u\n",    (p->ctrl).dslam_data.length);
02112       fprintf (out, "\t\tvendor ID:   %#lX\n",  (p->ctrl).dslam_data.vendor_id);
02113       fprintf (out, "\t\tport type:   %u\n",    (p->ctrl).dslam_data.port_type);
02114       fprintf (out, "\t\tversion:     %u\n",    (p->ctrl).dslam_data.version);
02115       fprintf (out, "\t\tvlan ID:     %hu\n",   (p->ctrl).dslam_data.vlan_id);
02116 
02117       /* --- CSV */
02118 
02119          snprintf (buff82, BUFFER_SIZE, "82;%#lX;%u;%u;%hu;",
02120                    (p->ctrl).dslam_data.vendor_id,
02121                    (p->ctrl).dslam_data.port_type,
02122                    (p->ctrl).dslam_data.version,
02123                    (p->ctrl).dslam_data.vlan_id);
02124 
02125       /* --- */
02126 
02127       fprintf (out, "\t\tnas mac:     ");
02128       for (k=0; k<6; k++)
02129       {
02130         char          dd[3];
02131         unsigned char c  = (p->ctrl).dslam_data.nas_mac[k];
02132         char          c1 = int_to_char ((c & 0xF0) >> 4);
02133         char          c2 = int_to_char (c & 0x0F);
02134 
02135         fprintf (out, "%c%c", c1, c2); 
02136         snprintf (dd, 3, "%c%c", c1, c2);
02137         strcat (buff82, dd);
02138 
02139         if (k<5) { fprintf (out, ":"); strcat (buff82, ":"); }
02140       }
02141       strcat (buff82, ";");
02142       fprintf (out, "\n"); 
02143 
02144       fprintf (out, "\t\tnas ip:      %s\n",  get_doted_ip((p->ctrl).dslam_data.nas_ip));
02145       fprintf (out, "\t\tnode:        %s\n",  (p->ctrl).dslam_data.node_id);
02146       fprintf (out, "\t\tshelf:       %u\n",  (p->ctrl).dslam_data.shelf);
02147       fprintf (out, "\t\tslot:        %u\n",  (p->ctrl).dslam_data.numero_slot);
02148       fprintf (out, "\t\tport:        %u\n",  (p->ctrl).dslam_data.numero_port);
02149       fprintf (out, "\t\tvpi:         %u\n",  (p->ctrl).dslam_data.vpi);
02150       fprintf (out, "\t\tvci:         %hu\n", (p->ctrl).dslam_data.vci);
02151       fprintf (out, "\t\tvendor:      ");
02152 
02153       /* --- CSV */
02154 
02155          memset ((void*)buffer, 0, BUFFER_SIZE);
02156          snprintf (buffer, BUFFER_SIZE, "%s;%s;%u;%u;%u;%u;%hu;",
02157                    get_doted_ip((p->ctrl).dslam_data.nas_ip),
02158                    (p->ctrl).dslam_data.node_id,
02159                    (p->ctrl).dslam_data.shelf,
02160                    (p->ctrl).dslam_data.numero_slot,
02161                    (p->ctrl).dslam_data.numero_port,
02162                    (p->ctrl).dslam_data.vpi,
02163                    (p->ctrl).dslam_data.vci);
02164 
02165          strcat (buff82, buffer);
02166 
02167       /* --- */
02168 
02169       switch ((p->ctrl).dslam_data.constructor)
02170       {
02171         case DSLAM_ALCATEL:    { fprintf (out, "ALCATEL\n");
02172                                  strcat (buff82, "ALCATEL;"); }
02173                                break;
02174         case DSLAM_UTSTARCOM:  { fprintf (out, "UTSTARCOM\n");
02175                                  strcat (buff82, "UTSTARCOM;"); }
02176                                break;
02177         default:               { fprintf (out, "Unknown (%d) - This should not happen!\n", (p->ctrl).dslam_data.constructor);
02178                                  strcat (buff82, "UNKNOWN;"); }
02179       }
02180     }
02181 
02182   } /* End of options' section */ 
02183 
02184   /* ------------------------------------------------------------ */
02185   /* Add option 82 to the end of the fixed part.                  */
02186   /* ------------------------------------------------------------ */
02187 
02188   if (buff82[0] != 0)
02189   {
02190     if (dstring_add (&ds, buff82, strlen(buff82)) == 1)
02191     {
02192       my_syslog (log_file,
02193                  "[FATAL] [%s:%d] Can not allocate memory!",
02194                  __FILE__, __LINE__);
02195       fclose (out);
02196       exit (1);
02197     }
02198   }
02199   else
02200   {
02201     char aux[]=";;;;;;;;;;;;;;";
02202 
02203     if (dstring_add (&ds, aux, strlen(aux)) == 1)
02204     {
02205       my_syslog (log_file,
02206                  "[FATAL] [%s:%d] Can not allocate memory!",
02207                  __FILE__, __LINE__);
02208       fclose (out);
02209       exit (1);
02210     }
02211   }
02212 
02213   fprintf (out, "\n\n\n");
02214 
02215   /* ------------------------------------------------------------ */
02216   /* Add options to the end of the CSV.                           */
02217   /* ------------------------------------------------------------ */
02218 
02219   sopt = dstring_get_data (&dsoptions, &size);
02220   if (sopt == NULL)
02221   {
02222      my_syslog (log_file,
02223                 "[FATAL] [%s:%d] Can not allocate memory!",
02224                 __FILE__, __LINE__);
02225                 fclose (out);
02226                 exit (1);
02227   }
02228 
02229   if (dstring_add (&ds, sopt, strlen(sopt)) == 1)
02230   {
02231     my_syslog (log_file,
02232                "[FATAL] [%s:%d] Can not allocate memory!",
02233                __FILE__, __LINE__);
02234     fclose (out);
02235     exit (1);
02236   }
02237 
02238   /* ------------------------------------------------------------ */
02239   /* Print the CSV                                                */
02240   /* ------------------------------------------------------------ */
02241 
02242   s = dstring_get_data (&ds, &size);
02243   if (s == NULL)
02244   {
02245      my_syslog (log_file,
02246                 "[FATAL] [%s:%d] Can not allocate memory!",
02247                 __FILE__, __LINE__);
02248                 fclose (out);
02249                 exit (1);
02250   }
02251 
02252   icsvfd = open (csv, O_CREAT | O_WRONLY | O_APPEND | O_LARGEFILE, S_IRWXU | S_IRWXG | S_IRWXO);
02253   if (icsvfd == -1)
02254   {
02255     my_syslog (log_file, "[WARNING] [%s:%d] Could not open file '%s' open() failed - %s",
02256                __FILE__, __LINE__,
02257                csv,
02258                strerror(errno));
02259     fclose (out);
02260     return 1;
02261   }
02262 
02263 
02264   csvfd = fdopen (icsvfd, "a");
02265   if (csvfd == NULL)
02266   {
02267     my_syslog (log_file, "[WARNING] [%s:%d] Could not fdopen file '%s' - %s",
02268                __FILE__, __LINE__,
02269                csv,
02270                strerror(errno));
02271     fclose (out);
02272     return 1;
02273   }
02274 
02275   fprintf (csvfd, "%s\n", s);
02276   fclose (csvfd);
02277 
02278   /* ------------------------------------------------------------ */
02279   /* Unlock dump file                                             */
02280   /* ------------------------------------------------------------ */
02281 
02282   if (dump_sync_fd != -1)
02283   {
02284     if (unlock_file (dump_sync_fd) == 1)
02285     {
02286       my_syslog (log_file, "[ERROR] [%s:%d] Could not unlock dump file! Continue processing ...",
02287                  __FILE__, __LINE__);
02288     }
02289   }
02290 
02291   fclose (out);
02292 
02293   /* ------------------------------------------------------------ */
02294   /* Free all allocated memory                                    */
02295   /* ------------------------------------------------------------ */
02296 
02297   dstring_free (&ds);
02298   dstring_free (&dsoptions);
02299   free (s);
02300 
02301   return 0;
02302 }
02303 
02304 /*! \brief Check the size of a packet. 
02305     \author Denis BEURIVE
02306     \param size Size of the packet.
02307     \return If the size of the packet is valid, the function returns 1. Otherwize, it returns 0.
02308  */
02309 
02310 int check_packet_size (int size)
02311 {
02312   /* ------------------------------------------------------------ */
02313   /* Minimum size is: fixed size (mandatory fields): 236 bytes    */
02314   /*                  Magic number (for options):      4 bytes    */
02315   /*                  The message ty (option 53)       3 bytes    */
02316   /*                  End padding (FF):                1 byte     */
02317   /*                                               -------------  */
02318   /*                                                 244 bytes    */
02319   /* ------------------------------------------------------------ */
02320 
02321   return (size >= 244);
02322 }
02323 
02324 /*! \brief Set the total size of a packet.
02325     \author Denis BEURIVE
02326     \param p Pointer to the packet.
02327     \param taille Total size of the packet.
02328     \warning You MUST call this function just after you receive the packet from the network
02329              (after the call to recvfrom().
02330  */
02331 
02332 void packet_set_taille (struct dhcp_packet *p, int taille) { (p->ctrl).taille = taille; }
02333 
02334 
02335 
02336 
02337 /*! \brief Return the current date as Apache's standard.
02338     \author Denis BEURIVE
02339     \return The function returns a pointer to a string of characters that contains the current date.
02340     \warning The string is returned in a statically allocated buffer, which subsequent calls will overwrite.
02341  */
02342 
02343 static char* dater()
02344 {
02345   static char  strtime[128];
02346   time_t       tt;
02347 
02348   tt = time(NULL);
02349   strftime (strtime, 128, "%Y-%m-%d %k:%M:%S", localtime(&tt));
02350 
02351   return strtime;
02352 }
02353 
02354 /*! \brief Return the IP address and the port number of a remote end point.
02355     \author Denis BEURIVE
02356     \param sender Pointer to the address of the destant end point.
02357     \param ip Pointer to a string of character used to store the IP address.
02358            This string should be, at least 16 characters long.
02359     \param port Pointer to an integer used to store the port number.
02360  */
02361 
02362 static void get_remote_address (struct sockaddr_in *sender, char *ip, int *port)
02363 {
02364    int  i;
02365    char *a;
02366 
02367    a = inet_ntoa(sender->sin_addr);
02368    for (i=0; i<15; i++) { ip[i] = *(a+i); };
02369    ip[15] = 0;
02370    *port = ntohs (sender->sin_port);
02371 }
02372 
02373 
02374 

Generated on Mon Jun 19 12:31:06 2006 for MyDhcp_V2 by doxygen1.2.15