dazuko_transport.c

Go to the documentation of this file.
00001 /* Dazuko Transport. Types shared between userspace and kernelspace.
00002    Written by Gerhard Sittig <gsittig@antivir.de>
00003 
00004    Copyright (c) 2005 H+BEDV Datentechnik GmbH
00005    All rights reserved.
00006 
00007    Redistribution and use in source and binary forms, with or without
00008    modification, are permitted provided that the following conditions
00009    are met:
00010 
00011    1. Redistributions of source code must retain the above copyright notice,
00012    this list of conditions and the following disclaimer.
00013 
00014    2. Redistributions in binary form must reproduce the above copyright notice,
00015    this list of conditions and the following disclaimer in the documentation
00016    and/or other materials provided with the distribution.
00017 
00018    3. Neither the name of Dazuko nor the names of its contributors may be used
00019    to endorse or promote products derived from this software without specific
00020    prior written permission.
00021 
00022    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00023    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00026    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00027    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00028    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00029    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00030    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00031    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032    POSSIBILITY OF SUCH DAMAGE.
00033 */
00034 
00035 /*
00036  * representation of "struct dazuko_request" in a form which is unambigious
00037  * across several platforms or between subsystems within a single platform
00038  *
00039  * high level language data types may vary in their size or internal
00040  * representation on the machine code level, high level language constructions
00041  * like a "struct" in C "suffer" from the compiler's freedom to align or
00042  * rearrange its fields
00043  *
00044  * since it is essential for Dazuko's functioning that the application and the
00045  * kernel agree in how to interpret the dazuko_request layout, we introduce an
00046  * intermediate format for passing this struct around
00047  *
00048  * this allows for 32bit applications to keep working against a 64bit kernel,
00049  * or to operate a Linux binary in a FreeBSD emulation, or to compile kernel
00050  * module and application with different options, or whatever influences the
00051  * layout of the high level language struct -- we don't mind any longer
00052  *
00053  * layout of the structure:
00054  * - no high level data type but a pure byte array
00055  * - fixed width header fields describing the sizeof an integer, a character and
00056  *   a pointer respectively, plus the stream's total length and a "used" flag
00057  * - variable width values following with the size specified before and thus known
00058  */
00059 #define LINUX
00060 
00061 #if defined __KERNEL__ || defined _KERNEL
00062   /* kernel part, every system has its own includes for NULL and int32_t :( */
00063 
00064   #if defined LINUX || defined LINUX26_SUPPORT || LINUX_VERSION_CODE
00065     #include <linux/stddef.h>
00066     #include <linux/types.h>
00067   #elif defined __FreeBSD__
00068     #include <stdio.h>
00069     #include <sys/types.h>
00070   #elif defined __sun__
00071     #include <stdio.h>
00072     #include <sys/types.h>
00073   #endif
00074   
00075 #else /* __KERNEL__ */
00076   /* user land part (regular app), not much nicer than kernel space */
00077 
00078   /* for NULL */
00079   #include <stdio.h>
00080 
00081   /* we have to get int32_t from somewhere */
00082   #include <sys/types.h>
00083   #ifndef __BIT_TYPES_DEFINED__
00084     #if defined __sun__ || defined __OpenBSD__ || defined __FreeBSD__
00085       #include <inttypes.h>
00086     #else
00087       #include <stdint.h>
00088     #endif
00089   #endif
00090 
00091 #endif /* __KERNEL__ */
00092 
00093 #include "dazuko_transport.h"
00094 
00095 /*
00096  * we need an integer to hold (store and transport) pointers; XXX what is a
00097  * reliable way to detect the width of pointers?  the warning here is to inform
00098  * us at compile time -- is there some #info directive which is not as
00099  * "serious" as a compiler warning?
00100  *
00101  * we actually could do without introducing this extra type and always use
00102  * int64_t which merely would issue a compiler warning (but would still work)
00103  * in all the cases where pointers are not of 64bit width
00104  */
00105 
00106 /* define this if you want to see the outcome of the decision */
00107 #undef WANT_INT_PTR_NOTIFICATION
00108 
00109 #if defined(_LP64) || defined(_I32LPx)
00110         #if defined WANT_INT_PTR_NOTIFICATION
00111         #warning using 64bit integer to store pointers
00112         #endif
00113         #define int_ptr_t       int64_t
00114 #else
00115         #if defined WANT_INT_PTR_NOTIFICATION
00116         #warning using 32bit integer to store pointers
00117         #endif
00118         #define int_ptr_t       int32_t
00119 #endif
00120 
00121 /* ----- base routines ----- */
00122 
00123 /* get a byte from a position within the buffer
00124  * and increment the buffer pointer */
00125 static int getbyte(unsigned char **p, int *b)
00126 {
00127         if (p == NULL)
00128                 return -1;
00129 
00130         if (*p == NULL)
00131                 return -1;
00132 
00133         if (b == NULL)
00134                 return -1;
00135 
00136         *b = **p;
00137         (*p)++;
00138 
00139         return 0;
00140 }
00141 
00142 /* get an integer from a position within the buffer with the specified width
00143  * and increment the buffer pointer */
00144 static int getinteger(unsigned char **p, int *b, int count)
00145 {
00146         int     res;
00147         int     idx;
00148 
00149         if (p == NULL)
00150                 return -1;
00151 
00152         if (*p == NULL)
00153                 return -1;
00154 
00155         if (b == NULL)
00156                 return -1;
00157 
00158         res = 0;
00159         for (idx=0 ; idx<count ; idx++)
00160         {
00161                 res <<= 8;
00162                 res += **p;
00163                 (*p)++;
00164         }
00165         *b = res;
00166 
00167         return 0;
00168 }
00169 
00170 int dazuko_reqstream_chunksize(unsigned char *ll, int *size)
00171 {
00172         /* this is a wrapper to getinteger that does NOT
00173          * increment the buffer pointer */
00174 
00175         unsigned char *p = ll;
00176 
00177         return getinteger(&p, size, 4);
00178 }
00179 
00180 /* get a pointer from a position within the buffer with the specified width
00181  * and increment the buffer pointer */
00182 static int getpointer(unsigned char **p, char **b, int count)
00183 {
00184         int_ptr_t       res;
00185         int             idx;
00186 
00187         if (p == NULL)
00188                 return -1;
00189 
00190         if (*p == NULL)
00191                 return -1;
00192 
00193         if (b == NULL)
00194                 return -1;
00195 
00196         res = 0;
00197         for (idx = 0; idx<count ; idx++)
00198         {
00199                 res <<= 8;
00200                 res += **p;
00201                 (*p)++;
00202         }
00203 
00204         *b = (void *)res;
00205 
00206         return 0;
00207 }
00208 
00209 /* put a byte to a position within the buffer
00210  * and increment the buffer pointer */
00211 static int putbyte(unsigned char **p, int b)
00212 {
00213         if (p == NULL)
00214                 return -1;
00215 
00216         if (*p == NULL)
00217                 return -1;
00218 
00219         **p = b;
00220         (*p)++;
00221 
00222         return 0;
00223 }
00224 
00225 /* put an integer to a position within the buffer with the specified width
00226  * and increment the buffer pointer */
00227 static int putinteger(unsigned char **p, int b, int count)
00228 {
00229         int     val;
00230         int     idx;
00231 
00232         if (p == NULL)
00233                 return -1;
00234 
00235         if (*p == NULL)
00236                 return -1;
00237 
00238         val = b;
00239         for (idx=1 ; idx<=count ; idx++)
00240         {
00241                 *(*p + count - idx) = (val & 0xFF);
00242                 val >>= 8;
00243         }
00244         *p += count;
00245 
00246         return 0;
00247 }
00248 
00249 /* put a pointer to a position within the buffer with the specified width
00250  * and increment the buffer pointer */
00251 static int putpointer(unsigned char **p, char *b, int count)
00252 {
00253         int_ptr_t       val;
00254         int              idx;
00255 
00256         if (p == NULL)
00257                 return -1;
00258 
00259         if (*p == NULL)
00260                 return -1;
00261 
00262         val = (int_ptr_t)b;
00263         for (idx=1 ; idx<=count ; idx++)
00264         {
00265                 *(*p + count - idx) = (val & 0xFF);
00266                 val >>= 8;
00267         }
00268         *p += count;
00269 
00270         return(0);
00271 }
00272 
00273 /* skip over data */
00274 
00275 static int skipinteger(unsigned char **p, int count)
00276 {
00277         if (p == NULL)
00278                 return -1;
00279 
00280         if (*p == NULL)
00281                 return -1;
00282 
00283         (*p) += count;
00284 
00285         return 0;
00286 }
00287 
00288 static int skippointer(unsigned char **p, int count)
00289 {
00290         if (p == NULL)
00291                 return -1;
00292 
00293         if (*p == NULL)
00294                 return -1;
00295 
00296         (*p) += count;
00297 
00298         return(0);
00299 }
00300 
00301 /* ----- public routines ----- */
00302 
00303 /* get the size of a low level byte stream representation */
00304 int dazuko_reqstream_dim_chunk0(int size_chr, int size_int, int size_ptr)
00305 {
00306         /*
00307          * a request consists of:
00308          * chunk0 length (as 4-byte integer)
00309          * used flag, sizeof char/int/void* (as single bytes)
00310          * type, in size, out size, out used (as integers)
00311          * in buff, out buff (as pointers)
00312          */
00313         return (4 + (4 * size_chr) + (4 * size_int) + (2 * size_ptr));
00314 }
00315 
00316 /*
00317  * convert a high level struct into a low level stream
00318  * (this is the app handing its variable over to the kernel)
00319  */
00320 int dazuko_reqstream_hl2ll(struct dazuko_request *req, unsigned char *ll)
00321 {
00322         unsigned char   *wrptr;
00323         int             size_chr;
00324         int             size_int;
00325         int             size_ptr;
00326         int             size_req;
00327         int             type_as_int;
00328 
00329         wrptr = ll;
00330 
00331         /* prepare to write */
00332         size_chr = sizeof(char);
00333         size_int = sizeof(int);
00334         size_ptr = sizeof(void *);
00335         size_req = dazuko_reqstream_dim_chunk0(size_chr, size_int, size_ptr);
00336 
00337         /*
00338          * we do not support multi byte characters
00339          * and we assume maximum int and ptr sizes
00340          */
00341         /*
00342          * XXX how to check these at compile time?
00343          * #if (sizeof int < 4)
00344          * etc did not work :(
00345          */
00346         if (size_chr != 1)
00347                 return -1;
00348 
00349         /* convert everything to base types */
00350         type_as_int = (req->type[0] << 8) + (req->type[1] << 0);
00351 
00352         /* stream out */
00353         if (putinteger(&wrptr, size_req, 4) != 0) return -1;
00354         if (putbyte(&wrptr, 0) != 0) return -1;
00355         if (putbyte(&wrptr, size_chr) != 0) return -1;
00356         if (putbyte(&wrptr, size_int) != 0) return -1;
00357         if (putbyte(&wrptr, size_ptr) != 0) return -1;
00358         if (putinteger(&wrptr, type_as_int, size_int) != 0) return -1;
00359         if (putinteger(&wrptr, req->buffer_size, size_int) != 0) return -1;
00360         if (putpointer(&wrptr, req->buffer, size_ptr) != 0) return -1;
00361         if (putinteger(&wrptr, req->reply_buffer_size, size_int) != 0) return -1;
00362         if (putpointer(&wrptr, req->reply_buffer, size_ptr) != 0) return -1;
00363         if (putinteger(&wrptr, req->reply_buffer_size_used, size_int) != 0) return -1;
00364 
00365         /* done */
00366         return 0;
00367 }
00368 
00369 /*
00370  * convert a low level stream into a high level struct
00371  * (this is the app reading back its variable after the kernel updated it)
00372  */
00373 int dazuko_reqstream_ll2hl(unsigned char *ll, struct dazuko_request *req, int strict)
00374 {
00375         unsigned char   *rdptr;
00376         int             size_req;
00377         int             req_used;
00378         int             size_chr;
00379         int             size_int;
00380         int             size_ptr;
00381         int             type_as_int;
00382 
00383         rdptr = (unsigned char *)ll;
00384 
00385         /* only accept streams with our own layout (length part) */
00386         if (getinteger(&rdptr, &size_req, 4) != 0) return -1;
00387         if (strict)
00388         {
00389                 if (size_req != dazuko_reqstream_dim_chunk0(sizeof(char), sizeof(int), sizeof(void *)))
00390                         return -1;
00391         }
00392 
00393         /* the kernel MUST have updated the stream, otherwise it's invalid */
00394         if (getbyte(&rdptr, &req_used) != 0) return -1;
00395         if (strict)
00396         {
00397                 if (!req_used)
00398                         return -1;
00399         }
00400 
00401         /* only accept streams with our own layout (type width part) */
00402         if (getbyte(&rdptr, &size_chr) != 0) return -1;
00403         if (getbyte(&rdptr, &size_int) != 0) return -1;
00404         if (getbyte(&rdptr, &size_ptr) != 0) return -1;
00405         if (strict)
00406         {
00407                 if ((size_chr != sizeof(char)) || (size_int != sizeof(int)) || (size_ptr != sizeof(void *)))
00408                         return -1;
00409         }
00410         if (size_req != dazuko_reqstream_dim_chunk0(size_chr, size_int, size_ptr))
00411                 return -1;
00412 
00413         /* stream in values */
00414         if (getinteger(&rdptr, &type_as_int, size_int) != 0) return -1;
00415         if (getinteger(&rdptr, &req->buffer_size, size_int) != 0) return -1;
00416         if (getpointer(&rdptr, &req->buffer, size_ptr) != 0) return -1;
00417         if (getinteger(&rdptr, &req->reply_buffer_size, size_int) != 0) return -1;
00418         if (getpointer(&rdptr, &req->reply_buffer, size_ptr) != 0) return -1;
00419         if (getinteger(&rdptr, &req->reply_buffer_size_used, size_int) != 0) return -1;
00420 
00421         /* post convert to req */
00422         req->type[0] = (type_as_int >> 8) & 0xFF;
00423         req->type[1] = (type_as_int >> 0) & 0xFF;
00424 
00425         /* done */
00426         return 0;
00427 }
00428 
00429 /*
00430  * update a low level stream with data from a high level struct
00431  * (this is the kernel passing back data to the app inside the app's variable)
00432  */
00433 int dazuko_reqstream_updll(struct dazuko_request *req, unsigned char *ll)
00434 {
00435         unsigned char   *wrptr;
00436         int             size_chr;
00437         int             size_int;
00438         int             size_ptr;
00439         int             size_req;
00440 
00441         wrptr = ll;
00442 
00443         /* fetch the complete length spec to check it later */
00444         if (getinteger(&wrptr, &size_req, 4) != 0) return -1;
00445 
00446         /* rather aux a test for minimum length */
00447         if (size_req < dazuko_reqstream_dim_chunk0(1, 4, 4))
00448                 return -1;
00449 
00450         /* set the "used" flag */
00451         /*
00452          * XXX delay this to a later point in time???  OTOH the update routine
00453          * will return an error when later steps fail and the stream will not
00454          * get passed back to the application, so this seems OK
00455          */
00456         if (putbyte(&wrptr, 1) != 0) return -1;
00457 
00458         /* fetch the data width fields to check them */
00459         if (getbyte(&wrptr, &size_chr) != 0) return -1;
00460         if (getbyte(&wrptr, &size_int) != 0) return -1;
00461         if (getbyte(&wrptr, &size_ptr) != 0) return -1;
00462         if (size_chr != 1)
00463                 return -1;
00464         if (size_req != dazuko_reqstream_dim_chunk0(size_chr, size_int, size_ptr))
00465                 return -1;
00466 
00467         /* skip over the fields not of interest, only write back the
00468          * "reply_buffer_size_used" component */
00469         if (skipinteger(&wrptr, size_int) != 0) return -1;
00470         if (skipinteger(&wrptr, size_int) != 0) return -1;
00471         if (skippointer(&wrptr, size_ptr) != 0) return -1;
00472         if (skipinteger(&wrptr, size_int) != 0) return -1;
00473         if (skippointer(&wrptr, size_ptr) != 0) return -1;
00474         if (putinteger(&wrptr, req->reply_buffer_size_used, size_int) != 0) return -1;
00475 
00476         /* done */
00477         return 0;
00478 }
00479 

Generated on Sun May 21 14:30:50 2006 for RSBAC by  doxygen 1.4.2